0% found this document useful (0 votes)
13 views

Programming-split

The document discusses the inherent errors in the C programming language, including lack of automatic checks, type information, and memory management, which can lead to vulnerabilities like buffer overflows and type confusion. It proposes an introspection interface to expose metadata that can help programmers enhance library robustness and improve error handling. The document also outlines state-of-the-art tools and techniques that can be applied to mitigate these issues.

Uploaded by

prakashv0841
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

Programming-split

The document discusses the inherent errors in the C programming language, including lack of automatic checks, type information, and memory management, which can lead to vulnerabilities like buffer overflows and type confusion. It proposes an introspection interface to expose metadata that can help programmers enhance library robustness and improve error handling. The document also outlines state-of-the-art tools and techniques that can be applied to mitigate these issues.

Uploaded by

prakashv0841
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 102

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
<Programming> 2018,
12 April 2018, Nice, France.
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

2
Problem: Errors in C
Buffer Overflows

int *arr = malloc(3 * sizeof(int));


arr[5] = …

• No bounds checks
• No bounds information

3
Problem: Errors in C
Memory Management Errors
Invalid free error Double-free error
Use-after-free error free(stackobject); free(heapobject);
free(heapobject); free(heapobject);
heapobject[0] = val; Memory leak
free(heapobject);

• No automatic memory management


• No location/liveness information

4
Problem: Errors in C
Type Confusion

void apply(long* arr, size_t n, long f(long arg1));

• No type safety
• No type information

5
Problem: Errors in C
Type Confusion int f(int arg1)

void apply(long* arr, size_t n, long f(long arg1));

• No type safety
• No type information

5
Problem: Errors in C
Format String Vulnerabilities
Type Confusion
printf("%s", 3);
Missing argument
printf("%d %d %s" , 3, 5);

• No checks for accessing variadic arguments


• No information for number and types of variadic arguments

6
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

Addressed by state-of-the-art tools

7
State-of-the-art Run-time Approaches

int *arr = malloc(3 * sizeof(int));


arr[5] = …

Detected buffer overflow


 exiting program

8
State-of-the-art Run-time Approaches

• LLVM’s sanitizers
• Valgrind, Dr. Memory
• Libcrunch
• SoftBound+CETS
• Safe Sulong

9
State-of-the-art Run-time Approaches

• LLVM’s sanitizers
• Valgrind, Dr. Memory
• Libcrunch These systems track object
• SoftBound+CETS metadata to implement checks
• Safe Sulong

9
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

Unaddressed

10
Goal

Expose metadata through an introspection


interface so that programmers can enhance
the robustness of their libraries

11
Motivation
Log error
and
continue

Goals

Return
Add
error
assertions
code

12
Motivation
Log error
and
continue

Programmers could “override”


the default behavior of
aborting the program
Goals

Return
Add
error
assertions
code

12
Structure

Introspection interface

Case study on libc

Implementation in tools

Ongoing work
13
Introspection interface

14
Introspection Functions
Object
bounds

Variadic Intro- Memory


arguments spection location

Types

15
Bounds

long size_right(void *);


long size_left(void *);

16
Bounds

int *arr = malloc(sizeof (int) * 10) ;


int *ptr = &(arr[4]);
printf ("%ld\n", size_left(ptr)); // prints 16

sizeof(int) * 10

_size_left()

17
Bounds

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

sizeof(int) * 10

_size_right()

18
Memory Location

enum Location location(void *);

enum Location {
INVALID,
AUTOMATIC,
DYNAMIC,
STATIC
};

19
Memory Location

int a;

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

20
Memory Location

int a; location(&a)  STATIC

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

20
Memory Location

int a;

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

20
Memory Location

int a;

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

20
Memory Location

int a;

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

20
Memory Location

int a;

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

20
Type Information

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

21
Type Information

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

Return the pointer or NULL


similar to dynamic_cast in C++

21
Type Information

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

22
Type Information

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

Check if an object is
"compatible" with a type

22
Type Information

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

23
Variadic Arguments

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

24
Variadic Arguments
"%d %d %s"

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));
}

25
Case Study on Libc

26
Introspection Goals
Improve
availability
of the
system

Goals

Improve Fix
bug-finding incomplete
capabilities APIs

27
Introspection to Increase Availability

• Continue execution after mitigating an error


• E.g., make libc robust against not NUL-terminated strings

size_t strlen(const char *str);


char *strcpy(char *dest, const char *src);

28
Example: strlen()

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}

29
Example: strlen()
... P r o g r a m m i n g \0 ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}

29
Example: strlen()
... P r o g r a m m i n g \0 ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}

29
Example: strlen()
... P r o g r a m m i n g \0 ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len; 11
}

29
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}

30
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}

30
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while (*str != '\0') {
len++;
str++;
}
return len; 23415
}

30
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while ( size_right(str) > 0 && *str != '\0') {
len++;
str++;
}
return len;
}

31
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while ( size_right(str) > 0 && *str != '\0') {
len++;
str++;
}
return len;
}

31
Example: strlen()
... P r o g r a m m i n g ...

size_t strlen(const char *str) {


size_t len = 0;
while ( size_right(str) > 0 && *str != '\0') {
len++;
str++;
}
return len; 11
}

31
Introspection to Improve Bug-Finding

• Check invariants
• Abort when detecting inconsistencies
• E.g., allow libc’s “safe” functions to detect incorrect buffer sizes

size_t strnlen_s(const char *str, size_t maxlen);


errno_t strcpy_s(char *dest, rsize_t maxdestsz, const char *src);

32
Improve bug-finding capabilities

size_t strnlen_s(char *str, rsize_t maxsize) {


size_t i = 0;
for (; i < maxsize && s[i] != '\0'; i++);
return i;
}

33
Improve bug-finding capabilities
... P r o g r a m m i n g \0 ... 100

size_t strnlen_s(char *str, rsize_t maxsize) {


size_t i = 0;
for (; i < maxsize && s[i] != '\0'; i++);
return i;
}

33
Improve bug-finding capabilities
... P r o g r a m m i n g \0 ... 100

size_t strnlen_s(char *str, rsize_t maxsize) {


size_t i = 0;
for (; i < maxsize && s[i] != '\0'; i++);
return i; 11
}

33
Improve bug-finding capabilities
... P r o g r a m m i n g \0 ... 100

size_t strnlen_s(char *str, rsize_t maxsize) {


size_t i = 0;
for (; i < maxsize && s[i] != '\0'; i++);
return i; 11
} Correct result but did not
detect incorrect buffer size

33
Improve bug-finding capabilities

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;
}
}
34
Improve bug-finding capabilities
... P r o g r a m m i n g \0 ... 100

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;
}
}
34
Improve bug-finding capabilities
... P r o g r a m m i n g \0 ... 100

size_t strnlen_s(char *str, rsize_t maxsize) {


if ( size_right(str) < maxsize) {
abort();
Abort
} else {
size_t i = 0;
for (; i < maxsize && s[i] != '\0'; i++);
return i;
}
}
34
Introspection to Fix Errors in API Design

char *gets(char *str);

35
Introspection to Fix Errors in API Design

... ...

char *gets(char *str);

35
Introspection to Fix Errors in API Design

... ...

char *gets(char *str);

35
Introspection to Fix Errors in API Design

char* gets(char *str) {


int size = size_right(str);
return gets_s(str, size);
}

36
Introspection to Fix Errors in API Design

char* gets(char *str) {


int size = size_right(str);
return gets_s(str, size);
}
Make gets() robust
against input that would
overflow the buffer

36
Other examples

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 *));

37
Other examples

void qsort(void *base, size_t nitems, size_t size, int


(*compar)(const void *, const void*));
Verify the
function pointer
void *bsearch(const void *key, const void
*base, size_t nel, size_t width, int
(*compar)(const void *, const void *));

37
Other examples

int printf(const char *format, ...);


int sprintf(char *str, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);

38
Other examples

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

38
Other examples

void *realloc(void *ptr, size_t new_size);


void free(void *ptr);

39
Other examples

void *realloc(void *ptr, size_t new_size);


void free(void *ptr);

Verify that the object was


dynamically allocated

39
Implementation in Tools

40
Implementation in Safe Sulong

C C++ Fortran ...

Execute on

JVM

41
Implementation in Safe Sulong

C C++ Fortran ...

Safe Sulong tracks all


necessary metadata

Execute on

JVM

41
Implementation in Safe Sulong

int *arr = malloc(3 * sizeof(int));


int *ptr = &arr[1];

42
Implementation in Safe Sulong

int *arr = malloc(3 * sizeof(int));


int *ptr = &arr[1];

ptr: Address
I32Array
data
offset=4
contents {0, 0, 0}
location=DYNAMIC
location=AUTOMATIC

42
Implementation in Safe Sulong

int *arr = malloc(3 * sizeof(int));


int *ptr = &arr[1];

ptr: Address
I32Array
data
offset=4
contents {0, 0, 0}
location=DYNAMIC
location=AUTOMATIC

size_right(ptr)  data.contents.length * sizeof(int) –


offset
 3 * 4 – 4 = 8
42
Implementation in Safe Sulong

int *arr = malloc(3 * sizeof(int));


int *ptr = &arr[1];

ptr: Address
I32Array
data
offset=4
contents {0, 0, 0}
location=DYNAMIC
location=AUTOMATIC

location(ptr)  DYNAMIC

43
Implementation in Safe Sulong

int *arr = malloc(3 * sizeof(int));


int *ptr = &arr[1];

ptr: Address
I32Array
data
offset=4
contents {0, 0, 0}
location=DYNAMIC
location=AUTOMATIC

try_cast(ptr, type(*ptr))  ptr

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

45
Ongoing work: LLVM’s AddressSanitizer

• LLVM’s AddressSanitizer: memory error detector based on


shadow memory

... ...

size_right()
46
Ongoing work: LLVM’s AddressSanitizer

• LLVM’s AddressSanitizer: memory error detector based on


shadow memory

... ...

size_right()
46
Ongoing work: GCC’s Intel MPX Bounds
Checks Instrumentation

• Intel MPX: bounds registers and instructions


• GCC uses them to detect memory errors

47
Ongoing work: GCC’s Intel MPX Bounds
Checks Instrumentation

• Intel MPX: bounds registers and instructions


• GCC uses them to detect memory errors

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

47
Ongoing work: SoftBound

• SoftBound: bounds checker


• Tracks upper bounds for each pointer

ssize_t _size_right(const char* p) {


const char* bound = __softboundcets_load_bound_shadow_stack(1);
return bound - p;
}

48
Ongoing work: Real-world bugs

• Case study on bugs contained in the CVE database


• Libc goal: Availability
https://cve.mitre.org/

49
CVE-2017-14493

• Dnsmasq: DHCP server


• Incorrect size argument to memcpy() caused buffer overflow

state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2),
state->mac_len);

50
CVE-2017-14493

• Dnsmasq: DHCP server


• Incorrect size argument to memcpy() caused buffer overflow

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
50
CVE-2017-9047

• Libxml2: XML parsing library


• String concatenating caused a buffer overflow

if (content->name != NULL)
strcat(buf, (char *) content->name);

51
CVE-2017-9047

• Libxml2: XML parsing library


• String concatenating caused a buffer overflow

if (content->name != NULL)
strcat(buf, (char *) content->name);

The parser printed a


truncated error message

51
CVE-2017-16352

• GraphicsMagick: image processing library


• Incorrect size argument to strncpy()
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’;
}

52
CVE-2017-16352

• GraphicsMagick: image processing library


• Incorrect size argument to strncpy()
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’;
}
The error was
mitigated… 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’;
}

53
CVE-2017-16352

• GraphicsMagick: image processing library


• Incorrect size argument to strncpy()
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’;
}

54
CVE-2017-16352

• GraphicsMagick: image processing library


• Incorrect size argument to strncpy()
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’;
}
… but the application code had a
subsequent out-of-bounds access 54
Discussion and Conclusion

55
Discussion

• Introspection as a complement to automatic checks

... P r o g r a m m i n g ...

56
Discussion

• Introspection as a complement to automatic checks

... P r o g r a m m i n g ...

size_t strlen(const char *str) 11

56
Discussion

• Introspection as a complement to automatic checks

... P r o g r a m m i n g ...

size_t strlen(const char *str) 11

size_t my_strlen(const char *str) abort

56
Discussion

• Introspection as a complement to automatic checks

... P r o g r a m m i n g ...

size_t strlen(const char *str) 11

size_t my_strlen(const char *str) abort

Automatic checks still abort if the


error is not mitigated
56
Discussion

• Introspection as a complement to automatic checks


• What about partial/no support of introspection?

57
Discussion

• Introspection as a complement to automatic checks


• What about partial/no support of introspection?

size_right(ptr); LONG_MAX

57
Discussion

• Introspection as a complement to automatic checks


• What about partial/no support of introspection?

size_right(ptr); LONG_MAX

Sensible default values and


conservative checks?

57
Discussion

• Introspection as a complement to automatic checks


• What about partial/no support of introspection?
• Safer languages

Legacy software

58
Discussion

• Introspection as a complement to automatic checks


• What about partial/no support of introspection?
• Safer languages
• Programming effort

Introspection checks only


useful for frequently used
libraries

59
Conclusion

@RiggerManuel

60

You might also like