Slide 1

Slide 1 text

Institute for System Programming of the Russian Academy of Sciences Predicate Abstraction Based Configurable Method for Data Race Detection in Linux Kernel Pavel Andrianov, Vadim Mutilin, Alexey Khoroshilov

Slide 2

Slide 2 text

2 int global; Race Condition Thread 1 { ... global = 1; ... } Thread 2 { ... global = 2; ... } A situation, in which simultaneous accesses to the same memory location take place from several threads, one of the accesses is write

Slide 3

Slide 3 text

3 Real Data Race drivers/net/wireless/marvell/libertas/libertas.ko disconnect: … kfree_skb(priv->currenttxskb); priv->currenttxskb = NULL; priv->tx_pending_len = 0; ... transmit: spin_lock(&priv->driver_lock, flags) if (priv->currenttxskb == NULL) return; … priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, priv->dev); netif_rx(priv->currenttxskb); … spin_unlock(&priv->driver_lock, flags)

Slide 4

Slide 4 text

4 Commit

Slide 5

Slide 5 text

5 Motivation ● Concurrency bugs make up 20% of all across the file systems (A Study of Linux File System Evolution, FAST'13) ● Data race conditions make up 17% of all errors in the Linux kernel (Analysis of typical faults in Linux operating system drivers, Proceedings ISP RAN)

Slide 6

Slide 6 text

6 Other Tools Fast and imprecise Precise, but slow Example: RELAY Example: Threader Difficult to adjust a tool to a particular task Adjustable analysis?

Slide 7

Slide 7 text

7 Lockset Algorithm Potential data race is a situation, when accesses to the same shared data occur with disjoint sets of locks from two parallel threads, one access is write.

Slide 8

Slide 8 text

8 Potential Race Condition … *a = 1; ... … mutex_lock(); *a = 1; mutex_unlock(); ... ● A disjoint set of synchronization primitives ● The same shared data ● Accesses from different threads, which can be executed simultaneously ● Real (reachable) paths

Slide 9

Slide 9 text

9 Lightweight core algorithm Method overview A set of warnings Lockset algorithm Shared analysis Heavyweight extensions CEGAR Thread analysis Precise warnings Imprecise warnings

Slide 10

Slide 10 text

10 Counter Example Guided Abstraction Refinement Error? Safe Counterexample Feasible? Abstraction Refinement Unsafe No Yes Yes No Solver Analysis Interpolation

Slide 11

Slide 11 text

11 Reachability analysis based on predicate abstraction {},[] {},[] {lock}, [] {}, [] {lock},[] {}, [] {}, [] {}, [] {lock}, [] {lock}, [] {lock}, [] {}, [] {}, [] {}, [] int global; int func(int var) { if (var) { lock(); } global++; if (var) { unlock(); } } {}, []

Slide 12

Slide 12 text

12 Reachability analysis based on predicate abstraction {} {} {lock}, [var != 0] {}, [var == 0] {lock} {}, [var != 0] {}, [var == 0] {} {lock}, [var != 0] {lock}, [var != 0] {lock}, [var != 0] {}, [var == 0] {}, [var == 0] {}, [var != 0] int global; int func(int var) { if (var) { lock(); } global++; if (var) { unlock(); } }

Slide 13

Slide 13 text

13 Two Ways of Refinement Analysis Refinement Analysis Refinement

Slide 14

Slide 14 text

14 Example of False Alarm adm8211_start(dev) adm8211_init_rings(dev) request_irq(adm8211_interrupt) dev->priv->tx_buffers[entry]->skb adm8211_interrupt(dev) dev->priv->tx_buffers[entry]->skb

Slide 15

Slide 15 text

15 Example of False Alarm adm8211_start(dev) adm8211_interrupt(dev) request_irq(adm8211_interrupt) dev->priv->tx_buffers[entry]->skb dev->priv->tx_buffers[entry]->skb

Slide 16

Slide 16 text

16 Example of Linux Driver module_init() catc_probe() catc_open() module_exit() usb_register_driver() register_netdev() catc_close() catc_disconnect() unregister_netdev() usb_deregister() usb_driver net_device

Slide 17

Slide 17 text

17 Example of Model entry_point usb_driver handlers usb_register_driver usb_deregister() net_device handlers register_netdev() unregister_netdev()

Slide 18

Slide 18 text

18 Анализ разделяемых данных struct my_struct { int *b; } *А; int func() { int *a; a = malloc(); If (undef_value) { A->b = a; } *a = 1; } Доступ к разделяемым данным – потенциальная гонка {} {a → local} {a → local} {a → shared} {a → shared} [undef_value ! = 0] [undef_value == 0]

Slide 19

Slide 19 text

19 Анализ примитивов синхронизации int global; int func(int var) { if (var) { lock(); } global++; if (var) { unlock(); } } {} {} {lock} {} {lock} {} {lock} {} {lock} {lock} {} {} {} {}

Slide 20

Slide 20 text

20 Thread Analysis int global; Int start() { global = 0; pthread_create(&thread, .., worker, ..); pthread_join(&thread); result = global; } {1.1} {1.1} {1.1, 2.1} {1.1} {1.1, 2.1} {1.1, 2.0} {1.1, 2.1} {1.1} {1.1} int worker() { global++; }

Slide 21

Slide 21 text

21 Method Overview

Slide 22

Slide 22 text

22 Results Unsafes Unknowns Safes Time, h Memory, Gb + Threads, + Refinement 5 61 51 3.2 8.1 - Threads, + Refinement 6 67 44 4.1 4.0 + Threads, - Refinement 27 57 49 2.3 8.2 - Threads, - Refinement 186 54 43 2.1 3.5 113 modules of OS Linux 4.5-rc1 subsystem drivers/net/wireless/

Slide 23

Slide 23 text

23 2219 warnings at drivers/ ● 2219 warnings = 270 unsafe drivers ● 55% - imprecision of environment model ● 10% - simple memory model ● 10% - operations with lists ● 10% - other inaccuracies in our analysis ● 15% - true races ● 290 true warnings = 32 bugs

Slide 24

Slide 24 text

24 Conclusion ● Flexible adjustment of the balance between resources and accuracy ● Applicable to industry projects ● Real race conditions are found

Slide 25

Slide 25 text

25 Thank you! Questions?