510 likes | 733 Views
Software Model Checking. Lecture 17 CS 6340 ( a dapted from a talk by Ranjit Jhala ). Property 1: Double Locking. lock. unlock. unlock. lock. “An attempt to re-acquire an acquired lock or release a released lock will cause a deadlock .” Calls to lock and unlock must alternate .
E N D
Software Model Checking Lecture 17CS 6340 (adapted from a talk by RanjitJhala)
Property 1: Double Locking lock unlock unlock lock “An attempt to re-acquire an acquired lock or release a released lock will cause a deadlock.” Calls to lock and unlockmust alternate.
Property 2: Drop Root Privilege [Chen-Dean-Wagner ’02] “User applications must not run with root privilege” When execv is called, must have suid 0
Property 3: IRP Handler start NP CallDriver SKIP1 SKIP2 return child status Skip CallDriver IPC synch MPR3 NP CallDriver prop completion PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC return not Pend no prop completion synch CallDriver N/A N/A IRP accessible CallDriver start P SKIP2 Mark Pending SKIP1 Skip CallDriver IPC synch MPR3 NP CallDriver prop completion return Pending PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC no prop completion CallDriver N/A [Fahndrich]
This Lecture • Model Checking • Path sensitive program analysis • Lazy abstraction • Compute abstraction on demand • Counterexample refinement • Use false positives to refine abstraction
Example lock unlock unlock lock Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); return; }
What a program really is… pc lock old new q • 3 • 5 • 5 • 0x133a pc lock old new q 4 ` 5 6 0x133a State Transition 3: unlock(); new++; 4:} … Example ( ) { 1: do { lock(); old = new; q= q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new ++; } 4: } while (new != old); 5: unlock(); return;}
The Safety Verification Problem Error Safe Initial Is there a path from an initial to an errorstate? Problem:Infinitestate graph Solution : Set of states ≈ logical formula
Representing States asFormulas • [F] • states satisfyingF { s|s|=F } • F • FO formula over prog. vars • [F1] intersect[F2] • F1∨F2 • [F1] union[F2] • F1∧ F2 • complement [F] • !F • [F1] subseteq[F2] • F1 =>F2
Idea 1: Predicate Abstraction • Predicates on program state: • lock • old = new • States satisfying samepredicates are equivalent • Merged into one abstract state • #abstract states is finite
Abstract States and Transitions pc lock old new q 3 5 5 0x133a pc lock old new q 4 5 6 0x133a State 3: unlock(); new++; 4:} … Theorem Prover lock old=new ! lock !old=new
Abstraction pc lock old new q 4 5 6 0x133a State 3: unlock(); new++; 4:} … pc lock old new q 3 5 5 0x133a Theorem Prover lock old=new ! lock !old=new Existential Lifting
Abstraction pc lock old new q 4 5 6 0x133a State 3: unlock(); new++; 4:} … pc lock old new q 3 5 5 0x133a lock old=new ! lock !old=new
Analyze Abstraction Analyze finite graph Over Approximate: Safe =>System Safe No false negatives Problem Spurious counterexamples
Idea 2: Counterexample-Guided Refinement Solution Use spurious counterexamples to refine abstraction!
Idea 2: Counterexample-Guided Refinement Solution Use spurious counterexamples to refine abstraction 1. Add predicates to distinguish states across cut 2. Build refined abstraction Imprecision due to merge
Iterative Abstraction-Refinement Solution Use spurious counterexamples to refine abstraction 1. Add predicates to distinguish states across cut 2. Build refined abstraction -eliminates counterexample 3. Repeat search Till real counterexample or system proved safe [Kurshan et al 93] [Clarke et al 00] [Ball-Rajamani 01]
The Big Picture boolean program symbolic reachability Program predicate abstraction error path refinement predicates path feasibility & predicate discovery + Property [Kurshan et al. ’93] [Clarke et al. ’00] [Ball, Rajamani ’00]
Problem: Abstraction is Expensive Reachable Problem #abstract states = 2#predicates Exponential Thm. Prover queries • Observe • Fraction of state space reachable • #Preds ~ 100’s, #States ~ 2100, • #Reach ~ 1000’s
Solution 1: Only Abstract Reachable States Safe Solution Build abstraction during search Problem #abstract states = 2#predicates Exponential Thm. Prover queries
Solution 2: Don’t Refine Error-Free Regions Error Free Solution Don’t refine error-free regions Problem #abstract states = 2#predicates Exponential Thm. Prover queries
Key Idea:Reachability Tree Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off Initial 1 2 3 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 5 4 3
Key Idea:Reachability Tree Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off Initial 1 2 3 6 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 4 7 5 3 3 Error Free
Key Idea:Reachability Tree Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off Initial 1 2 3 6 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 4 7 8 5 8 3 1 1 3 Error Free S1: Only abstract reachable states S2: Don’t refine error-free regions SAFE
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 1 Reachability Tree Predicates:LOCK
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK lock() old = new q=q->next 2 LOCK 1 2 Reachability Tree Predicates:LOCK
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK [q!=NULL] 3 LOCK 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK 3 LOCK q->data = new unlock() new++ 4 !LOCK 4 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK 3 LOCK 4 !LOCK [new==old] 5 !LOCK 5 4 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK 3 LOCK 4 !LOCK 5 !LOCK 5 unlock() 4 !LOCK 1 2 3 Reachability Tree Predicates:LOCK
Analyze Counterexample Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK lock() old = new q=q->next 2 LOCK [q!=NULL] 3 LOCK q->data = new unlock() new++ 4 !LOCK [new==old] 5 !LOCK 5 unlock() 4 !LOCK 1 2 3 Reachability Tree Predicates:LOCK
Analyze Counterexample Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK old = new 2 LOCK 3 LOCK new++ 4 !LOCK [new==old] 5 !LOCK 5 Inconsistent 4 !LOCK new == old 1 2 3 Reachability Tree Predicates:LOCK
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 1 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK lock() old = new q=q->next 2 LOCK, new==old 1 2 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK, new==old 3 LOCK, new==old q->data = new unlock() new++ 4 ! LOCK, !new==old 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK, new==old 3 LOCK, new==old 4 ! LOCK, ! new==old [new==old] 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK, new==old 3 LOCK, new==old 4 ! LOCK, !new==old [new!=old] 1 !LOCK, ! new==old 4 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK, new==old SAFE 3 LOCK, new==old 4 4 LOCK, new==old ! LOCK, ! new==old 1 5 5 !LOCK, ! new==old 4 4 4 1 ! LOCK, new==old 2 3 Reachability Tree Predicates:LOCK, new==old
Key Idea:Reachability Tree Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off Initial 1 2 3 6 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 4 7 8 5 8 3 1 1 3 Error Free S1: Only Abstract Reachable States S2: Don’t refine error-free regions SAFE
Two handwaves Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4:} while (new != old); 5: unlock(); } 1 !LOCK 2 LOCK, new==old SAFE 3 LOCK, new==old 4 4 LOCK, new==old ! LOCK, ! new==old 1 5 5 !LOCK, ! new==old 4 4 4 1 ! LOCK, new==old 2 3 Reachability Tree Predicates:LOCK, new==old
Two handwaves Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4:} while (new != old); 5: unlock(); } 1 !LOCK Q. How to compute “successors” ? 2 LOCK, new==old SAFE 3 3 LOCK, new==old LOCK, new==old q->data = new unlock() new++ 4 4 4 LOCK, new==old ! LOCK, ! new==old ! LOCK, !new==old 1 5 5 !LOCK, ! new==old 4 4 4 1 ! LOCK, new==old 2 3 Reachability Tree Predicates:LOCK, new==old
Two handwaves Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4:} while (new != old); 5: unlock(); } 1 : LOCK Q. How to compute “successors” ? 2 LOCK , new==old SAFE 3 LOCK, new==old 4 4 LOCK , new=old ! LOCK, !new = old Q. How to find predicates ? 1 5 5 Refinement : LOCK, : new == old 4 4 4 1 : LOCK , new==old 2 3 Predicates:LOCK, new==old
Two handwaves Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4:} while (new != old); 5: unlock(); } 1 : LOCK Q. How to compute “successors” ? 2 LOCK , new==old SAFE 3 LOCK, new==old 4 4 LOCK , new=old ! LOCK, !new = old Q. How to find predicates ? 1 5 5 Refinement : LOCK, : new == old 4 4 4 1 : LOCK , new==old 2 3 Predicates:LOCK, new==old
Weakest Preconditions WP(P,OP) Weakest formula P’s.t. if P’ is true beforeOP then P is true afterOP [WP(P, OP)] OP [P]
Weakest Preconditions WP(P,OP) Weakest formula P’ s.t. if P’ is true beforeOP then P is true afterOP [WP(P, OP)] OP [P] P[e/x] new+1 = old Assign new=new+1 x=e P new = old
How to Compute Successor ? Example() { 1: do { lock(); old = new; q = q->next; 2: if (q != NULL) { 3: q->data = new; unlock(); new++; } 4: } while (new != old); 5: unlock(); } 3 F LOCK, new==old OP ? 4 !LOCK, !new==old • For each p • Check if p is true (or false) after OP • Q:When is p true afterOP? • - If WP(p, OP) is true beforeOP! • - We know F is true before OP • - Thm. Prover Query: F=> WP(p, OP) Predicates:LOCK, new==old
Lazy Abstraction Yes Proof Program Abstract Refine No Counterexample Property Problem:Abstraction is Expensive Solution:1.Only abstract reachable states, 2. Don’t refine error-free regions Key Idea: Reachability Tree
Property: IRP Handler start NP CallDriver SKIP1 SKIP2 return child status Skip CallDriver IPC synch MPR3 NP CallDriver prop completion PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC return not Pend no prop completion synch CallDriver N/A N/A IRP accessible CallDriver start P SKIP2 Mark Pending SKIP1 Skip CallDriver IPC synch MPR3 NP CallDriver prop completion return Pending PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC no prop completion CallDriver N/A [Fahndrich]
Results Property: IRP Handler Win NT DDK * Pre-processed
Lazy Abstraction: Main Ideas • Predicates: • Abstract infinite program states • Counterexample-guided Refinement: • Find predicates tailored to program, property • Abstraction: Expensive • Reachability Tree • Refinement: Find new predicates