Slide 1

Slide 1 text

Introspection for C and its Applications to Library Robustness Manuel Rigger1, René Mayrhofer1, Roland Schatz2, Matthias Grimmer2, Hanspeter Mössenböck1 1 Johannes Kepler University Linz, Austria 2 Oracle Labs Linz, Austria 2018, 12 April 2018, Nice, France.

Slide 2

Slide 2 text

Problem: Errors in C 2 • Problem 1: C lacks automatic checks • Errors can be exploited by attackers or cause hard-to-find-bugs • Problem 2: C objects lack type information • No defensive programming

Slide 3

Slide 3 text

Problem: Errors in C • No bounds checks • No bounds information 3 int *arr = malloc(3 * sizeof(int)); arr[5] = … Buffer Overflows

Slide 4

Slide 4 text

Problem: Errors in C 4 free(stackobject); Invalid free error free(heapobject); free(heapobject); Double-free error free(heapobject); heapobject[0] = val; Use-after-free error free(heapobject); Memory leak Memory Management Errors • No automatic memory management • No location/liveness information

Slide 5

Slide 5 text

Problem: Errors in C 5 Type Confusion void apply(long* arr, size_t n, long f(long arg1)); • No type safety • No type information

Slide 6

Slide 6 text

Problem: Errors in C 5 Type Confusion void apply(long* arr, size_t n, long f(long arg1)); int f(int arg1) • No type safety • No type information

Slide 7

Slide 7 text

Problem: Errors in C 6 Format String Vulnerabilities printf("%d %d %s" , 3, 5); Missing argument printf("%s", 3); Type Confusion • No checks for accessing variadic arguments • No information for number and types of variadic arguments

Slide 8

Slide 8 text

Problem: Errors in C • Problem 1: C lacks automatic checks • Errors can be exploited by attackers or cause hard-to-find-bugs • Problem 2: C objects lack type information • No defensive programming 7 Addressed by state-of-the-art tools

Slide 9

Slide 9 text

State-of-the-art Run-time Approaches 8 int *arr = malloc(3 * sizeof(int)); arr[5] = … Detected buffer overflow  exiting program

Slide 10

Slide 10 text

State-of-the-art Run-time Approaches • LLVM’s sanitizers • Valgrind, Dr. Memory • Libcrunch • SoftBound+CETS • Safe Sulong 9

Slide 11

Slide 11 text

State-of-the-art Run-time Approaches • LLVM’s sanitizers • Valgrind, Dr. Memory • Libcrunch • SoftBound+CETS • Safe Sulong 9 These systems track object metadata to implement checks

Slide 12

Slide 12 text

Problem: Errors in C • Problem 1: C lacks automatic checks • Errors can be exploited by attackers or cause hard-to-find-bugs • Problem 2: C objects lack type information • No defensive programming 10 Unaddressed

Slide 13

Slide 13 text

Goal 11 Expose metadata through an introspection interface so that programmers can enhance the robustness of their libraries

Slide 14

Slide 14 text

Motivation 12 Goals Log error and continue Return error code Add assertions

Slide 15

Slide 15 text

Motivation 12 Goals Log error and continue Return error code Add assertions Programmers could “override” the default behavior of aborting the program

Slide 16

Slide 16 text

Structure 13 Ongoing work Implementation in tools Case study on libc Introspection interface

Slide 17

Slide 17 text

Introspection interface 14

Slide 18

Slide 18 text

Introspection Functions 15 Intro- spection Object bounds Memory location Types Variadic arguments

Slide 19

Slide 19 text

Bounds 16 long size_right(void *); long size_left(void *);

Slide 20

Slide 20 text

Bounds 17 int *arr = malloc(sizeof (int) * 10) ; int *ptr = &(arr[4]); printf ("%ld\n", size_left(ptr)); // prints 16 _size_left() sizeof(int) * 10

Slide 21

Slide 21 text

Bounds 18 int *arr = malloc(sizeof (int) * 10) ; int *ptr = &(arr[4]); printf ("%ld\n", size_left(ptr)); // prints 16 printf ("%ld\n", size_right(ptr)); // prints 24 _size_right() sizeof(int) * 10

Slide 22

Slide 22 text

Memory Location 19 enum Location location(void *); enum Location { INVALID, AUTOMATIC, DYNAMIC, STATIC };

Slide 23

Slide 23 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); }

Slide 24

Slide 24 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); } location(&a)  STATIC

Slide 25

Slide 25 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); } location(&b)  STATIC

Slide 26

Slide 26 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); } location(&c)  AUTOMATIC

Slide 27

Slide 27 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); } location(d)  DYNAMIC

Slide 28

Slide 28 text

Memory Location 20 int a; void func() { static int b; int c; int *d = malloc(sizeof(int) * 10); free(d); } location(d)  INVALID

Slide 29

Slide 29 text

Type Information 21 void* try_cast(void *, struct Type*);

Slide 30

Slide 30 text

Type Information 21 void* try_cast(void *, struct Type*); Return the pointer or NULL similar to dynamic_cast in C++

Slide 31

Slide 31 text

Type Information 22 void* try_cast(void *, struct Type*);

Slide 32

Slide 32 text

Type Information 22 void* try_cast(void *, struct Type*); Check if an object is "compatible" with a type

Slide 33

Slide 33 text

Type Information 23 int arr[10]; int *ptr = &(arr[9]); int val; val = try_cast(&ptr, type(val));

Slide 34

Slide 34 text

Variadic Arguments 24 int count_varargs(); void* get_vararg(int i, struct Type* type);

Slide 35

Slide 35 text

Variadic Arguments 25 int printf(const char * format, ... ) { if (count_varargs() != 3) { abort(); } int int1 = *get_vararg(0, type(int1)); int int2 = *get_vararg(1, type(&int2)); char* str = *get_vararg(2, type(&str)); } "%d %d %s"

Slide 36

Slide 36 text

Case Study on Libc 26

Slide 37

Slide 37 text

Introspection Goals 27 Goals Improve availability of the system Fix incomplete APIs Improve bug-finding capabilities

Slide 38

Slide 38 text

Introspection to Increase Availability • Continue execution after mitigating an error • E.g., make libc robust against not NUL-terminated strings 28 size_t strlen(const char *str); char *strcpy(char *dest, const char *src); …

Slide 39

Slide 39 text

Example: strlen() 29 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; }

Slide 40

Slide 40 text

Example: strlen() 29 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } P r o g r a m m i n g \0 ... ...

Slide 41

Slide 41 text

Example: strlen() 29 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } P r o g r a m m i n g \0 ... ...

Slide 42

Slide 42 text

Example: strlen() 29 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } 11 P r o g r a m m i n g \0 ... ...

Slide 43

Slide 43 text

Example: strlen() 30 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } P r o g r a m m i n g ... ...

Slide 44

Slide 44 text

Example: strlen() 30 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } P r o g r a m m i n g ... ...

Slide 45

Slide 45 text

Example: strlen() 30 size_t strlen(const char *str) { size_t len = 0; while (*str != '\0') { len++; str++; } return len; } 23415 P r o g r a m m i n g ... ...

Slide 46

Slide 46 text

size_t strlen(const char *str) { size_t len = 0; while ( size_right(str) > 0 && *str != '\0') { len++; str++; } return len; } Example: strlen() 31 P r o g r a m m i n g ... ...

Slide 47

Slide 47 text

size_t strlen(const char *str) { size_t len = 0; while ( size_right(str) > 0 && *str != '\0') { len++; str++; } return len; } Example: strlen() 31 P r o g r a m m i n g ... ...

Slide 48

Slide 48 text

size_t strlen(const char *str) { size_t len = 0; while ( size_right(str) > 0 && *str != '\0') { len++; str++; } return len; } Example: strlen() 31 11 P r o g r a m m i n g ... ...

Slide 49

Slide 49 text

Introspection to Improve Bug-Finding • Check invariants • Abort when detecting inconsistencies • E.g., allow libc’s “safe” functions to detect incorrect buffer sizes 32 size_t strnlen_s(const char *str, size_t maxlen); errno_t strcpy_s(char *dest, rsize_t maxdestsz, const char *src);

Slide 50

Slide 50 text

Improve bug-finding capabilities 33 size_t strnlen_s(char *str, rsize_t maxsize) { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; }

Slide 51

Slide 51 text

Improve bug-finding capabilities 33 size_t strnlen_s(char *str, rsize_t maxsize) { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } P r o g r a m m i n g \0 ... ... 100

Slide 52

Slide 52 text

Improve bug-finding capabilities 33 size_t strnlen_s(char *str, rsize_t maxsize) { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } P r o g r a m m i n g \0 ... ... 100 11

Slide 53

Slide 53 text

Improve bug-finding capabilities 33 size_t strnlen_s(char *str, rsize_t maxsize) { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } P r o g r a m m i n g \0 ... ... 100 11 Correct result but did not detect incorrect buffer size

Slide 54

Slide 54 text

Improve bug-finding capabilities 34 size_t strnlen_s(char *str, rsize_t maxsize) { if ( size_right(str) < maxsize) { abort(); } else { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } }

Slide 55

Slide 55 text

Improve bug-finding capabilities 34 size_t strnlen_s(char *str, rsize_t maxsize) { if ( size_right(str) < maxsize) { abort(); } else { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } } P r o g r a m m i n g \0 ... ... 100

Slide 56

Slide 56 text

Improve bug-finding capabilities 34 size_t strnlen_s(char *str, rsize_t maxsize) { if ( size_right(str) < maxsize) { abort(); } else { size_t i = 0; for (; i < maxsize && s[i] != '\0'; i++); return i; } } P r o g r a m m i n g \0 ... ... 100 Abort

Slide 57

Slide 57 text

Introspection to Fix Errors in API Design 35 char *gets(char *str);

Slide 58

Slide 58 text

Introspection to Fix Errors in API Design 35 char *gets(char *str); ... ...

Slide 59

Slide 59 text

Introspection to Fix Errors in API Design 35 char *gets(char *str); ... ...

Slide 60

Slide 60 text

Introspection to Fix Errors in API Design 36 char* gets(char *str) { int size = size_right(str); return gets_s(str, size); }

Slide 61

Slide 61 text

Introspection to Fix Errors in API Design 36 Make gets() robust against input that would overflow the buffer char* gets(char *str) { int size = size_right(str); return gets_s(str, size); }

Slide 62

Slide 62 text

Other examples 37 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));

Slide 63

Slide 63 text

Other examples 37 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*compar)(const void *, const void *)); Verify the function pointer

Slide 64

Slide 64 text

Other examples 38 int printf(const char *format, ...); int sprintf(char *str, const char *format, ...); int fprintf(FILE *stream, const char *format, ...);

Slide 65

Slide 65 text

Other examples 38 int printf(const char *format, ...); int sprintf(char *str, const char *format, ...); int fprintf(FILE *stream, const char *format, ...); Verify the number and types of variadic arguments

Slide 66

Slide 66 text

Other examples 39 void *realloc(void *ptr, size_t new_size); void free(void *ptr);

Slide 67

Slide 67 text

Other examples 39 void *realloc(void *ptr, size_t new_size); void free(void *ptr); Verify that the object was dynamically allocated

Slide 68

Slide 68 text

Implementation in Tools 40

Slide 69

Slide 69 text

Implementation in Safe Sulong 41 JVM C C++ Fortran ... Execute on

Slide 70

Slide 70 text

Implementation in Safe Sulong 41 JVM C C++ Fortran ... Execute on Safe Sulong tracks all necessary metadata

Slide 71

Slide 71 text

Implementation in Safe Sulong 42 int *arr = malloc(3 * sizeof(int)); int *ptr = &arr[1];

Slide 72

Slide 72 text

Implementation in Safe Sulong 42 int *arr = malloc(3 * sizeof(int)); int *ptr = &arr[1]; ptr: Address offset=4 data I32Array contents {0, 0, 0} location=AUTOMATIC location=DYNAMIC

Slide 73

Slide 73 text

Implementation in Safe Sulong 42 int *arr = malloc(3 * sizeof(int)); int *ptr = &arr[1]; ptr: Address offset=4 data I32Array contents {0, 0, 0} location=AUTOMATIC location=DYNAMIC size_right(ptr)  data.contents.length * sizeof(int) – offset  3 * 4 – 4 = 8

Slide 74

Slide 74 text

Implementation in Safe Sulong 43 int *arr = malloc(3 * sizeof(int)); int *ptr = &arr[1]; ptr: Address offset=4 data I32Array contents {0, 0, 0} location=AUTOMATIC location=DYNAMIC location(ptr)  DYNAMIC

Slide 75

Slide 75 text

Implementation in Safe Sulong 44 int *arr = malloc(3 * sizeof(int)); int *ptr = &arr[1]; ptr: Address offset=4 data I32Array contents {0, 0, 0} location=AUTOMATIC location=DYNAMIC try_cast(ptr, type(*ptr))  ptr

Slide 76

Slide 76 text

Ongoing Work 45 • Implementation in other tools • Case Study on real-world bugs

Slide 77

Slide 77 text

Ongoing work: LLVM’s AddressSanitizer 46 ... ... • LLVM’s AddressSanitizer: memory error detector based on shadow memory size_right()

Slide 78

Slide 78 text

Ongoing work: LLVM’s AddressSanitizer 46 ... ... • LLVM’s AddressSanitizer: memory error detector based on shadow memory size_right()

Slide 79

Slide 79 text

Ongoing work: GCC’s Intel MPX Bounds Checks Instrumentation • Intel MPX: bounds registers and instructions • GCC uses them to detect memory errors 47

Slide 80

Slide 80 text

Ongoing work: GCC’s Intel MPX Bounds Checks Instrumentation • Intel MPX: bounds registers and instructions • GCC uses them to detect memory errors 47 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; }

Slide 81

Slide 81 text

Ongoing work: SoftBound • SoftBound: bounds checker • Tracks upper bounds for each pointer 48 ssize_t _size_right(const char* p) { const char* bound = __softboundcets_load_bound_shadow_stack(1); return bound - p; }

Slide 82

Slide 82 text

Ongoing work: Real-world bugs • Case study on bugs contained in the CVE database • Libc goal: Availability 49 https://cve.mitre.org/

Slide 83

Slide 83 text

CVE-2017-14493 • Dnsmasq: DHCP server • Incorrect size argument to memcpy() caused buffer overflow 50 state->mac_len = opt6_len(opt) - 2; memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);

Slide 84

Slide 84 text

CVE-2017-14493 • Dnsmasq: DHCP server • Incorrect size argument to memcpy() caused buffer overflow 50 state->mac_len = opt6_len(opt) - 2; memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len); The server stayed fully functional after mitigation

Slide 85

Slide 85 text

CVE-2017-9047 • Libxml2: XML parsing library • String concatenating caused a buffer overflow 51 if (content->name != NULL) strcat(buf, (char *) content->name);

Slide 86

Slide 86 text

CVE-2017-9047 • Libxml2: XML parsing library • String concatenating caused a buffer overflow 51 The parser printed a truncated error message if (content->name != NULL) strcat(buf, (char *) content->name);

Slide 87

Slide 87 text

CVE-2017-16352 • GraphicsMagick: image processing library • Incorrect size argument to strncpy() 52 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’; }

Slide 88

Slide 88 text

CVE-2017-16352 • GraphicsMagick: image processing library • Incorrect size argument to strncpy() 52 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’; }

Slide 89

Slide 89 text

53 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’; }

Slide 90

Slide 90 text

CVE-2017-16352 • GraphicsMagick: image processing library • Incorrect size argument to strncpy() 54 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’; }

Slide 91

Slide 91 text

CVE-2017-16352 • GraphicsMagick: image processing library • Incorrect size argument to strncpy() 54 … 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’; }

Slide 92

Slide 92 text

Discussion and Conclusion 55

Slide 93

Slide 93 text

Discussion • Introspection as a complement to automatic checks 56 P r o g r a m m i n g ... ...

Slide 94

Slide 94 text

Discussion • Introspection as a complement to automatic checks 56 size_t strlen(const char *str) P r o g r a m m i n g ... ... 11

Slide 95

Slide 95 text

Discussion • Introspection as a complement to automatic checks 56 size_t strlen(const char *str) P r o g r a m m i n g ... ... size_t my_strlen(const char *str) 11 abort

Slide 96

Slide 96 text

Discussion • Introspection as a complement to automatic checks 56 size_t strlen(const char *str) P r o g r a m m i n g ... ... size_t my_strlen(const char *str) 11 abort Automatic checks still abort if the error is not mitigated

Slide 97

Slide 97 text

Discussion • Introspection as a complement to automatic checks • What about partial/no support of introspection? 57

Slide 98

Slide 98 text

Discussion • Introspection as a complement to automatic checks • What about partial/no support of introspection? 57 size_right(ptr); LONG_MAX

Slide 99

Slide 99 text

Discussion • Introspection as a complement to automatic checks • What about partial/no support of introspection? 57 size_right(ptr); LONG_MAX Sensible default values and conservative checks?

Slide 100

Slide 100 text

Discussion • Introspection as a complement to automatic checks • What about partial/no support of introspection? • Safer languages 58 Legacy software

Slide 101

Slide 101 text

Discussion • Introspection as a complement to automatic checks • What about partial/no support of introspection? • Safer languages • Programming effort 59 Introspection checks only useful for frequently used libraries

Slide 102

Slide 102 text

Conclusion 60 @RiggerManuel