Computer Security Course. Dawn Computer Security Course. Dawn Song Song Vulnerability Analysis (IV): Program Verifjcation Slide credit: Vijay Dawn Song D’Silva
Program Verifjcation Dawn Song
Program Verifjcation • How to prove a program free of bufger overfmows? – Precondition – Postcondition – Loop invariants Dawn Song
Precondition • Precondition for f() is an assertion (a logical proposition) that must hold Precondition: at input to f() φ(x) – If any precondition is not met, f(x) f(x) f() may not behave correctly Postcondition: – Callee may freely assume ψ obligation has been met • The concept similarly holds for any statement or block of statements Dawn Song
φ(x Precondition Example ) f( f( ψ x) x) 1:int parse(FILE *fp) { • Precondition: 2: char cmd[256], *url, buf[5]; 3: fread(cmd, 1, 256, fp); – fp points to a valid 4: int i, header_ok = 0; 5: if (cmd[0] == ‘G’) location in memory 6: if (cmd[1] == ‘E’) 7: if (cmd[2] == ‘T’) – fp points to a fjle 8: if (cmd[3] == ‘ ’) 9: header_ok = 1; 10: if (!header_ok) return -1; – the fjle that fp points to 11: url = cmd + 4; 12: i=0; contains at least 4 13: while (i<5 && url[i]!=‘\0’ && url[i]! =‘\n’) { characters 14: buf[i] = tolower(url[i]); 15: i++; – … 16: } 17: buf[i] = ‘\0’; 18: printf(“Location is %s\n”, buf); 19: return 0; } Dawn Song
Postcondition • Postcondition for f() Precondition: – An assertion that holds when φ(x) f() returns f(x) f(x) – f() has obligation of ensuring Postcondition: condition is true when it ψ returns – Caller may assume postcondition has been established by f() Dawn Song
φ(x Postcondition Example ) f( f( ψ x) x) 1:int parse(FILE *fp) { 2: char cmd[256], *url, buf[5]; 3: fread(cmd, 1, 256, fp); • Postcondition: 4: int i, header_ok = 0; 5: if (cmd[0] == ‘G’) – buf contains no uppercase 6: if (cmd[1] == ‘E’) 7: if (cmd[2] == ‘T’) letters 8: if (cmd[3] == ‘ ’) – (return 0) ⇒(cmd[0..3] == 9: header_ok = 1; 10: if (!header_ok) return -1; “GET “) 11: url = cmd + 4; 12: i=0; 13: while (i<5 && url[i]!=‘\0’ && url[i]! =‘n’) { 14: buf[i] = tolower(url[i]); 15: i++; 16: } 17: buf[i] = ‘\0’; 18: printf(“Location is %s\n”, buf); 18: return 0; } Dawn Song
Proving Precondition ⇒ Postcondition • Given preconditions and postconditions Precondition: φ(x) – Specifying what obligations caller has and what caller is entitled to rely upon f(x) f(x) ⇒ Postcondition: • Verify: No matter how function is ψ called, – if precondition is met at function ’ s entrance, – then postcondition is guaranteed to hold upon function ’ s return Dawn Song
Proving Precondition ⇒ Postcondition φ(x ⇒ ) f( f( ψ x) x) • Basic idea: – Write down a precondition and postcondition for every line of code – Use logical reasoning • Requirement: – Each statement ’ s postcondition must match (imply) precondition of any following statement – At every point between two statements, write down invariant that must be true at that point • Invariant is postcondition for preceding statement, and precondition for next one Dawn Song
We’ll take our example, fjx the bug, and show that we can φ(x successfully prove that the bug no longer exists. ) f( f( ψ x) x) 1:int parse(FILE *fp) { i = 0; i = 0; 2: char cmd[256], *url, buf[5]; 3: fread(cmd, 1, 256, fp); 4: int i, header_ok = 0; 5: if (cmd[0] == ‘G’) 6: if (cmd[1] == ‘E’) is(i<5 && url[i]!=‘\0’ && url[i]! is(i<5 && url[i]!=‘\0’ && url[i]! 7: if (cmd[2] == ‘T’) =‘\n’)? T =‘\n’)? T 8: if (cmd[3] == ‘ ’) F F 9: header_ok = 1; 10: if (!header_ok) return -1; i++; i++; 11: url = cmd + 4; 12: i=0; 13: while (i<5 && url[i]!=‘\0’ && url[i]!=‘n’) { assert(i>=0 && i<5); assert(i>=0 && i<5); 14: buf[i] = tolower(url[i]); T F T F 15: i++; 16: } 17: assert(i>=0 && i <5); CRASH! buf[i] = CRASH! buf[i] = 18: buf[i] = ‘\0’; ‘\0’; 19: printf(“Location is %s\n”, buf); ‘\0’; 20: return 0; } Dawn Song
We’ll take our example, fjx the bug, and show that we can φ(x successfully prove that the bug no longer exists. ) f( f( ψ x) x) 1:int parse(FILE *fp) { 1:int parse(FILE *fp) { i = 0; i = 0; i = 0; i = 0; 2: char cmd[256], *url, buf[5]; 2: char cmd[256], *url, buf[5]; 3: fread(cmd, 1, 256, fp); 3: fread(cmd, 1, 256, fp); 4: int i, header_ok = 0; 4: int i, header_ok = 0; 5: if (cmd[0] == ‘G’) 5: if (cmd[0] == ‘G’) 6: if (cmd[1] == ‘E’) 6: if (cmd[1] == ‘E’) is(i<5 && url[i]!=‘\0’ && url[i]! is(i<4 && url[i]!=‘\0’ && url[i]! is(i<5 && url[i]!=‘\0’ && url[i]! is(i<4 && url[i]!=‘\0’ && url[i]! 7: if (cmd[2] == ‘T’) 7: if (cmd[2] == ‘T’) =‘\n’)? =‘\n’)? T T =‘\n’)? =‘\n’)? T T 8: if (cmd[3] == ‘ ’) 8: if (cmd[3] == ‘ ’) F F F F 9: header_ok = 1; 9: header_ok = 1; 10: if (!header_ok) return -1; 10: if (!header_ok) return -1; i++; i++; i++; i++; 11: url = cmd + 4; 11: url = cmd + 4; 12: i=0; 12: i=0; 13: while (i<4 && url[i]!=‘\0’ && url[i]!=‘n’) 13: while (i<5 && url[i]!=‘\0’ && url[i]!=‘n’) { { assert(i>=0 && i<5); assert(i>=0 && i<5); assert(i>=0 && i<5); assert(i>=0 && i<5); 14: buf[i] = tolower(url[i]); 14: buf[i] = tolower(url[i]); T T F F T T F F 15: i++; 15: i++; 16: } 16: } 17: assert(i>=0 && i <5); 17: assert(i>=0 && i <5); CRASH! CRASH! buf[i] = buf[i] = CRASH! CRASH! buf[i] = buf[i] = 18: buf[i] = ‘\0’; 18: buf[i] = ‘\0’; ‘\0’; ‘\0’; 19: printf(“Location is %s\n”, buf); 19: printf(“Location is %s\n”, buf); ‘\0’; ‘\0’; 20: return 0; } 20: return 0; } Bug Fixed! Dawn Song
We’ll take our example, fjx the bug, and show that we can φ(x successfully prove that the bug no longer exists… ) f( f( ψ x) x) …So assuming fp points to a fjle that 1:int parse(FILE *fp) { begins with “GET “, we want to show 2: char cmd[256], *url, buf[5]; 3: fread(cmd, 1, 256, fp); that parse never goes down the false 4: int i, header_ok = 0; assertion path. 5: if (cmd[0] == ‘G’) i = 0; i = 0; 6: if (cmd[1] == ‘E’) 7: if (cmd[2] == ‘T’) 8: if (cmd[3] == ‘ ’) is(i<4 && url[i]!=‘\0’ && url[i]! is(i<4 && url[i]!=‘\0’ && url[i]! 9: header_ok = 1; =‘\n’)? T =‘\n’)? 10: if (!header_ok) return -1; T 11: url = cmd + 4; F F 12: i=0; i++; i++; 13: while (i<4 && url[i]!=‘\0’ && url[i]!=‘n’) { 14: buf[i] = tolower(url[i]); 15: i++; assert(i>=0 && i<5); assert(i>=0 && i<5); 16: } T F T F 17: buf[i] = ‘\0’; 18: printf(“Location is %s\n”, buf); 18: return 0; } CRASH! buf[i] = CRASH! buf[i] = ‘\0’; ‘\0’; ut fjrst, we will need the concept of loop invariant. Dawn Song
Loop Invariant and Induction φ(i+1 φ(i) ) • An assertion that is true at entrance to the loop, on any path through the code – Must be true before every loop iteration • Both a pre- and post-condition for the loop body i = 0; A i = 0; A φ(i+1 is(i<5 && url[i]!=‘\0’ && url[i]! B is(i<5 && url[i]!=‘\0’ && url[i]! B φ(i =‘\n’)? T =‘\n’)? T ) ) buf[i] = C C buf[i] = F F tolower(url[i]); tolower(url[i]); i++; i++; Dawn Song
Loop Invariant and Induction φ(i+1 φ(i) ) o verify : • T – Base Case: Prove true for fjrst iteration: φ(0) – Inductive step: Assume φ(i) at the beginning of the loop. Prove φ(i+1) at the start of the next iteration. Dawn Song
Try with our familiar example, proving that (0≤i<5) after the loop φ(i+1 terminates: φ(i) ) LOOP INVARIANT: LOOP INVARIANT: /* φ( i ) = (0 ≤ i < 5) */ i = 0; i = 0; Base Case: /* φ( 0 ) = (0 ≤ 0 < 5) */ is(i<4 && url[i]!=‘\0’ && url[i]! is(i<4 && url[i]!=‘\0’ && url[i]! Inductive Step: =‘\n’)? T =‘\n’)? T F F /* assume (0 ≤ i < 5)at the beginning of the loop */ i++; i++; /* for (0 ≤ i < 4), clearly (0 ≤ i+1 < 5) */ /* (i=5) is not a possible case since assert(i>=0 && i<5); assert(i>=0 && i<5); T F that would fail the looping predicate */ T F /* ⇒ (0 ≤ i+1 < 5) at the end of the loop */ CRASH! buf[i] = CRASH! buf[i] = /* ⇒ parse never fails the assertion */ ‘\0’; ‘\0’; Dawn Song
Recommend
More recommend