confidence 2014: andreas bogk: preventing violation of memory safety in c/c++ software

Post on 09-May-2015

221 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

The hacker community has a lot of words for situations in which access to the wrong part of memory leads to an exploitable vulnerability: buffer overflow, integer overflows, stack smashing, heap overflow, use-after-free, double free and so on. Different words are used because the techniques to trigger the faulty memory access and to subsequently use that to gain code execution vary, but they all share a common root cause: violation of spatial and temporal memory safety. If one looks at the C/C++ standard, the situations that tend to be exploitable are “unspecified”. Usually, compiler writers take that as an excuse to cut corners, to gain that extra bit of performance in the benchmarks. Because, you know, who cares you’re exploitable when you make a mistake, look how fast it is! However, the standards also allow the compiler to introduce safety checks, to see whether access to a pointer actually touches the inside of an allocated object instead of the outside (spatial memory safety), and to make sure that the pointer being accessed actually points to an object that has been allocated, but not yet been freed again (temporal memory safety). Such compilers do exist, in the form of LLVM with specialized optimizer passes that introduce runtime safety checks. This talk will look into the details of the implementation, the performance impact, practical handling, and of course, whether it really delivers the promised 100% protection against buffer overflows.

TRANSCRIPT

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Applying science to eliminate 100% of buffer overflows

CONFidence, Krakow, 2014Andreas Bogk, andreas.bogk@here.com, @andreasdotorg

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

The problem

void foo (char* arg) {

  char some[16];

  char* p = some;

  while (*p++ = *arg++);

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

The problem: spatial memory safety

void foo (char* arg) {

  char some[16];

  char* p = some;

  while (*p++ = *arg++);

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

The other problem

void bar (char* arg) {

  char* p = malloc(16);

  free(p);

  while (*p++ = *arg++);

  free(p);

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

The other problem:temporal memory safety

void bar (char* arg) {

  char* p = malloc(16);

  free(p);

  while (*p++ = *arg++);

  free(p);

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Existing approaches

● Use a safe language!

● Mitigations: ASLR, DEP, stack canaries

● Memory debugging tools:

– Valgrind

– gcc and llvm memory sanitizer

– SAFEcode

– Ccured

– SafeC

– Cyclone

– Etc...

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

A word on notation

red.is­>compiler_generated(code);

black.is­>user_written(code);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Object-based approach

if (IsPoisoned(address)) {

  ReportError(address);

}

*address = ...;  // or: ... = *address;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Intrastructural safety

struct {

  char id[8];

  int account_balance;

} bank_account;

char* ptr = &(bank_account.id);

strcpy(ptr, "overflow...");

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Pointer-based approach

● Every pointer represented by three words: pointer value, base, bound

● We call that a „fat pointer“

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Meet SoftBoundCETS

● Santosh Nagarakatte, Jianzhou Zhao, Milo M. K. Martin, Steve Zdancewic; UPenn

● SoftBound: spatial safety

● CETS: temporal safety

● Uses disjoint fat pointers

● Proof of correctness (but caveat emptor)

● Implemented as LLVM optimizer pass

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Meet SoftBoundCETS

● Source compatibility

● Complete coverage

● Separate compilation

● Low overhead

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: instrumenting dereference

check(ptr, ptr_base, ptr_bound,

      sizeof(*ptr));

value = *ptr;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: implementation of check

void check(ptr, base, bound, size) {

  if ((ptr < base) 

      || (ptr + size > bound)) {

    abort();

  }

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

„Beware of bugs in the above code; I have only proved it correct, not tried it.“

– Donald E. Knuth

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: correct implementation of check

void check(ptr, base, bound, size) {

  if ((ptr < base) 

      || (ptr + size > bound)

      || (ptr + size < ptr)) {

    abort();

  }

}

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: memory allocation

ptr = malloc(size);

ptr_base = ptr;

ptr_bound = ptr + size;

if (ptr == NULL) ptr_bound = NULL;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: stack allocation

int array[100];

ptr = &array;

ptr_base = &array[0];

ptr_bound = ptr_base +

              sizeof(array);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: Pointer arithmetic

newptr = ptr + index;

// or &ptr[index]

newptr_base = ptr_base;

newptr_bound = ptr_bound;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: narrowing

struct { ... int num; ... } *n;

...

p = &(n­>num);

p_base = max(&(n­>num), n_base);

p_bound = min(p_base + sizeof(n­>num),

              n_bound);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: more narrowing

struct { ... int arr[5]; ... } *n;

...

p = &(n­>arr[2]);

p_base = max(&(n­>arr), n_base);

p_bound = min(p_base + sizeof(n­>arr), 

              n_bound);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: loading metadata

int** ptr;

int* new_ptr;

...

check(ptr, ptr_base, ptr_bound,sizeof(*ptr));

newptr = *ptr;

newptr_base = table_lookup(ptr)­>base;

newptr_bound = table_lookup(ptr)­>bound;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: storing metadata

int** ptr;

int* new_ptr;

...

check(ptr, ptr_base, ptr_bound, sizeof(*ptr));

(*ptr) = new_ptr;

table_lookup(ptr)­>base = newptr_base;

table_lookup(ptr)­>bound = newptr_bound;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: augmenting function calls

int func(char* s)

{ ... }

int value = func(ptr);

int func(char* s,void* s_base,void* s_bound)

{ ... }

int value = func(ptr, ptr_base, ptr_bound);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Spatial: loose ends

● Global variables

● Separate compilation and library code

● Memcpy()

● Function pointers

● Creating pointers from integers

● Arbitrary casts and unions

● Variable argument functions

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: allocation

ptr = malloc(size);

ptr_key = next_key++;

ptr_lock_addr = allocate_lock();

*(ptr_lock_addr) = ptr_key;

freeable_ptrs_map.insert(ptr_key, ptr);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: free

if (freeable_ptrs_map.lookup(ptr_key) != ptr) {

  abort();

}

freeable_ptrs_map.remove(ptr_key);

free(ptr);

*(ptr_lock_addr) = INVALID_KEY;

deallocate_lock(ptr_lock_addr);

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: dereference check

if (ptr_key != *ptr_lock_addr) { abort(); }

value = *ptr;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: pointer arithmetic

newptr = ptr + offset; 

// or &ptr[index]

newptr_key = ptr_key;

newptr_lock_addr = ptr_lock_addr;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: propagating metadata

int** ptr;

int* newptr;

if (ptr_key != *ptr_lock_addr) { abort(); }

newptr = *ptr;

newptr_key = table_lookup(ptr)­>key;

newptr_lock_addr = table_lookup(ptr)­>lock_addr;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: propagating metadata

int** ptr;

int* newptr;

if (ptr_key != *ptr_lock_addr) { abort(); }

(*ptr) = newptr;

table_lookup(ptr)­>key = newptr_key;

table_lookup(ptr)­>lock_addr = newptr_lock_addr;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: globals

int var; // global variable

ptr = &var;

ptr_key = GLOBAL_KEY;

ptr_lock_addr = GLOBAL_LOCK_ADDR;

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Temporal: loose ends

● Threads. Shared state is evil. Zalgo, etc.

● Shared memory. Shared state... see above.

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Own contribution

● Introduced two function attributes to control instrumentation process

● Ported SoftBoundCETS to FreeBSD

● Instrumented FreeBSD libc and executable startup code

● Deleted ton of now useless wrappers

● Goal: build all of FreeBSD world with safe memory access

● Status: PoC works!

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Demo Time!

● Everybody loves a good demo!

● Sufficiently advanced technology is indistinguishable from a properly rigged fake.

TOP SECRET//HCS/SI/TK//ORCON/NOFORN

Thanks and references

● SoftBoundCETS: http://www.cs.rutgers.edu/~santosh.nagarakatte/softbound/

● SoftBoundCETS on FreeBSD: https://github.com/andreas23/freebsd/tree/softbounds

● Many thanks to Hannes Mehnert for joint work on FreeBSD port

● Many thanks to Santosh Nagarakatte, Milo M. K. Martin, Steve Zdancewic for answering questions and providing access to beta versions of code

top related