• No results found

Past Sensitive Pointer Analysis for Symbolic Execution

N/A
N/A
Protected

Academic year: 2021

Share "Past Sensitive Pointer Analysis for Symbolic Execution"

Copied!
65
0
0

Loading.... (view fulltext now)

Full text

(1)

Past Sensitive Pointer Analysis

for Symbolic Execution

David Trabish, Timotej Kapus, Noam Rinetzky, and Cristian Cadar Tel-Aviv University, Israel Imperial College, UK

(2)

Symbolic Execution: Introduction

• Systematic program analysis technique • Many applications:

• Test input generation • Bug finding

• ...

(3)

Symbolic Execution & Pointer Analysis

pointer analysis

(4)

Symbolic Execution & Pointer Analysis

[Symbiotic] (TACAS’13) [KATCH] (FSE’13)

[Chopper] (ICSE’18)

[Segmented memory model] (FSE’19)

pointer analysis

(5)

Symbolic Execution & Pointer Analysis

[Symbiotic] (TACAS’13) [KATCH] (FSE’13)

[Chopper] (ICSE’18)

[Segmented memory model] (FSE’19)

pointer analysis

symbolic execution

(6)

Symbolic Execution & Pointer Analysis

[Symbiotic] (TACAS’13) [KATCH] (FSE’13)

[Chopper] (ICSE’18)

[Segmented memory model] (FSE’19)

pointer analysis

symbolic execution

(7)
(8)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N];

for (int i = 0; i < N; i++) objs[i] = calloc(...); ...

(9)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

(10)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

(11)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

All objects allocated in the loop have same allocation site

Can’t be distinguished between

(12)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) // pts: (𝑪, 𝟎) o->d = 7;

} ...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

All objects allocated in the loop have same allocation site

Can’t be distinguished between

objs[0] and objs[1]

(13)

Example

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) // pts: (𝑪, 𝟎) o->d = 7;

} ...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

All objects allocated in the loop have same allocation site

Can’t be distinguished between

objs[0] and objs[1]

(14)

Goal

Run pointer analysis on-demand, not ahead of time: • From a specific symbolic state

(15)

Past-Sensitive Pointer Analysis

• Distinguish between past and future: • Objects that were already allocated

• Objects that might be allocated during pointer analysis • Local pointer analysis

obj_t *objs[N];

for (int i = 0; i < N; i++) objs[i] = calloc(...); ...

objs[0]->p = malloc(...); foo(objs[1]);

void foo(obj_t *o) {

if (o->p) // pts: (B, 1)

o->d = 7; // pts: (B, 0)

(16)

Unique Allocation Sites

During symbolic execution:

• Allocated objects are associated with unique allocation sites for (int i = 0; i < N; i++)

(17)

Unique Allocation Sites

During symbolic execution:

• Allocated objects are associated with unique allocation sites for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

(18)

Local Pointer Analysis

When a symbolic state reaches a function call: • Compute a path-specific abstraction

• Run pointer analysis from the initial abstract state

(19)

Local Pointer Analysis

Use current symbolic state to abstract:

• Traverse function parameters and global variables • Translate to points-to graph

(20)

Local Pointer Analysis

symbolic state

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

(21)

Local Pointer Analysis

o

symbolic state

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

(22)

Local Pointer Analysis

o

symbolic state

d p

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

(23)

Local Pointer Analysis

o symbolic state d p null

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

foo(objs[1]);

(24)

Local Pointer Analysis

o symbolic state d p null

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

(25)

Local Pointer Analysis

o symbolic state d p null

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

(26)

Local Pointer Analysis

o symbolic state d p null

typedef struct { int d, *p; } obj_t; void foo(obj_t *o) {

if (o->p) o->d = 7; }

...

obj_t *objs[N]; // AS: A

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

...

objs[0]->p = malloc(...); // AS: C

(27)

Local Pointer Analysis

void foo(obj_t *o) { if (o->p)

o->d = 7; }

abstract state Analyze foo from the initial abstract state:

𝑜𝑣 𝐵2, 0

(28)

Local Pointer Analysis

void foo(obj_t *o) { if (o->p) // pts: 𝒏𝒖𝒍𝒍

o->d = 7; }

abstract state Analyze foo from the initial abstract state:

𝑜𝑣 𝐵2, 0

(29)

Local Pointer Analysis

void foo(obj_t *o) { if (o->p) // pts: 𝒏𝒖𝒍𝒍

o->d = 7; }

abstract state Analyze foo from the initial abstract state:

𝑜𝑣 𝐵2, 0

(𝐵2, 1) 𝑛𝑢𝑙𝑙

(30)

Reusing Summaries

• Number of analyzed functions can be high

• Running pointer analysis from scratch is expensive • Empirical observation

(31)

Reusing Summaries

mod-set

(32)

Reusing Summaries

mod-set

(33)

Reusing Summaries

mod-set

(34)

Reusing Summaries

mod-set

(35)

Reusing Summaries

{ 𝐴, 0 }

mod-set

(36)

Reusing Summaries

{ 𝐴, 0 }

mod-set

(37)

Reusing Summaries

{ 𝐴, 0 }

mod-set

(38)

Reusing Summaries

{ 𝐴, 0 }

mod-set

(39)

Reusing Summaries

{ 𝐴, 0 }

mod-set

(40)

Evaluation

Implemented using:

• KLEE (https://github.com/klee/klee) • SVF (https://github.com/SVF-tools/SVF) Client applications:

• Chopped symbolic execution (ICSE’18) • Symbolic pointer resolution

(41)

Application: Chopped Symbolic Execution

• Skip user-specified functions

• Dynamically resolve side effects of skipped function • Relies on static mod-ref analysis

(42)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

(43)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with static pointer analysis?

(44)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with static pointer analysis?

• mod-set of foo: 𝐵, 0

(45)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with static pointer analysis?

• mod-set of foo: 𝐵, 0

(46)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with static pointer analysis?

• mod-set of foo: 𝐵, 0

• read location abstracted by 𝐵, 0

(47)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

(48)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with past-sensitive pointer analysis?

(49)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with past-sensitive pointer analysis?

• mod-set of foo: 𝐵2, 0

(50)

Application: Chopped Symbolic Execution

void foo(obj_t *o) { if (o->p)

o->d = 7; }

...

for (int i = 0; i < N; i++)

objs[i] = calloc(...); // AS: B

foo(objs[1]);

int y = objs[0]->d;

Can we skip foo with past-sensitive pointer analysis?

• mod-set of foo: 𝐵2, 0

(51)

Application: Chopped Symbolic Execution

Compare static and past-sensitive mod-ref analysis: • Reducing recoveries

• Code coverage

(52)

Application: Chopped Symbolic Execution

Reducing recoveries

• Several configurations of skipped functions • Record number of recoveries per path

• Show relative reduction compared to static pointer analysis Benchmark Min Max

libosip 0% 57%

libtiff 61% 99%

(53)

Application: Chopped Symbolic Execution

Code coverage

• Manually select skipped functions • Measure coverage (lines)

Benchmark Search Static PSPA

(54)

Application: Chopped Symbolic Execution

Failure reproduction

• Measure time required to find bugs (DFS search heuristic)

CVE Chopping-aware heuristic

Without With

(55)

Application: Symbolic Pointer Resolution

• Symbolic pointers may point to multiple objects • Resolve by scanning the memory

• Construct a SMT query for each scanned object • SMT queries are expensive

𝑚𝑜1 𝑚𝑜2 𝑚𝑜3

(56)

Application: Symbolic Pointer Resolution

• Can improve using points-to information

• Compute the points-to set of the symbolic pointer • If an object is not contained:

• Skip it, and avoid solver queries…

𝑚𝑜1 𝑚𝑜2 𝑚𝑜3

(57)

Application: Symbolic Pointer Resolution

• Computing with static pointer analysis is trivial

• How to compute with past-sensitive pointer analysis?

(58)

Application: Symbolic Pointer Resolution

• Computing with static pointer analysis is trivial

• How to compute with past-sensitive pointer analysis? • Run the analysis from the calling function

void foo(char *key) { h = hash(key); // symbolic pointer p = o->table[h]; if (p->x > 7) ... }

(59)

Application: Symbolic Pointer Resolution

(60)

Application: WIT

Write integrity testing (WIT)

• Detect memory corruptions in runtime (in production) • Each pointer and object are assigned a color

(61)

Application: WIT

Color assignment relies on static pointer analysis

(62)

Application: WIT

• Need a more precise color assignment

• Compute colors only after the initialization code completes • Use past-sensitive pointer analysis

analyze from here

(63)

Application: WIT

Evaluation:

• Compute the number of colors

• Record the number of color transitions (between allocations) • During one hour

Benchmark Paths Colors Transitions

Static PSPA Static PSPA

libosip 12,084,552 70 277 108,532,593 302,069,717 libtasn1 90,289 157 645 8,848,322 39,456,279

(64)

Future Work

• Integrate symbolic execution with other static analyses • Constant propagation, numerical analysis, etc.

• Apply to other pointer analyses

(65)

Summary

• Tighter integration between symbolic execution and pointer analysis • Evaluated with several client applications:

• Chopped symbolic execution • Symbolic pointer resolution • WIT

Available on github: https://github.com/davidtr1037/klee-pspa

References

Related documents

MPS-ovi mogu prijaviti projektne prijedloge za ovu prioritetnu os na trenutno otvorene natječaje (1) Kompetentnost i razvoj MSP-ova (cilj 3d1, raspoloživa sredstva 867 mil. kn)

Following the first European experience in RAKT [7,8] , the robotic approach in KT is now performed in a few European centers as an alternative to the open approach in

If the detector is on, the solenoid is clicking and the offset is zero, then as previously mentioned, the ratio of the column + makeup gas flow to reference flow should be

● Symbolic execution is the execution of the program using symbolic variables instead of concrete values. ● Symbolic execution translates the program's semantic into a

FICS: flow-insensitive, context-sensitive analysis FSCI: flow-sensitive, context-insensitive analysis FSCS: flow-sensitive, context-sensitive analysis All field sensitive..

Hypothesis 2: Individuals exploiting Schumpeterian opportunities are more likely to be (2A) better educated, (2B) innovative, (2C) marked by higher risk taking propensity and

Standard Semi-Customized Full-Customized | 3 Core Competence | 4 System Solutions | 5 Embedded Systems | 6 Infinity ® 19“ Industrial Rack Systems | 10 Panel PC

In Tools and Algorithms for the Construction and Analysis of Systems - 27th International Conference, TACAS 2021, Held as Part of the European Joint Conferences on Theory and