Verifying the Safety of User Pointer Dereferences - PowerPoint PPT Presentation

Verifying the safety of user pointer dereferences
Download
1 / 77

  • 55 Views
  • Uploaded on
  • Presentation posted in: General

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

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

Download Presentation

Verifying the Safety of User Pointer Dereferences

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Verifying the safety of user pointer dereferences

Verifying the Safety of User Pointer Dereferences

Suhabe Bugrara

suhabe@stanford.edu

Stanford University

Joint work with Alex Aiken


Unchecked user pointer dereferences

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


Unchecked user pointer dereferences1

Unchecked User PointerDereferences

1: static ssize_t read_port(…, char * __user buf, …) {

2:unsigned long i = *ppos;

3:char * __user tmp = buf;

4:


Unchecked user pointer dereferences2

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) //deref

10:return -EFAULT;

11:i++;

12:tmp++;

13:}

14:

15:*ppos = i;

16:return tmp-buf;

17: }


Unchecked user pointer dereferences3

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) //deref

10:return -EFAULT;

11:i++;

12:tmp++;

13:}

14:

15:*ppos = i;

16:return tmp-buf;

17: }


Security vulnerability

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


Verifying the safety of user pointer dereferences

Goal

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


Challenges

Challenges

  • Verification

    • provide guarantee of correctness

  • Precision

    • report low number of false alarms

  • Scalability

    • analyze more than 6 MLOC


Verification

Verification


Verification1

Verification

  • Soundness

    • If the program analysis reports that no vulnerabilities exist, then the program contains none


Verification2

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


Verification3

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


Sound and incomplete verifier

Sound and Incomplete Verifier

  • Proves the absence of vulnerabilities

  • May report false alarms


Soundness caveats

Soundness Caveats

  • Unsafe memory operations

  • Concurrency

  • Inline assembly

  • Analysis fails to analyze some procedures


Precision

Precision

  • Minimize the number of false alarms

  • Reasoning more deeply about program

  • Computationally expensive

  • High precision inhibits scalability


Example

Example

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: }


One possible approach

One Possible Approach

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)


One possible approach1

One Possible Approach

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)


One possible approach2

One Possible Approach

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)


One possible approach3

One Possible Approach

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)

(*u,user)

(*u,checked)


One possible approach4

One Possible Approach

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)

(*u,user)

(*u,checked)

(*u,user) lost precision!


One possible approach5

One Possible Approach

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)

(*u,user)

(*u,checked)

(*u,user) lost precision!

(*u,user)

(*u,error) emit warning!

…, but, procedure does not contain any vulnerabilities!


Path sensitivity

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


Example1

Example

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: }


Path sensitivity1

Path Sensitivity

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: }

Valid Path


Path sensitivity2

Path Sensitivity

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: }

Valid Path


Path sensitivity3

Path Sensitivity

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: }

Valid Path


Path sensitivity4

Path Sensitivity

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: }

Invalid Path!


Path sensitive analysis

Path Sensitive Analysis

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: }


Path sensitive analysis1

Path Sensitive Analysis

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


Path sensitive analysis2

Path Sensitive Analysis

“guard”

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


Path sensitive analysis3

Path Sensitive Analysis

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


Path sensitive analysis4

Path Sensitive Analysis

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

(*u,user)  true


Path sensitive analysis5

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1


Path sensitive analysis6

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1


Path sensitive analysis7

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  . . .


Path sensitive analysis8

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  cmd == 1 && . . .


Path sensitive analysis9

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  cmd == 1 && !(cmd == 1) && . . .


Path sensitive analysis10

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  cmd == 1 && !(cmd == 1) && true

. . .


Path sensitive analysis11

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  cmd == 1 && !(cmd == 1) && true

 false


Path sensitive analysis12

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false


Path sensitive analysis13

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false


Scalability

Scalability

  • Abstraction

    • Throw away guards at procedure boundaries

  • Compositionality

    • Analyze each procedure in isolation


Path sensitive analysis14

Path Sensitive Analysis

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false


Abstraction

Abstraction

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false

initial summary


Abstraction1

Abstraction

α

=

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false

abstraction function

initial summary


Abstraction2

Abstraction

α

=

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false

(*u,user)  true

(*u,checked)  false

(*u,error)  false

abstraction function

initial summary

final

summary


Abstraction3

Abstraction

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false


Abstraction4

Abstraction

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

(*u,user)  true

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  cmd == 1

(*u,user)  true

(*u,checked)  false

(*u,error)  false


Compositionality

Compositionality

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }


Compositionality1

Compositionality

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }

(*v,user)  c1


Compositionality2

Compositionality

“context variable”

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }

(*v,user)  c1


Compositionality3

Compositionality

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }

(*v,user)  c1

(*v,user)  c1


Compositionality4

Compositionality

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }

(*v,user)  c1

(*v,user)  c1

(*v,user)  c1

(*v,error)  c1


Compositionality5

Compositionality

1: int get (int *v) {

2: int x;

3:

4:x = *v;

5:

6:return x;

7: }

(*v,user)  c1

(*v,user)  c1

(*v,user)  c1

(*v,error)  c1


Fixed point computation

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


Analysis passes

Analysis Passes

  • Alias analysis

    • computes memory model for each procedure


Analysis passes1

Analysis Passes

  • Alias analysis

    • computes memory model for each procedure

  • User state propagation

    • propagates user states throughout OS


Analysis passes2

Analysis Passes

  • Alias analysis

    • computes memory model for each procedure

  • User state propagation

    • propagates user states throughout OS

  • Unchecked and safety state propagation

    • determines safety of each dereference site


Linux 2 6 17 1 built for x86

Linux 2.6.17.1 built for x86


Experiment setup

Experiment Setup


Results

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


False alarm interprocedural must modify

False Alarm: Interprocedural Must-Modify

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 modify1

False Alarm: Interprocedural Must-Modify

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 modify2

False Alarm: Interprocedural Must-Modify

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 modify3

False Alarm: Interprocedural Must-Modify

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:}

m->msg_name

must-modified under

!(m->msg_namelen &&

mode == VERIFY_READ &&

err < 0)


False alarm interprocedural branch correlation

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: }


False alarm interprocedural branch correlation1

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


False alarm interprocedural branch correlation2

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

1. *arg

checked under condition

_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE


False alarm interprocedural branch correlation3

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

2

1. *arg

checked under condition

_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0 && _SIOC_DIR(cmd)&_SIOC_WRITE


False alarm interprocedural branch correlation4

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

2

1. *arg

checked 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


False alarm function pointers

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: }


False alarm function pointers1

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: }


Related work

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


Future work

Future Work

  • Eliminate the time outs on procedures

  • Handle inline assembly statements

  • Reduce number of false alarms


Conclusions

Conclusions

  • Nearly verifying important security property

  • Scaling to largest open source program

  • Reporting low number of false alarms


Questions

Questions


  • Login