Presentation is loading. Please wait.

Presentation is loading. Please wait.

Specifying and Verifying Device Drivers Wes Weimer George Necula Gregoire Sutre.

Similar presentations


Presentation on theme: "Specifying and Verifying Device Drivers Wes Weimer George Necula Gregoire Sutre."— Presentation transcript:

1 Specifying and Verifying Device Drivers Wes Weimer George Necula Gregoire Sutre

2 Overview Background and Motivation Safety Properties Events and History Registers Driver States Specifications Verification Implementation

3 Background and Motivation Why bother? PCC-style background –Want a sound analysis Decided on an all-paths analysis –Similar to PREfix, ESC, Slam, Magick –Check pre- and post-conditions, kernel API –But also specify resource management, etc. Greg will recast as model checking later

4 Safety Properties We aim to verify that … –Allocated resources are freed Over the lifetime of the driver Enforce acquire order: no deadlocks –Kernel functions are called correctly Also includes ordering requirements and obligations, like schedule() and signal_pending(). –Certain minimum actions are performed

5 Events Three broad types: + allocation, - deallocation, ! event Applied to uninterpreted constructors: irq, dma, memory, schedule And given program values as arguments: +irq(5), -dma(3), !schedule Function call and return may be treated as events

6 History Register Abstract register used to verify programs –Like the “memory register” in PCC/VCGen –Never appears in user-written code Keeps an ever-increasing list of events –E.g., [ +irq(7) ; !schedule ; +misc(&qpmouse) ] May refer to it in conditions –E.g., PRE(!historyContains(+irq(i)))

7 Driver States S0: Uninitialized S1: Initialized S2: Opened init_module=0cleanup_module=0 misc_open=0 misc_release=0 misc_read=* misc_write=* Inv(S0) = true Inv(S1) = historyContains(+misc(any))

8 Driver States (cont’d) Kernel API guarantees a certain state-like behavior for device drivers –E.g., misc_open will only be called if the driver is in S1 We associate an invariant with each state –Captures history register values –And global variables in the driver Must check all paths from S0 to S0. –For resource leaks, etc. –Similar to data-flow analysis

9 Specifications Write spec in C, just like driver –May use data and control non-determinism –May use pre-conditions: like assert(), but will not fail Spec is minimal –List only things that must be done –Looks like a “template” device driver –Normal device drivers often written by copying others Side-conditions govern optional behavior –Like matching alloc/free –Or checking signals after sleeping

10 Specification Example int init_module() { /* user code must look like this */ PRE(!historyContains(+misc(any))); switch (__rand_int_range(0,3)) { case 0: misc_register(any); /* use kernel API */ return 0; case 1: return –5; /* EIO */ case 2: return –6; /* ENXIO */ case 3: return –19; /* ENODEV */ }}

11 Specification Example (2) int misc_fasync(void *fd, void *filp, int on) { PRE(fd != 0 && filp && (on == 1 || on == 0) && current->state == TASK_RUNNING && historyCount(!misc_open) > historyCount(!misc_release)); int retval = fasync_helper(fd, filp, on, any); if (retval < 0) return retval; else return 0; }

12 Kernel API Spec Model behavior of kernel functions –Like kmalloc(), schedule(), kfree() –May modify history register Example: int request_irq(int i, void *f, …) { PRE(historyCount(+irq(i)) == historyCount(-irq(i)) && implements(f, irq_handler) && …); if (__rand_int_range(0,1)) { return –5; } else { historyAdd(+irq(i)); return 0; } }

13 Kernel API Spec (2) int kmalloc(int size, int prio) { PRE(size > 0 && size < (128*1024) && (prio & GFP_KERNEL || prio & GFP_ATOMIC) && !(prio & GFP_KERNEL && prio & GFP_ATOMIC)); if (prio & GFP_KERNEL) { int old_state = current->state; current->state = TASK_INTERRUPTIBLE; schedule(); current->state = old_state; historyAdd(!signal_pending); } if (__rand_int_range(0,1) { void *retval = __rand_int_range(1, MAX_INT/4)*4; historyAdd(+memory(retval)); return retval; } else return NULL; }

14 Side Conditions Used to verify optional behavior –Like resource allocation, scheduling –Conditions on the history register Examples: –Every !schedule must match a !signal_pending –After !must_return(-512), must return –512 –All +irq(…) before any +dma(…) –All +irq(…) occur after !misc_open

15 Story so far … We have the user source code We have the history register abstraction –Keep track of the past, etc. We have a spec for the user code –Minimal, lists things that must be done We have a spec for the kernel API We have side conditions

16 Verification When does the user code meet the spec? –Each user function F “matches up” (defined next) with our spec for function F –If the user calls a kernel function with a pre- condition, the condition will always be satisfied –All of the side conditions hold over the life of the device driver

17 “Matching Up” Can be phrased as a trace inclusion problem –More on that with the next speaker We’ll do it as an all-paths analysis Symbolically execute all paths in user code Keep track of history register Remove +resource(X) and –resource(X) Make sure other important events match

18 How to Verify Symbolically execute all paths in user code –End up with a set of final states U –Verify pre-conditions, use theorem prover Symbolically execute all paths in spec –End up with a set of final states S For every u  U, find an s  S such that –They have the same return value –Their history registers match up –If s proves T then u proves T (for a few global T’s)

19 How to Verify: States Start in S0, then check init_module() –Match each final state against the spec –Check all side-conditions in each final state Gather all states R with return value 0 –Their LUB becomes the invariant for S1 –Analyze all paths out of S1 (= symbolically execute those functions with that invariant) Repeat until this terminates.

20 What can go wrong? User code can call a kernel function and fail to meet the pre-condition User code can fail to meet a side condition User code can fail to match up to the spec If so, report an error! And hope that it’s not a false positive.

21 Loop Invariants Used in symbolic execution to model loops Currently, we guess “true” –or use any other heuristic (e.g., on “for” loops) Except for the history register Gather all history changes in the loop body Add a special history element: X_copies_of(history_element_list)

22 Does it work? Sample implementation Tested on init_module() in 46 misc device drivers (about 300k post-processed each) 30 successful terminations (25 meet spec) –Others look fine, spec needs to be refined 16 “no answer after 45 seconds” –All-paths analysis is expensive: O(2 n )

23 Conclusions and Future Work Method for specifying and verifying –Spec looks like original code –Sound, incomplete, expensive –Uses abstract events Captures allocation, function ordering, other API and behavioral restrictions Next steps: –folding similar paths –handling concurrency (e.g., irq handlers)


Download ppt "Specifying and Verifying Device Drivers Wes Weimer George Necula Gregoire Sutre."

Similar presentations


Ads by Google