• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Automatically Tolerating And Correcting Memory Errors
 

Automatically Tolerating And Correcting Memory Errors

on

  • 3,273 views

Applications written in unsafe languages like C and C++ are vulnerable to memory errors such as buffer overflows, dangling pointers, and reads of uninitialized data. These errors, which lead to ...

Applications written in unsafe languages like C and C++ are vulnerable to memory errors such as buffer overflows, dangling pointers, and reads of uninitialized data. These errors, which lead to program crashes, security vulnerabilities, and unpredictable behavior, are both difficult to avoid and costly to repair.

This talk presents two systems that automatically harden unaltered C and C++ programs against heap-based memory errors. The first, DieHard, uses randomization and replication to make programs probabilistically resistant to a wide range of memory errors. Instead of crashing or running amok, DieHard lets programs run correctly in the face of memory errors with high probability. DieHard trades a modest increase in memory consumption (and optionally, the extra processing power of multicore CPUs) for dramatically increased reliability.

While DieHard tolerates errors, our second system, Exterminator, automatically isolates and corrects them. Exterminator exploits randomization to pinpoint errors with high precision. From this information, Exterminator generates patches that fix these errors in current and subsequent executions. In addition, Exterminator enables collaborative bug correction by merging patches generated by multiple users.

Statistics

Views

Total Views
3,273
Views on SlideShare
3,268
Embed Views
5

Actions

Likes
1
Downloads
71
Comments
0

3 Embeds 5

http://www.slideshare.net 3
http://wildfire.gigya.com 1
http://www.docshut.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Automatically Tolerating And Correcting Memory Errors Automatically Tolerating And Correcting Memory Errors Presentation Transcript

  • Automatically Tolerating & Correcting Memory Errors Emery Berger University of Massachusetts Amherst joint work with Gene Novark (UMass Amherst), Ben Zorn (Microsoft Research) [PLDI 2006, PLDI 2007] TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A A A A A A A
  • Problems with Unsafe Languages
    • C, C++: pervasive apps, but langs. memory unsafe
    • Numerous opportunities for security vulnerabilities, errors
      • Double free
      • Invalid free
      • Uninitialized reads
      • Dangling pointers
      • Buffer overflows (stack & heap )
  • Current Approaches
    • Unsound, may work or abort
      • Windows, GNU libc, etc., Rx [Zhou]
    • Unsound, will definitely continue
      • Failure oblivious [Rinard]
    • Sound, definitely aborts (fail-safe)
      • CCured [Necula] , CRED [Ruwase & Lam], SAFECode [Dhurjati, Kowshik & Adve], etc.
        • Slowdowns: 30% - 20X
        • Requires C source, programmer intervention
        • Garbage collection or partially sound (pools)
      • Good for debugging , less for deployment
  • Soundness for “Erroneous” Programs
    • Normally: memory errors  ?
    • Consider infinite-heap allocator:
      • All new s fresh ; ignore delete
        • No dangling pointers, invalid frees, double frees
      • Every object infinitely large
        • No buffer overflows, data overwrites
    • Transparent to correct program
    • “ Erroneous” programs sound
  • Probabilistic Memory Safety
    • Approximate  with M -heaps (e.g., M=2)
    • DieHard : fully-randomized M-heap
      • Increases odds of benign errors
      • Probabilistic memory safety
        • i.e., P(no error)  n
      • Errors independent across heaps
        • E(users with no error)  n * |users|
      • Efficient implementation…
  • Implementation Choices
    • Conventional, freelist-based heaps
      • Hard to randomize, protect from errors
        • Double frees, heap corruption
    • What about bitmaps? [Wilson90]
      • Catastrophic fragmentation
        • Each small object likely to occupy one page
    obj obj obj obj pages
  • Randomized Heap Layout
    • Bitmap-based, segregated size classes
      • Bit represents one object of given size
        • i.e., one bit = 2 i+3 bytes, etc.
      • Prevents fragmentation
    00000001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
  • Randomized Allocation
    • malloc(8) :
      • compute size class = ceil(log 2 sz) – 3
      • randomly probe bitmap for zero-bit (free)
    • Fast: runtime O(1)
      • M=2  E[# of probes] ≈ 2
    00000001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
    • malloc(8) :
      • compute size class = ceil(log 2 sz) – 3
      • randomly probe bitmap for zero-bit (free)
    • Fast: runtime O(1)
      • M=2  E[# of probes] ≈ 2
    Randomized Allocation 00010001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
    • free(ptr) :
      • Ensure object valid – aligned to right address
      • Ensure allocated – bit set
      • Resets bit
    • Prevents invalid frees, double frees
    Randomized Deallocation 00010001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
  • Randomized Deallocation
    • free(ptr) :
      • Ensure object valid – aligned to right address
      • Ensure allocated – bit set
      • Resets bit
    • Prevents invalid frees, double frees
    00010001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
    • free(ptr) :
      • Ensure object valid – aligned to right address
      • Ensure allocated – bit set
      • Resets bit
    • Prevents invalid frees, double frees
    Randomized Deallocation 000 0 0001 1010 10 size = 2 i+3 2 i+4 2 i+5 metadata heap
  • Randomized Heaps & Reliability
    • Objects randomly spread across heap
    • Different run = different heap
      • Improves security
      • Errors across heaps independent
    2 3 4 5 3 1 6 object size = 2 i+4 object size = 2 i+3 … My Mozilla: “malignant” overflow Your Mozilla: “benign” overflow 1 1 6 3 2 5 4 …
  • DieHard software architecture broadcast vote input output execute replicas (separate processes)
    • Optional: replication-based fault-tolerance
      • Requires randomization: errors independent
    replica 3 seed 3 replica 1 seed 1 replica 2 seed 2
  • DieHard Results
    • Analytical results (pictures!)
      • Dangling pointer errors
      • Buffer overflows
      • Uninitialized reads
    • Empirical results
      • Runtime overhead
      • Error avoidance
        • Injected faults & actual applications
  • Analytical Results: Dangling Pointers
    • Free one object too early
  • Analytical Results: Dangling Pointers
    • Free one object too early
    • Object extremely unlikely to be reused soon
  • Analytical Results: Dangling Pointers
    • Free one object too early
    • Object extremely unlikely to be reused soon
  • Analytical Results: Dangling Pointers
    • Free one object too early
    • Object extremely unlikely to be reused soon
      • Example : F = 1,000,000
        • P(ok after one malloc ) ¼ 1
        • P(ok after 1000 mallocs ) ¸ 99.9%
    F = # free objects A = # mallocs
  • Analytical Results: Buffer Overflows
    • Model overflow: random write of live data
      • Heap half full (max occupancy)
  • Analytical Results: Buffer Overflows
    • Model overflow: random write of live data
      • Heap half full (max occupancy)
  • Analytical Results: Buffer Overflows
    • Model overflow: random write of live data
      • Heap half full (max occupancy)
  • Analytical Results: Buffer Overflows
    • Replicas: Increase odds of avoiding overflow in at least one replica
    replicas
  • Analytical Results: Buffer Overflows
    • Replicas: Increase odds of avoiding overflow in at least one replica
    replicas
  • Analytical Results: Buffer Overflows
    • Replicas: Increase odds of avoiding overflow in at least one replica
    replicas
    • P(Overflow in all replicas) = (½) 3 = 1/8
    • P(No overflow in ≥ 1 replica) = 1-(½) 3 = 7/8
  • Analytical Results: Buffer Overflows
    • F = free space
    • H = heap size
    • N = # objects worth of overflow
    • k = replicas
    • Overflow one object
  • Empirical Results: Error Avoidance
    • Injected faults:
      • Dangling pointers ( @ 50%, 10 allocations)
        • glibc : crashes ; DieHard : 9/10 correct
      • Overflows (@1%, 4 bytes over) –
        • glibc : crashes 9/10, “inf loop” ; DieHard : 10/10 correct
    • Real faults:
      • Avoids Squid web cache overflow
        • Crashes BDW & glibc
      • Avoids dangling pointer error in Mozilla
        • DoS in glibc & Windows
  • DieHard Limitations
    • Fine for single error
      • But: multiple errors eventually swamp probabilistic protection
      • Not great for large overflows
    • Tolerates errors
      • But doesn’t find them
        • No information for programmer
    • Ideal: point directly to bug…
  • Exterminator: Automatically Correcting Memory Errors with High Probability
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
    char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
    char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
    bad object (too small) char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
    bad object (too small)  bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
    bad object (too small)  bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”);
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”); 1. Heap provides no useful information
  • Diagnosing Buffer Overflows
    • Canonical buffer overflow:
      • Allocate object – too small
      • Write past end ) nukes object  bytes forward
        • Not necessarily contiguous
     bytes past end char * str = new char[8]; strcpy (str, “goodbye cruel world”); 2. No way to detect corruption
  • Isolating Buffer Overflows
    • Canaries in freed space detect corruption
    8 2 9 3 4 5 1 7 Red = possible bad object Green = not bad object known random value dead canary = corruption # = object id (allocation time)
  • Isolating Buffer Overflows
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
    8 2 9 3 4 5 1 7 Red = possible bad object Green = not bad object
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
    Isolating Buffer Overflows Red = possible bad object Green = not bad object 1 8 7 5 3 2 9 6 4 8 2 9 3 4 5 1 7
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
      • Key insight: Overflow must be at same 
    Isolating Buffer Overflows Red = possible bad object Green = not bad object 1 8 7 5 3 2 9 6 4 8 2 9 3 4 5 1 7
  • Isolating Buffer Overflows
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
      • Key insight: Overflow must be at same 
    Red = possible bad object Green = not bad object 1 8 7 5 3 2 9 6 4 8 2 9 4 5 1 7 3
  • Isolating Buffer Overflows
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
      • Key insight: Overflow must be at same 
    Red = possible bad object Green = not bad object 1 8 7 5 3 2 9 6 4 8 2 9 3 4 5 1 7
  • Isolating Buffer Overflows
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
      • Key insight: Overflow must be at same 
    Red = possible bad object Green = not bad object 1 8 7 5 3 6 4 9 2 8 2 9 3 4 5 1 7
  • Isolating Buffer Overflows Red = possible bad object Green = not bad object 4 9 6 3 8 5 7 2 1
    • Canaries in freed space detect corruption
      • Run multiple times with “DieFast” allocator
      • Key insight: Overflow must be at same 
    • ) object 9 overflowed, with high probability
    8 2 9 3 4 5 1 7 1 8 7 5 3 2 9 6 4
  • Buffer Overflow Analysis
      • Example: H = 1,000,000 objects 3 iterations ¼ false positives
    • Iterations exponentially increase precision
    H = # heap objects K = # iterations 8 2 9 3 4 5 1 7 1 8 7 5 3 2 9 6 4 4 9 6 3 8 5 7 2 1
  • Isolating Dangling Pointers
    • Dangling pointer error:
      • Allocated object freed too soon
      • Overwritten by some other object
    int * v = new int[4]; … delete [] v; // oops … char * str = new char[16]; strcpy (str, “die, pointer”); v[3] = 12; … use of v[0]
  • Isolating Dangling Pointers
    • Unlike buffer overflow:
      • dangling pointer ) same corruption in all
      • k = 3 ) false negatives ¼
    11 2 3 6 4 5 10 1 12 7 9 8 1 7 5 3 2 11 12 6 4 8 9 10 4 6 3 12 5 7 2 1 4 10 8 9
  • Correcting Allocator
    • Generate runtime patches to correct errors
      • Track object call sites in allocator
    • Prevent overflows : pad overflowed objects malloc(8)  malloc(8 + δ )
    • Prevent dangling pointers : defer frees free(ptr)  delay δ mallocs; free(ptr)
    1  1
  • Exterminator Summary
    • Three main pieces:
      • DieHard-based allocator (DieFast)
        • Reveals bugs
      • Error isolator
        • Finds bugs across multiple heaps w.h.p.
      • Correcting allocator
        • Fixes bugs
    • Modes suitable for testing (debugging) or deployment
  • Exterminator Modes
    • Iterative
      • Run multiple times
      • Same inputs
      • Debugging
    • Replicated
      • Run simultaneously
      • Deployable w/limitations
      • Can fix errors on-the-fly
    • Cumulative
      • Different inputs, nondeterminism
      • Deployable; see paper for details
    seed vote output DieFast replica 1 seed DieFast replica 2 seed Error isolator correcting allocator correcting allocator correcting allocator DieFast replica 3 runtime patches broadcast input
  • Exterminator Runtime Overhead 25%
  • Empirical Results: Real Faults
    • Squid heap overflow
      • Crashes glibc 2.8.0 and BDW collector
      • 3 iterations to fix ) 6 byte pad
        • Prevents overflow for all subsequent executions
    • Mozilla 1.7.3 buffer overflow
      • Debug scenario:
        • repeated load of PoC: 23 runs to fix overflow
      • Deployed scenario :
        • different browsing sessions: 34 runs to fix
    Empirical Results: Real Faults 2 3 1 1 2
  • Conclusion
    • Randomization: enables probabilistic memory safety (DieHard) & automatic error correction (Exterminator)
    • Trades hardware resources (RAM,CPU) for reliability
      • Hardware trends
        • Larger memories, multi-core CPUs
      • Follows in footsteps of ECC memory, RAID
  • The End www.diehard-software.org www.cs.umass.edu/~emery
  • Actual DieHard Heap Layout
    • Bitmap-based, segregated size classes
      • Bit represents one object of given size
        • i.e., one bit = 2 i+3 bytes, etc.
    • malloc() : randomly probe bitmap for free space
    • free() : just reset bit
    4 3 6 5 2 1 8 16 allocation space bitmap 1 object size 2 inUse 4 inUse 1 inUse 6 inUse 1 inUse miniheaps