Verifying the safety of user pointer dereferences
Download
1 / 77

Verifying the Safety of User Pointer Dereferences - PowerPoint PPT Presentation


  • 210 Views
  • Updated On :

Verifying the Safety of User Pointer Dereferences. Suhabe Bugrara [email protected] Stanford University Joint work with Alex Aiken. Unchecked User Pointer Dereferences. Security property of operating systems Two types of pointers in operating systems

Related searches for Verifying the Safety of User Pointer Dereferences

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

PowerPoint Slideshow about 'Verifying the Safety of User Pointer Dereferences' - andrew


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 l.jpg

Verifying the Safety of User Pointer Dereferences

Suhabe Bugrara

[email protected]

Stanford University

Joint work with Alex Aiken


Unchecked user pointer dereferences l.jpg
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 dereferences3 l.jpg
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 dereferences4 l.jpg
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 dereferences5 l.jpg
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 l.jpg
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


Slide7 l.jpg
Goal

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


Challenges l.jpg
Challenges

  • Verification

    • provide guarantee of correctness

  • Precision

    • report low number of false alarms

  • Scalability

    • analyze more than 6 MLOC



Verification10 l.jpg
Verification

  • Soundness

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


Verification11 l.jpg
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


Verification12 l.jpg
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 l.jpg
Sound and Incomplete Verifier

  • Proves the absence of vulnerabilities

  • May report false alarms


Soundness caveats l.jpg
Soundness Caveats

  • Unsafe memory operations

  • Concurrency

  • Inline assembly

  • Analysis fails to analyze some procedures


Precision l.jpg
Precision

  • Minimize the number of false alarms

  • Reasoning more deeply about program

  • Computationally expensive

  • High precision inhibits scalability


Example l.jpg
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 l.jpg
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 approach18 l.jpg
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 approach19 l.jpg
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 approach20 l.jpg
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 approach21 l.jpg
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 approach22 l.jpg
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 l.jpg
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


Example24 l.jpg
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 sensitivity25 l.jpg
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 sensitivity26 l.jpg
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 sensitivity27 l.jpg
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 sensitivity28 l.jpg
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 l.jpg
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 analysis30 l.jpg
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 analysis31 l.jpg
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 analysis32 l.jpg
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 analysis33 l.jpg
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 analysis34 l.jpg
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 analysis35 l.jpg
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 analysis36 l.jpg
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 analysis37 l.jpg
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 analysis38 l.jpg
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 analysis39 l.jpg
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 analysis40 l.jpg
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 analysis41 l.jpg
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 analysis42 l.jpg
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 l.jpg
Scalability

  • Abstraction

    • Throw away guards at procedure boundaries

  • Compositionality

    • Analyze each procedure in isolation


Path sensitive analysis44 l.jpg
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 l.jpg
Abstraction

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false

initial summary


Abstraction46 l.jpg
Abstraction

α

=

(*u,user)  true

(*u,checked)  cmd == 1

(*u,error)  false

abstraction function

initial summary


Abstraction47 l.jpg
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


Abstraction48 l.jpg
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


Abstraction49 l.jpg
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 l.jpg
Compositionality

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }


Compositionality51 l.jpg
Compositionality

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user)  c1


Compositionality52 l.jpg
Compositionality

“context variable”

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user)  c1


Compositionality53 l.jpg
Compositionality

1: int get (int *v) {

2: int x;

3:

4: x = *v;

5:

6: return x;

7: }

(*v,user)  c1

(*v,user)  c1


Compositionality54 l.jpg
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


Compositionality55 l.jpg
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 l.jpg
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 l.jpg
Analysis Passes

  • Alias analysis

    • computes memory model for each procedure


Analysis passes58 l.jpg
Analysis Passes

  • Alias analysis

    • computes memory model for each procedure

  • User state propagation

    • propagates user states throughout OS


Analysis passes59 l.jpg
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




Results l.jpg
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 l.jpg
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 modify64 l.jpg
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 modify65 l.jpg
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 modify66 l.jpg
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 l.jpg
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 correlation68 l.jpg
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 correlation69 l.jpg
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 correlation70 l.jpg
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 correlation71 l.jpg
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 l.jpg
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 pointers73 l.jpg
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 l.jpg
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 l.jpg
Future Work

  • Eliminate the time outs on procedures

  • Handle inline assembly statements

  • Reduce number of false alarms


Conclusions l.jpg
Conclusions

  • Nearly verifying important security property

  • Scaling to largest open source program

  • Reporting low number of false alarms



ad