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

389c8e3d83119ec458c5c57e8d92da2a?s=128

Manuel Rigger

August 29, 2018
Tweet

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. Background: Strings in C 4 A valid C string ends

    with a \0 character
  6. Background: Strings in C 5 N S S _ 2

    0 1 8 \0
  7. Background: Strings in C 6 N S S _ 2

    0 1 8
  8. 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); ...
  9. 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); ...
  10. 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!
  11. N S S Example: strlen() 8 size_t strlen(const char *str)

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

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

    { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } 3252
  14. Existing Work 9 Most existing approaches instrument the program to

    detect errors and terminate execution
  15. Existing Work 10 LLVM’s AdddressSanitizer (Serebryany 2011) SoftBound (Nagarakatte 2009)

    Intel MPX’s based bounds instrumentation (Oleksenko 2018)
  16. 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; }
  17. 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; }
  18. 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
  19. Existing Work 12 What about systems with high-availability requirements?

  20. Idea 13 Idea: Mitigate the error and continue execution while

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

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

    three bug-finding tools • Evaluation • Effectiveness • Performance 14
  23. Approach 15

  24. Approach 16 Context-aware Failure-oblivious Computing

  25. Approach 16 Context-aware Failure-oblivious Computing Failure-oblivious Computing (Rinard et al.

    2004)
  26. Failure-oblivious Computing 17 Idea: detect buffer overflows, but continue execution

  27. Failure-oblivious Computing 18 try { // write access } catch

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

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

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

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

  32. 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
  33. Introspection 21 Idea: provide object meta-data to the programmer, tracked

    by existing bug-finding tools
  34. Introspection 22 Uses introspection function Instruments program

  35. 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);
  36. 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);
  37. 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
  38. Approach 25 Context-aware Failure-oblivious Computing Failure-oblivious Computing (Rinard et al.

    2004) Introspection (Rigger et al. 2018)
  39. Context-aware Failure-oblivious Computing 26 Idea: Implement a Failure-oblivious Computing logic

    for common library functions by using introspection
  40. Context-aware Failure-oblivious Computing 27 strlen() strnlen() _size_right() instruments

  41. Context-aware Failure-oblivious Computing 28 strlen() strnlen() _size_right() instruments

  42. 1. Interceptor for strlen() 29 size_t strlen(const char *str) {

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

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

    } N S S return strnlen(str, 3);
  45. 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; }
  46. 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; }
  47. 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
  48. 2. Interceptor for gets() 30 char *gets(char *s) { return

    fgets(s, _size_right(s), stdin); }
  49. 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); }
  50. Implementation in Tools 32

  51. Context-aware Failure-oblivious Computing 33 strlen() strnlen() _size_right() instruments

  52. Implementation of size_right() 34 LLVM’s AdddressSanitizer (Serebryany 2011) SoftBound (Nagarakatte

    2009) Intel MPX’s based bounds instrumentation (Oleksenko 2018)
  53. 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; }
  54. SoftBound+CETS 36 ssize_t _size_right(const char* p) { const char* bound

    = __softboundcets_load_bound_shadow_stack(1); return bound - p; }
  55. LLVM’s AddressSanitizer 37 N S S

  56. LLVM’s AddressSanitizer 37 N S S

  57. LLVM’s AddressSanitizer 37 N S S _size_right()

  58. LLVM’s AddressSanitizer 37 ASan’s metadata is not optimal for the

    introspection implementation N S S _size_right()
  59. Evaluation 38

  60. 39 Effectiveness Performance

  61. 40 Effectiveness

  62. Effectiveness 41 Can the introspection interceptors be used to defend

    against buffer overflows in practice?
  63. Effectiveness 42 Dnsmasq CVE-2017-14493 CVE-2017-14496 CVE-2017-9047 Libxml2 CVE-2017-16352 LightFTP CVE-2017-1000218

  64. Effectiveness 43 Dnsmasq CVE-2017-14493 CVE-2017-14496 CVE-2017-9047 Libxml2 CVE-2017-16352 LightFTP CVE-2017-1000218

  65. CVE-2017-14493 (Dnsmasq) 44 state->mac_len = opt6_len(opt) - 2; memcpy(&state->mac[0], opt6_ptr(opt,

    2), state->mac_len);
  66. 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
  67. CVE-2017-9047 (Libxml2) 45 if (content->name != NULL) strcat(buf, (char *)

    content->name);
  68. 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);
  69. 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’; }
  70. 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’; }
  71. 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’; }
  72. 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’; }
  73. 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
  74. 49 Performance

  75. Performance 50 What is the overhead of the introspection interceptors?

  76. Performance • Benchmarks • Network-intensive (servers) • Computation-intensive (SPEC INT)

    51
  77. Performance 52 Approach Network-bound CPU-bound MPX ~1% Up to 13%

    ASan ~1% Up to 140% SoftBound+CETS ? 3%?
  78. 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; }
  79. 54 Context-aware Failure-oblivious Computing @RiggerManuel https://github.com/introspection-libc

  80. 54 Context-aware Failure-oblivious Computing @RiggerManuel https://github.com/introspection-libc

  81. 54 Context-aware Failure-oblivious Computing @RiggerManuel https://github.com/introspection-libc

  82. 54 Context-aware Failure-oblivious Computing @RiggerManuel https://github.com/introspection-libc

  83. 54 Context-aware Failure-oblivious Computing @RiggerManuel https://github.com/introspection-libc