Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Context-aware Failure-oblivious Computing as a Means of Preventing Buffer Overflows

Context-aware Failure-oblivious Computing as a Means of Preventing Buffer Overflows

Talk held at the 12th International Conference on Network and System Security (NSS-2018) in Hong Kong, China

Manuel Rigger

August 29, 2018
Tweet

More Decks by Manuel Rigger

Other Decks in Research

Transcript

  1. Context-aware Failure-oblivious Computing as a Means of Preventing Buffer Overflows

    Manuel Rigger, Daniel Pekarek, Hanspeter Mössenböck Johannes Kepler University Linz, Austria Session 4A. Software Security. 29. August, NSS 2018, Hong Kong
  2. Problem: Buffer Overflows in C • Buffer overflows have disastrous

    consequences • Arbitrary-code execution • Denial-of-service 2 2011 CWE/SANS Top 25 Most Dangerous Software Errors (http://cwe.mitre.org/top25/) Ranking Error #1 SQL Injection #2 OS Command Injection #3 Classic Buffer Overflow
  3. Problem: Buffer Overflows in C 3 char buf[MAX]; ... strncpy(buf,

    src, MAX); int length = strlen(buf); ...
  4. Problem: Buffer Overflows in C 3 char buf[MAX]; ... strncpy(buf,

    src, MAX); int length = strlen(buf); ... What could go wrong?
  5. Problem: Buffer Overflows in C 7 N S S _

    2 0 1 8 \0 MAX > strlen(buf) char buf[MAX]; ... strncpy(buf, src, MAX); int length = strlen(buf); ...
  6. Problem: Buffer Overflows in C 7 N S S _

    2 0 1 8 \0 MAX > strlen(buf) MAX = 3 N S S char buf[MAX]; ... strncpy(buf, src, MAX); int length = strlen(buf); ...
  7. Problem: Buffer Overflows in C 7 N S S _

    2 0 1 8 \0 MAX > strlen(buf) MAX = 3 N S S char buf[MAX]; ... strncpy(buf, src, MAX); int length = strlen(buf); ... buf is no longer NULL-terminated!
  8. N S S Example: strlen() 8 size_t strlen(const char *str)

    { size_t len = 0; while (*str != '\0') { len++; str++; } return len; }
  9. N S S Example: strlen() 8 size_t strlen(const char *str)

    { size_t len = 0; while (*str != '\0') { len++; str++; } return len; }
  10. N S S Example: strlen() 8 size_t strlen(const char *str)

    { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } 3252
  11. Existing Work 10 LLVM’s AdddressSanitizer (Serebryany 2011) SoftBound (Nagarakatte 2009)

    Intel MPX’s based bounds instrumentation (Oleksenko 2018)
  12. N S S Example: LLVM’s AddressSanitizer 11 size_t strlen(const char

    *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; }
  13. N S S Example: LLVM’s AddressSanitizer 11 size_t strlen(const char

    *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; }
  14. N S S Example: LLVM’s AddressSanitizer 11 size_t strlen(const char

    *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } ==16497==ERROR: AddressSanitizer: stack-buffer- overflow on address 0x7ffc59c0ef63 READ of size 1 at 0x7ffc59c0ef63 thread T0 #0 0x4e7442 in strlen /home/manuel/test.c:10:12 #1 0x4e7392 in main /home/manuel/test.c:5:5
  15. Idea 13 Idea: Mitigate the error and continue execution while

    minimizing the chance of incorrect execution
  16. Idea 13 Idea: Mitigate the error and continue execution while

    minimizing the chance of incorrect execution Useful in a production environment!
  17. Contributions • Context-aware Failure-oblivious Computing • Implementation on top of

    three bug-finding tools • Evaluation • Effectiveness • Performance 14
  18. Failure-oblivious Computing 18 try { // write access } catch

    (ArrayIndexOutOfBoundsException e) { }
  19. Failure-oblivious Computing 18 try { // write access } catch

    (ArrayIndexOutOfBoundsException e) { } We execute C, not Java code
  20. Failure-oblivious Computing 19 try { // read access } catch

    (ArrayIndexOutOfBoundsException e) { return getPredefinedValue(); }
  21. Failure-oblivious Computing 19 try { // read access } catch

    (ArrayIndexOutOfBoundsException e) { return getPredefinedValue(); } What if the predefined value results in erroneous execution?
  22. Approach 20 Context-aware Failure-oblivious Computing Introspection (Rigger et al. 2018)

    Behavior depends on the semantics of the function in which the buffer overflow occurs
  23. Introspection 23 long size_right(void *); long size_left(void *); enum Location

    location(void *); void* try_cast(void *, struct Type*); int count_varargs(); void* get_vararg(int i, struct Type* type);
  24. Introspection 23 long size_right(void *); long size_left(void *); enum Location

    location(void *); void* try_cast(void *, struct Type*); int count_varargs(); void* get_vararg(int i, struct Type* type);
  25. Introspection for Bounds 24 int *arr = malloc(sizeof (int) *

    10) ; int *ptr = &(arr[4]); printf ("%ld\n", size_right(ptr)); // prints 24 _size_right() sizeof(int) * 10
  26. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

    return strnlen(str, size_right(str)); }
  27. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

    return strnlen(str, size_right(str)); } N S S
  28. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

    } N S S return strnlen(str, 3); size_t strnlen(const char *str, size_t maxlen) { const char *p = str; while (maxlen-- > 0 && *p != '\0') p++; return p - str; }
  29. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

    } N S S return strnlen(str, 3); size_t strnlen(const char *str, size_t maxlen) { const char *p = str; while (maxlen-- > 0 && *p != '\0') p++; return p - str; }
  30. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

    } N S S return strnlen(str, 3); size_t strnlen(const char *str, size_t maxlen) { const char *p = str; while (maxlen-- > 0 && *p != '\0') p++; return p - str; } 3
  31. 3. Interceptor for memcpy() 31 void *memcpy(void *dest, const void

    *src, size_t n) { ssize_t dstsz = _size_right(dest); size_t len = n; if (dstsz < len) { len = dstsz; } return memcpy(dest, src, len); }
  32. Implementation of size_right() 34 LLVM’s AdddressSanitizer (Serebryany 2011) SoftBound (Nagarakatte

    2009) Intel MPX’s based bounds instrumentation (Oleksenko 2018)
  33. GCC’s Intel MPX Bounds Checks Instrumentation 35 ssize_t size_right(void* p){

    ssize_t upper_bounds = (ssize_t)__builtin___bnd_get_ptr_ubound(p); size_t size = (size_t) (upper_bounds + 1) - (size_t) p; return (ssize_t) size; }
  34. SoftBound+CETS 36 ssize_t _size_right(const char* p) { const char* bound

    = __softboundcets_load_bound_shadow_stack(1); return bound - p; }
  35. LLVM’s AddressSanitizer 37 ASan’s metadata is not optimal for the

    introspection implementation N S S _size_right()
  36. CVE-2017-14493 (Dnsmasq) 44 state->mac_len = opt6_len(opt) - 2; memcpy(&state->mac[0], opt6_ptr(opt,

    2), state->mac_len); The server successfully handled subsequent requests after mitigation
  37. CVE-2017-9047 (Libxml2) 45 The parser printed a truncated error message,

    similar to the fixed version if (content->name != NULL) strcat(buf, (char *) content->name);
  38. CVE-2017-16352 (GraphicsMagick) 46 for (p=image->directory; *p != ’\0’; p++) {

    q=p; while ((*q != ’\n’) && (*q != ’\0’)) q++; (void) strncpy(image_info->filename,p,q-p); image_info->filename[q-p]=’\0’; }
  39. CVE-2017-16352 (GraphicsMagick) 46 The error was mitigated… for (p=image->directory; *p

    != ’\0’; p++) { q=p; while ((*q != ’\n’) && (*q != ’\0’)) q++; (void) strncpy(image_info->filename,p,q-p); image_info->filename[q-p]=’\0’; }
  40. CVE-2017-16352 (GraphicsMagick) 47 for (p=image->directory; *p != ’\0’; p++) {

    q=p; while ((*q != ’\n’) && (*q != ’\0’)) q++; (void) strncpy(image_info->filename,p,q-p); image_info->filename[q-p]=’\0’; }
  41. CVE-2017-16352 (GraphicsMagick) 47 … but the application code had a

    subsequent out-of-bounds access for (p=image->directory; *p != ’\0’; p++) { q=p; while ((*q != ’\n’) && (*q != ’\0’)) q++; (void) strncpy(image_info->filename,p,q-p); image_info->filename[q-p]=’\0’; }
  42. Effectiveness: Discussion • Prevents buffer overflows only in libc functions

    • Terminates execution if no interceptor mitigates the error • We do not want to risk incorrect execution! 48 Execution # CVEs Could continue 4 Terminated 1
  43. Performance: Discussion • Low overhead • Could be more efficient

    by directly implementing libc functions 53 size_t strlen(const char *str) { size_t len = 0; while ( size_right(str) > 0 && *str != '\0') { len++; str++; } return len; }