verifying the safety of user pointer dereferences
Download
Skip this Video
Download Presentation
Verifying the Safety of User Pointer Dereferences

Loading in 2 Seconds...

play fullscreen
1 / 77

Verifying the Safety of User Pointer Dereferences - PowerPoint PPT Presentation


  • 73 Views
  • Uploaded 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

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' - alina


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

[email protected]

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
slide7
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
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
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
ad