SAFECode Memory Safety Without Runtime Checks or Garbage Collection By Dinakar Dhurjati Joint work...
-
Upload
shon-roberts -
Category
Documents
-
view
222 -
download
0
Transcript of SAFECode Memory Safety Without Runtime Checks or Garbage Collection By Dinakar Dhurjati Joint work...
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
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
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
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
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
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
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”
SAFECode
Dangling pointer problem
struct S *p, *q;
….
p = q
….
free(p)
…
q->next->val = … //dangling pointer usage
p
r = malloc(sizeof(struct T))
q
q->next
r
q
r
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.
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
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
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); } …}
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
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
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
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
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++
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
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
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 ?
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
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
SAFECode
URLs
SAFECode
Static Analysis For safe Execution of Code
http://safecode.cs.uiuc.edu/
LLVM
http://llvm.cs.uiuc.edu
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)
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