Pending Constraints in Symbolic Execution for Better Exploration and - - PowerPoint PPT Presentation

pending constraints in symbolic execution for better
SMART_READER_LITE
LIVE PREVIEW

Pending Constraints in Symbolic Execution for Better Exploration and - - PowerPoint PPT Presentation

Pending Constraints in Symbolic Execution for Better Exploration and Seeding Timotej Kapus Frank Busse Cristian Cadar Imperial College London 1 Symbolic Execution Program analysis technique Active research area Used in


slide-1
SLIDE 1

Pending Constraints in Symbolic Execution for Better Exploration and Seeding

Timotej Kapus Frank Busse Cristian Cadar Imperial College London

1

slide-2
SLIDE 2

Symbolic Execution

2

  • Program analysis technique
  • Active research area
  • Used in industry

○ IntelliTest, SAGE ○ KLOVER

Angr

slide-3
SLIDE 3

Why symbolic execution?

3

  • No false positives!

○ Every bug found has a concrete input triggering it

  • Can interact with the environment

○ I/O, unmodeled libraries

  • Only relevant code executed

“symbolically”, the rest is fast “native” execution

slide-4
SLIDE 4

Why (not) symbolic execution?

4

  • Scalability, scalability, scalability

○ Constraint solving is hard ○ Path explosion

slide-5
SLIDE 5

This talk

5

Introduce pending constraints which enhance the scalability of symbolic execution via aggressively tackling paths that are known to be feasible.

slide-6
SLIDE 6

“known to be feasible”

6

Caching

  • Cache assignments from

previous solver queries

  • Already widely adopted

Seeding

  • External, usually valid

concrete inputs

  • Used to bootstrap symbolic

execution

  • From test-suites, examples,

production data

slide-7
SLIDE 7

Symbolic execution example: get_sign

7

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

slide-8
SLIDE 8

8

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x);

Known assignments ∅

slide-9
SLIDE 9

9

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); r = -1;

Known assignments ∅

slide-10
SLIDE 10

10

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 r = -1;

Known assignments ∅

slide-11
SLIDE 11

11

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 r = -1;

Known assignments x = -2 Known assignments x = -2

x < 1

slide-12
SLIDE 12

12

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 r = -1;

Known assignments x = -2 Known assignments x = -2 x = 7

x ≥ 1 x < 1

slide-13
SLIDE 13

13

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2 x = 7

x ≥ 1

slide-14
SLIDE 14

14

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2 x = 7

x ≠ 0 x ≥ 1

slide-15
SLIDE 15

15

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 x = 0 r = -1;

Known assignments x = -2 x = 7 x = 0

x = 0 x ≠ 0 x ≥ 1

slide-16
SLIDE 16

16

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 x = 0 r = -1; r = 0;

Known assignments x = -2 x = 7 x = 0

x = 0 x ≠ 0 x ≥ 1

slide-17
SLIDE 17

17

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 x = 0 r = -1; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

x ≠ 0 x ≥ 1

slide-18
SLIDE 18

18

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 x = 0 x ≠ 0 r = -1; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

x ≥ 1

slide-19
SLIDE 19

19

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

slide-20
SLIDE 20

20

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

slide-21
SLIDE 21

21

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

x = 0

slide-22
SLIDE 22

22

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

x = 0 x ≠ 0

slide-23
SLIDE 23

23

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x ≠ 0 x = 0 x ≠ 0 r = -1; r = 1; return r; return r; r = 0; return r;

Known assignments x = -2 x = 7 x = 0

x = 0

slide-24
SLIDE 24

Symbolic execution with pending constraints

24

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

  • Explore paths that are known

to be feasible

  • Solve constraints only when

necessary to make progress

slide-25
SLIDE 25

25

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x);

Known assignments ∅

slide-26
SLIDE 26

26

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); r = -1;

Known assignments ∅

slide-27
SLIDE 27

27

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 r = -1;

Known assignments ∅

x ≥ 1 x < 1

slide-28
SLIDE 28

28

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 r = -1;

Known assignments ∅

x ≥ 1 x < 1

Pending constraints

  • Not known to be feasible
  • When only pending

constraints left ○ Pick one and check

slide-29
SLIDE 29

29

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x < 1 r = -1;

Known assignments x = -2

x ≥ 1

slide-30
SLIDE 30

30

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2

x ≥ 1 x = 0 x ≠ 0

slide-31
SLIDE 31

x ≠ 0

31

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2

x ≥ 1 x = 0

Pending constraints: still not known if feasible

slide-32
SLIDE 32

x = 0

32

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 r = -1; x ≥ 1 x ≠ 0

Pending constraints: known feasible path!

Known assignments x = -2

x < 1

slide-33
SLIDE 33

33

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2

x ≥ 1 x = 0 x ≠ 0 return r;

slide-34
SLIDE 34

34

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 r = -1;

Known assignments x = -2

x ≠ 0 return r; x ≥ 1 x = 0

Only pending constraints: check one

slide-35
SLIDE 35

35

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x < 1 x = 0 x ≠ 0 r = -1; return r; r = 0; return r;

Known assignments x = -2 x = 0

x ≥ 1

slide-36
SLIDE 36

36

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 0 x = 7

slide-37
SLIDE 37

37

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 0 x = 7

slide-38
SLIDE 38

38

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 x = 0 x ≠ 0 r = -1; r = 1; return r; r = 0; return r;

Known assignments x = -2 x = 0 x = 7

return r;

slide-39
SLIDE 39

39

int get_sign(int x) { int r = -1; if (x >= 1) r = 1; if (x == 0) r = 0; return r; }

get_sign(x); x >= 1 x == 0 x == 0 x ≥ 1 x < 1 x = 0 x ≠ 0 x = 0 x ≠ 0 r = -1; r = 1; return r; return r; r = 0; return r;

Known assignments x = -2 x = 0 x = 7

slide-40
SLIDE 40

Pending constraints: why would they be useful?

40

char msg[8] = symbolic; uint32_t *hash = md5(msg, 8); assert(hash[0] == 1471037522)

  • Reversing md5 hash

○ Very hard for SMT solvers

  • 1471037522 = md5("ase2020")[0]

○ Use as seed

slide-41
SLIDE 41

41

Suppose this exploration tree for md5

slide-42
SLIDE 42

42

Suppose this path

md5("ase2020")

slide-43
SLIDE 43

43

Solver queries: 0

Pending Vanilla

slide-44
SLIDE 44

44

Solver queries: 0

Pending Vanilla

ase20 20

slide-45
SLIDE 45

45

Solver queries: 0

Pending Vanilla

ase20 20

slide-46
SLIDE 46

46

Solver queries: 0

Pending Vanilla

ase20 20

slide-47
SLIDE 47

47

Solver queries: 1

Pending Vanilla

ase20 20

slide-48
SLIDE 48

48

Solver queries: 2

Pending Vanilla

ase20 20

slide-49
SLIDE 49

49

Solver queries: 3

Pending Vanilla

ase20 20

slide-50
SLIDE 50

50

Solver queries: 4

Pending Vanilla

ase20 20

slide-51
SLIDE 51

51

Solver queries: 5

Pending Vanilla

ase20 20

slide-52
SLIDE 52

52

Solver queries: 6

Pending Vanilla

ase20 20

slide-53
SLIDE 53

53

Solver queries: 7

Pending Vanilla

ase20 20

slide-54
SLIDE 54

54

Solver queries: 8

Pending Vanilla

ase20 20 ase20 20

slide-55
SLIDE 55

Why pending constraints?

55

  • More efficient use of solver solutions

○ Explore more instructions per query ○ Less time solving infeasible queries

  • Prefers deeper search tree exploration
  • Empowering search heuristics

○ Control over constraint solving ○ ZESTI

slide-56
SLIDE 56

Evaluation

  • Based on an implementation in KLEE
  • 8 real world applications
  • Hard targets for symbolic execution

56

make m4 bc datamash

slide-57
SLIDE 57

Experiment design

  • 2 hour runs
  • With and without seeds
  • 3 search strategies: random path, DFS, depth biased
  • 3 repetitions
  • Case study on SQLite3 with 24 hour runs

57

slide-58
SLIDE 58

Vanilla vs Pending without seeds (random path)

58

slide-59
SLIDE 59

Proportion of time spent solving queries that were infeasible

59

slide-60
SLIDE 60

SQLite3: 24 hour run without seeds (random path)

60

slide-61
SLIDE 61

Vanilla vs Pending with seeds (random path)

61

slide-62
SLIDE 62

SQLite3: 24 hour run with seed

62

slide-63
SLIDE 63

ZESTI and seeding

63

  • Extension of KLEE for

augmenting test suites

  • Explores paths “around” a seed
  • Easy to implement with

pending constraints

  • Found 2 bugs in tar,

dwarfdump that were fixed

ICSE 2012

slide-64
SLIDE 64

Conclusion

  • Pending constraints

○ Tackles scalability of symbolic execution by aggressively following paths that are known to be feasible

  • Effective in improving coverage for 8 challenging programs

64

slide-65
SLIDE 65

65

slide-66
SLIDE 66

66

slide-67
SLIDE 67

Without seeds

67

slide-68
SLIDE 68

Time spent constraint solving by vanilla KLEE

68

slide-69
SLIDE 69

69

slide-70
SLIDE 70

70