verifying the safety of user pointer dereferences suhabe bugrara [email protected] stanford...

77
Verifying the Safety of User Pointer Dereferences Suhabe Bugrara [email protected] Stanford University Joint work with Alex Aiken

Post on 21-Dec-2015

212 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Verifying the Safety of User Pointer Dereferences

Suhabe [email protected]

Stanford University

Joint work with Alex Aiken

Page 2: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Unchecked User Pointer Dereferences

• Security property of operating systems• Two types of pointers in operating systems

– kernel pointer: pointer created by the operating system– user pointer: pointer created by a user application and passed to the

operating system via an entry point such as a system call

• Must check that a user pointer points into userspace before dereferencing it

Page 3: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Unchecked User PointerDereferences

1: static ssize_t read_port(…, char * __user buf, …) { 2: unsigned long i = *ppos; 3: char * __user tmp = buf; 4:

Page 4: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Unchecked User PointerDereferences

1: static ssize_t read_port(…, char * __user buf, …) { 2: unsigned long i = *ppos; 3: char * __user tmp = buf; 4:

7: 8: while (count-- > 0 && i < 65536) { 9: if (__put_user(inb(i),tmp) < 0)

//deref10: return -EFAULT; 11: i++; 12: tmp++; 13: }14:15: *ppos = i; 16: return tmp-buf; 17: }

Page 5: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Unchecked User PointerDereferences

1: static ssize_t read_port(…, char * __user buf, …) { 2: unsigned long i = *ppos; 3: char * __user tmp = buf; 4: 5: if (!access_ok(..,buf,...)) //check 6: return -EFAULT; 7: 8: while (count-- > 0 && i < 65536) { 9: if (__put_user(inb(i),tmp) < 0) //deref10: return -EFAULT; 11: i++; 12: tmp++; 13: }14:15: *ppos = i; 16: return tmp-buf; 17: }

Page 6: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Security Vulnerability

• Malicious user could– Take control of the operating system– Overwrite kernel data structures– Read sensitive data out of kernel memory– Crash machine by corrupting data

Page 7: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Goal

• Design a program analysis to prove statically that no unchecked user pointer dereferences exist in the entire operating system

Page 8: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Challenges

• Verification – provide guarantee of correctness

• Precision– report low number of false alarms

• Scalability– analyze more than 6 MLOC

Page 9: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Verification

Page 10: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Verification

• Soundness– If the program analysis reports that no

vulnerabilities exist, then the program contains none

Page 11: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Verification

• Soundness– If the program analysis reports that no

vulnerabilities exist, then the program contains none

• Completeness– If the program analysis reports that a

vulnerability exists, then program contains one

Page 12: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Verification

• Soundness– If the program analysis reports that no

vulnerabilities exist, then the program contains none

• Completeness– If the program analysis reports that a vulnerability

exists, then program contains one

• Impossible for a program analysis to be both sound and complete

Page 13: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Sound and Incomplete Verifier

1. Proves the absence of vulnerabilities

2. May report false alarms

Page 14: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Soundness Caveats

1. Unsafe memory operations

2. Concurrency

3. Inline assembly

4. Analysis fails to analyze some procedures

Page 15: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Precision

• Minimize the number of false alarms

• Reasoning more deeply about program

• Computationally expensive

• High precision inhibits scalability

Page 16: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Example1: void sys_call (int *u, const int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 17: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

Page 18: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

(*u,user)

Page 19: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

(*u,user)

(*u,user)

Page 20: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach

(*u,user)(*u,checked)

1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

(*u,user)

(*u,user)

Page 21: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach

(*u,user) lost precision!

(*u,user)(*u,checked)

1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

(*u,user)

(*u,user)

Page 22: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

One Possible Approach

…, but, procedure does not contain any vulnerabilities!

(*u,user)(*u,error) emit warning!

(*u,user) lost precision!

(*u,user)(*u,checked)

1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user)

(*u,user)

(*u,user)

Page 23: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitivity

• Ability to reason about branch correlations

• Programs use substantial amount of branch correlation in practice

• Important for reducing the number of false alarms

Page 24: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Example1: void sys_call (int *u, int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 25: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitivity

Valid Path

1: void sys_call (int *u, int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 26: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitivity

Valid Path

1: void sys_call (int *u, const int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 27: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitivity

Valid Path

1: void sys_call (int *u, const int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 28: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitivity

Invalid Path!

1: void sys_call (int *u, const int cmd) { //u is user pointer

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) { //check u

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u; //dereference u

12: }

Page 29: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

Page 30: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

Page 31: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

“guard”

Page 32: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

Page 33: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 34: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 35: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true 1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 36: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) . . .

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 37: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) cmd == 1 &&

. . .

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 38: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) cmd == 1 &&

!(cmd == 1) && . . .

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 39: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) cmd == 1 &&

!(cmd == 1) && true

. . .

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 40: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) cmd == 1 &&

!(cmd == 1) && true

false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 41: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 42: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 43: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Scalability

1. Abstraction– Throw away guards at procedure boundaries

2. Compositionality– Analyze each procedure in isolation

Page 44: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Path Sensitive Analysis

(*u,user) true(*u,checked) cmd == 1(*u,error) false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 45: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Abstraction

(*u,user) true(*u,checked) cmd == 1(*u,error) false

initial summary

Page 46: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Abstraction

(*u,user) true(*u,checked) cmd == 1(*u,error) false

α =

abstraction function

initial summary

Page 47: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Abstraction

(*u,user) true(*u,checked) cmd == 1(*u,error) false

α =(*u,user) true(*u,checked) false(*u,error) false

abstraction function

initial summary

finalsummary

Page 48: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Abstraction

(*u,user) true(*u,checked) cmd == 1(*u,error) false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 49: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Abstraction

(*u,user) true(*u,checked) false(*u,error) false

(*u,user) true(*u,checked) cmd == 1

(*u,user) true(*u,checked) cmd == 1

(*u,user) true1: void sys_call (int *u, const int cmd) {

2: int x;

3:

4: if (cmd == 1) {

5: if (!access_ok(u)) {

6: return;

7: }

8: }

9: …

10: if (cmd == 1)

11: x = *u;

12: }

(*u,user) true

(*u,user) true

Page 50: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

Page 51: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality

(*v,user) c1

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

Page 52: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality

(*v,user) c1

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

“context variable”

Page 53: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality

(*v,user) c1

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user) c1

Page 54: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality

(*v,user) c1

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user) c1

(*v,user) c1

(*v,error) c1

Page 55: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Compositionality

(*v,user) c1

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user) c1

(*v,user) c1

(*v,error) c1

Page 56: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Fixed Point Computation

• Generate summary of behavior for each procedure with respect to calling context

• Apply summary of callee at call site in caller

• Repeatedly generate and apply summaries until a fixed point is reached

Page 57: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Analysis Passes

1. Alias analysis• computes memory model for each procedure

Page 58: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Analysis Passes

1. Alias analysis• computes memory model for each procedure

2. User state propagation• propagates user states throughout OS

Page 59: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Analysis Passes

1. Alias analysis• computes memory model for each procedure

2. User state propagation• propagates user states throughout OS

3. Unchecked and safety state propagation• determines safety of each dereference site

Page 60: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Linux 2.6.17.1 built for x86

lines of code 6.2 million

procedures 91,543

global variables 40,760

composite types 14,794

initializers 35,317

loops 33,886

system call parameters 627

dereference sites 867,544

Page 61: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Experiment Setup

time bound per procedure 3 minutes

alias analysis time outs ~9 K procedures (10%)

user ptr analysis time outs 154 procedures (0.17%)

compute nodes 25

cpus per node 4

memory per node 6 GB

total run time 3.5 hours

Page 62: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Results

• Verified automatically– 616 out of 627 system call parameters (98.2 %)– 851,686 out of 852,092 dereferences (99.95%)

• Warnings– 11 warnings on system call parameters– 406 warnings on dereferences– 22 annotations required to verify

Page 63: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

1: int verify_iovec (struct msghdr *m, ..., char *address, int mode)

2: {

3: int err;

4:

5: if (m->msg_namelen) {

6: if (mode == VERIFY_READ) {

7: err = move_addr_to_kernel (m->msg_name,

8: m->msg_namelen,

9: address);

10: if (err < 0) return err;

11: }

12:

13: m->msg_name = address;

14: } else {

15: m->msg_name = NULL;

16: }

17: ...

18:}

False Alarm: Interprocedural Must-Modify

Page 64: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

1: int verify_iovec (struct msghdr *m, ..., char *address, int mode)

2: {

3: int err;

4:

5: if (m->msg_namelen) {

6: if (mode == VERIFY_READ) {

7: err = move_addr_to_kernel (m->msg_name,

8: m->msg_namelen,

9: address);

10: if (err < 0) return err;

11: }

12:

13: m->msg_name = address;

14: } else {

15: m->msg_name = NULL;

16: }

17: ...

18:}

False Alarm: Interprocedural Must-Modify

Page 65: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

1: int verify_iovec (struct msghdr *m, ..., char *address, int mode)

2: {

3: int err;

4:

5: if (m->msg_namelen) {

6: if (mode == VERIFY_READ) {

7: err = move_addr_to_kernel (m->msg_name,

8: m->msg_namelen,

9: address);

10: if (err < 0) return err;

11: }

12:

13: m->msg_name = address;

14: } else {

15: m->msg_name = NULL;

16: }

17: ...

18:}

False Alarm: Interprocedural Must-Modify

Page 66: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

1: int verify_iovec (struct msghdr *m, ..., char *address, int mode)

2: {

3: int err;

4:

5: if (m->msg_namelen) {

6: if (mode == VERIFY_READ) {

7: err = move_addr_to_kernel (m->msg_name,

8: m->msg_namelen,

9: address);

10: if (err < 0) return err;

11: }

12:

13: m->msg_name = address;

14: } else {

15: m->msg_name = NULL;

16: }

17: ...

18:}

False Alarm: Interprocedural Must-Modify

m->msg_name must-modified under !(m->msg_namelen && mode == VERIFY_READ && err < 0)

Page 67: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Interprocedural Branch Correlation

1: int sound_ioctl(uint cmd, ulong arg) {

2:

3: if (_SIOC_DIR(cmd) != _SIOC_NONE &&

4: _SIOC_DIR(cmd) != 0)

5:

6: if(_SIOC_DIR(cmd)&_SIOC_WRITE)

7: if (!access_ok(arg))

8: return -EFAULT;

9:

10: ...

11: return sound_mixer_ioctl(cmd, arg);

12: }

13: int sound_mixer_ioctl(uint cmd, void *arg) 14: { 15: ... 16: return aci_mixer_ioctl(cmd, arg); 17: }18: 19: 20: int aci_mixer_ioctl(uint cmd, void *arg) 21: {22: switch(cmd) 23: case SOUND_MIXER_WRITE_IGAIN: 24: ...*arg...; 25: ... 26: }

Page 68: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Interprocedural Branch Correlation

1: int sound_ioctl(uint cmd, ulong arg) {

2:

3: if (_SIOC_DIR(cmd) != _SIOC_NONE &&

4: _SIOC_DIR(cmd) != 0)

5:

6: if(_SIOC_DIR(cmd)&_SIOC_WRITE)

7: if (!access_ok(arg))

8: return -EFAULT;

9:

10: ...

11: return sound_mixer_ioctl(cmd, arg);

12: }

13: int sound_mixer_ioctl(uint cmd, void *arg) 14: { 15: ... 16: return aci_mixer_ioctl(cmd, arg); 17: }18: 19: 20: int aci_mixer_ioctl(uint cmd, void *arg) 21: {22: switch(cmd) 23: case SOUND_MIXER_WRITE_IGAIN: 24: ...*arg...; 25: ... 26: }

1

Page 69: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Interprocedural Branch Correlation

1: int sound_ioctl(uint cmd, ulong arg) {

2:

3: if (_SIOC_DIR(cmd) != _SIOC_NONE &&

4: _SIOC_DIR(cmd) != 0)

5:

6: if(_SIOC_DIR(cmd)&_SIOC_WRITE)

7: if (!access_ok(arg))

8: return -EFAULT;

9:

10: ...

11: return sound_mixer_ioctl(cmd, arg);

12: }

13: int sound_mixer_ioctl(uint cmd, void *arg) 14: { 15: ... 16: return aci_mixer_ioctl(cmd, arg); 17: }18: 19: 20: int aci_mixer_ioctl(uint cmd, void *arg) 21: {22: switch(cmd) 23: case SOUND_MIXER_WRITE_IGAIN: 24: ...*arg...; 25: ... 26: }

1. *argchecked under condition_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE

1

Page 70: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Interprocedural Branch Correlation

1: int sound_ioctl(uint cmd, ulong arg) {

2:

3: if (_SIOC_DIR(cmd) != _SIOC_NONE &&

4: _SIOC_DIR(cmd) != 0)

5:

6: if(_SIOC_DIR(cmd)&_SIOC_WRITE)

7: if (!access_ok(arg))

8: return -EFAULT;

9:

10: ...

11: return sound_mixer_ioctl(cmd, arg);

12: }

13: int sound_mixer_ioctl(uint cmd, void *arg) 14: { 15: ... 16: return aci_mixer_ioctl(cmd, arg); 17: }18: 19: 20: int aci_mixer_ioctl(uint cmd, void *arg) 21: {22: switch(cmd) 23: case SOUND_MIXER_WRITE_IGAIN: 24: ...*arg...; 25: ... 26: }

1. *argchecked under condition_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE

1

2

Page 71: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Interprocedural Branch Correlation

1: int sound_ioctl(uint cmd, ulong arg) {

2:

3: if (_SIOC_DIR(cmd) != _SIOC_NONE &&

4: _SIOC_DIR(cmd) != 0)

5:

6: if(_SIOC_DIR(cmd)&_SIOC_WRITE)

7: if (!access_ok(arg))

8: return -EFAULT;

9:

10: ...

11: return sound_mixer_ioctl(cmd, arg);

12: }

13: int sound_mixer_ioctl(uint cmd, void *arg) 14: { 15: ... 16: return aci_mixer_ioctl(cmd, arg); 17: }18: 19: 20: int aci_mixer_ioctl(uint cmd, void *arg) 21: {22: switch(cmd) 23: case SOUND_MIXER_WRITE_IGAIN: 24: ...*arg...; 25: ... 26: }

1. *argchecked under condition_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE

2. cmd == SOUND_MIXER_WRITE_IGAIN implies_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE

1

2

Page 72: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Function Pointers

1: struct { char *name; ...} map[] = ...,

2: {[NFSCTL_GETFD] = {.name = ".getfd", ...},

3: [NFSCTL_GETFS] = {.name = ".getfs", ...},};

4:

5: long sys_nfsservctl (int cmd, ..., void *res) {

6: ...

7: struct file *file = do_open(map[cmd].name);

8: ...

9: int err = file->f_op->read(file, res, ...);

10: ...

11: }

Page 73: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

False Alarm:Function Pointers

1: int notifier_call_chain(struct notifier_block **nl, ulong val, void *v)

2: {

3: int ret = NOTIFY_DONE;

4: struct notifier_block *nb;

5:

6: nb = *nl;

7:

8: while (nb) {

9: ret = nb->notifier_call(nb, val, v);

10: ...

11: nb = nb->next;

12: }

13:

14: return ret;

15: }

Page 74: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Related Work

• MECA, by Yang, Kremenek, Xie, Engler

– bug finder, path-insensitive, Linux, automatic

• Sparse, by Torvalds

– bug finder, path-insensitive, Linux, 10,000 annotations

• CQual, by Johnson, Wagner

– verifier, path-insensitive, Linux, automatic, 300 KLOC

• ESP, by Dor, Adams, Das, Yang

– verifier, path-sensitive, Windows, automatic, 1 MLOC

Page 75: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Future Work

• Eliminate the time outs on procedures

• Handle inline assembly statements

• Reduce number of false alarms

Page 76: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Conclusions

• Nearly verifying important security property

• Scaling to largest open source program

• Reporting low number of false alarms

Page 77: Verifying the Safety of User Pointer Dereferences Suhabe Bugrara suhabe@stanford.edu Stanford University Joint work with Alex Aiken

Questions