Memory Safety Without Runtime Checks or Garbage Collection

27
SAFECode Memory Safety Without Runtime Checks or Garbage Collection By Dinakar Dhurjati Joint work with Sumant Kowshik, Vikram Adve and Chris Lattner University of Illinois at Urbana- Champaign

description

Memory Safety Without Runtime Checks or Garbage Collection. By Dinakar Dhurjati Joint work with Sumant Kowshik, Vikram Adve and Chris Lattner University of Illinois at Urbana-Champaign. Motivation. Secure Online Upgrades in Embedded Systems. - PowerPoint PPT Presentation

Transcript of Memory Safety Without Runtime Checks or Garbage Collection

Page 1: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Memory Safety Without Runtime Checks or Garbage Collection

By

Dinakar Dhurjati

Joint work with

Sumant Kowshik, Vikram Adve and Chris Lattner

University of Illinois at Urbana-Champaign

Page 2: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Motivation

Upgrade := new software modules in to host application

• Same address space

• Need to protect the host from Buggy/Untrusted modules

• Need to ensure each module is memory safe

Memory safe := Never access a memory location outside its data area Never execute instructions outside its code area

Secure Online Upgrades in Embedded Systems

Need Language and Compiler support for memory safety

Page 3: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Existing Solutions

Problems

Bad Casts

Unintialized pointers

Array bound violations

Dangling pointers to stack locations

Dangling pointers to freed memory

Current Solutions e.g. Java, RT-Java,Modula -3

Runtime null pointer checks

Not expressible

No free + Garbage Collection [ + scoped regions + runtime checks]

Runtime array bound checks

Runtime checks or garbage collection unattractive for Embedded Code

Type checker disallows

Page 4: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Our Approach

1. Minimal semantic restrictions to enable static checking– No new syntax or annotations

2. Aggressive compiler techniques (old and new)

Goal : 100 % Static Checking

Page 5: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Our Previous Work[CASES2002]

Problems

Bad Casts

Unintialized pointers

Array bound violations

Dangling pointers to stack locations (stack safety)

Dangling pointers to freed memory (heap safety)

Our Previous Solutions

Type checker disallowsInitialize to reserved address range

Language rule + Compiler checks

???

Restrict index to be affine in terms of size

Static safety for real time control programs

Page 6: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Contributions of this Work

• 100% static technique for ensuring heap safety for “type safe” C programs– No Runtime Checks– No Garbage Collection : allow explicit deallocation!– No Programmer annotations

• Evaluate our approach on 17 embedded benchmarks– Array Safety – Heap safety – Stack safety

Page 7: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Talk Outline

• Introduction

• Our Solution

• Results

• Related Work

• Conclusion

Page 8: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Methodology

• Do not prevent uses of dangling pointers to freed memory

• Ensure that they cannot cause memory safety violation– Builds on a compiler transformation called

“Automatic Pool Allocation”

Page 9: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Dangling pointer problem

struct S *p, *q;

….

p = q

….

free(p)

q->next->val = … //dangling pointer usage

p

qq

r = malloc(sizeof(struct T))

q

q->next

r

q

r

Page 10: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

q

Making Dangling Pointers Safe

struct S *p, *q;

….

p = q

….

free(p)

q->next->val = … //dangling pointer usage

s = malloc(sizeof(struct S))

s ->next

q

q->next

s

Principle : If freed memory is reallocated to any object of the same type with same alignment, then dereferencing pointers to freed memory is safe.

Page 11: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Exploiting the principle

• First simple solution– N different heaps based on type, N = #types– Never move memory from one heap to other

BUT : Increased memory consumption

• A more sophisticated solution : Using previously developed compiler transformation called Automatic Pool Allocation

Page 12: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Automatic Pool Allocation

• Identifies logical data structures not reachable from outside a function

• Creates a separate pool (region) for nodes of that data structure.

• At the function exit, entire pool is deallocated

• Advantages :Fine grained poolsSmall life timesType homogenous poolsExplicit deallocation

Page 13: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Pool Allocation Examplef() {

… p = g(); … p->next->val = …..

}

g() { … p = create_list_10_nodes(p); h(p); free_everything_but_head(p); … return p; }

p

h(struct S *p) { … for (j = 0; j < 100000; j++) { tmp = malloc(sizeof(struct s)) insert_tmp_to_list(tmp,p); …. q = least_useful_member(p) free(q); } …}

Page 14: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Pool Allocation Examplef() { PP = poolinit(struct S); … p = g(PP); … p->next->val = ….. pooldestroy(PP)}

g(PoolPointer *PP) { … p = create_list_10_nodes(PP); h(p, PP); free_everything_but_head(p, PP); … return p; }

p

h(struct S *p, PoolPointer *PP) { … for (j = 0; j < 100000; j++) { tmp = poolalloc(PP); insert_tmp_to_list(tmp,p); …. q = least_useful_member(p); poolfree(q, PP); } …}

Not Memory Safe

PP

Page 15: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Using Pool Allocation for Safety

• Pools are type homogenous

• Restriction : Do not release memory from a pool until pooldestroy

=> The principle is satisfied : “Accessible freed memory is reallocated only to objects of the same type”.

Memory Safety guaranteed

Problem– Could lead to increased memory consumption– Need to identify when it happens

Page 16: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Identifying increased memory usage

f() { PP = poolinit(struct S); … g(p, PP); … p->next->val = ….. pooldestoy(PP);}

g(Struct S *p, PoolPointer *PP) { … create_list_10_nodes(p, PP); h(p, PP); free_everything_but_head(p, PP); … }

h(struct S *p, PoolPointer *PP) { … //no free after allocation for (j = 0; j < 10; j++) { …. q = least_useful_member(p) poolfree(q,PP); }

…}

Case 1 : No Reuse

h(struct S *p, PoolPointer *PP) { … for (j = 0; j < 100000; j++) { tmp = poolalloc(PP); insert_tmp_to_list(tmp,p); …. q = least_useful_member(p) poolfree(q,PP); } …}

h(struct S *p, PoolPointer *PP) { … for (j = 0; j < 100000; j++) { tmp = poolalloc(PP); tmp2 = poolalloc(PP2); insert_tmp_to_list(tmp,p); …. q = least_useful_member(p) poolfree(q,PP); } …}

Case 2 : Self Reuse

Case 3 : Cross Reuse

Page 17: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Algorithm

On all control flow paths interprocedurally

For every poolfree(…, P) on the path,

if before the subsequent pooldestroy(P)

there is

No poolalloc : P is Case 1 poolalloc only from the same pool : P is Case

2 poolalloc from a different pool : P is Case 3

Page 18: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Implementation

C GCCLLVM Linker

LLVM

Object code

• Source Language Independence

• Link – time Analysis => whole program analysis

Pool Allocation

Categorizing pools

Safe Code

with no checks

Type Safety

Uninit. Variables

Stack Safety

Array Safety

C++

Page 19: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Evaluation

• 17 applications in MediaBench and MIBench suite of bench marks

• Studied how easy it is to port them

• Results for 6 of them

Program Lines of Code

No of Lines Modified

Basicmath 579 4

Epic 3524 4

Dijkstra 348 0

Gsm 6038 0

Mpeg 9839 0

Rasta 7373 13

39869 59Total for 17 pgms

Page 20: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Results : Heap Safety

All 17 programs are proven heap safe!

• 15 Programs had only Case 1 or Case 2 pools

Memory safety without increase in memory consumption

• 2 programs with Case 3 pools– Rasta : 5 Case-3 pools out of 14– Epic : 1 Case-3 pool out of 14– Further Analysis can convert some Case 3 pools

to Case 2

Page 21: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Results - II

• Stack Safety– 16 codes passed the compiler– 1 code needs restructuring to pass

• Array Safety– Only 8 codes passed – Indirection vectors caused 5 codes to fail– Detected 4 bugs in benchmarks

Array Bounds Checking remaining bottleneck for 100% static checking

How do our previous techniques work ?

Page 22: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Related Work : Static Heap Safety Checking

Linear and alias type systems : Vault – Severely restrict aliasing in programs– Require lot of annotations

Region based Schemes : TofteTalpin[TOPLAS98], Aiken[PLDI98], Cyclone, RT-Java, Boyapati[PLDI03]– No deallocation within a region – Manual region annotations in most cases

Page 23: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Conclusions

• Result : Guarantee heap safety statically for “type safe” C.

=> New State of the Art :

100 % Static Checking for all C codes that – Are “type safe”– Use only affine array references

Page 24: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

URLs

SAFECode

Static Analysis For safe Execution of Code

http://safecode.cs.uiuc.edu/

LLVM

http://llvm.cs.uiuc.edu

Page 25: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Pool Allocation Example

f() {

… g(p); … p->next->val = …..

}

g(Struct S *p) { … create_list_10_nodes(p); h(p); free_everything_but_head(p); … }

PP = poolinit(Struct S);

h(struct S *p) { … for (j = 0; j < 100000; j++) { insert_tmp_to_list(tmp); …. q = least_useful_member(p) free(q); } …}

poolfree(PP,q)

tmp = malloc(sizeof(Struct S))

pooldestroy(PP);

tmp = poolalloc(PP)

Page 26: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Results : Heap Safety• All 17 are guaranteed heap safe

• 15 programs had only Case 1 or Case 2 poolsMemory safety without increase in memory consumption

• 2 programs with Case 3 pools• rasta -- 5 Case 3 out of 14 pools• epic -- 1 Case 3 out of 13 pools• Further analysis can convert some

case 3 to case 2 pools

Page 27: Memory Safety Without Runtime Checks or Garbage Collection

SAFECode

Conclusions and Future Work

• 100 % static checking for heap safety

• Future Work– Improve the array bounds checker– Evaluate the actual increase, if any, in the few

case 3 pools.– Detect illegal system calls/illegal sequences of

system calls