Summary: | Optionally compile free calls in such a way that the passed pointer is clobbered after the call | ||
---|---|---|---|
Product: | gcc | Reporter: | Federico Bento <up201407890> |
Component: | c | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | NEW --- | ||
Severity: | enhancement | CC: | dimhen, egallager, fw, msebor |
Priority: | P3 | ||
Version: | unknown | ||
Target Milestone: | --- | ||
URL: | https://sourceware.org/ml/libc-alpha/2017-09/msg00423.html | ||
See Also: | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80532 | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2017-12-11 00:00:00 |
Description
Federico Bento
2017-09-11 14:31:54 UTC
Hello, This a request for an exploit mitigation to be added to the compiler, possibly when making use of FORTIFY_SOURCE. Something like the below, but at the compiler level: #define SAFE_FREE(x) do { if((x) != 0x0) { free(x); (x) = (void *)0x1; } } while(0) After free(x), we set x to an address that will crash when dereferenced (use-after-free), and will also crash when it's an argument to free(). Note that NULL isn't used, because free(NULL) does nothing, which might hide potential double-free bugs. This will detect use-after-free and double-free bugs by having the program crash instead of allowing various heap grooms and further exploitation. After discussion with Martin Sebor and Florian Weimer in the libc-alpha list, it was pointed out to me to post the request here for further interest. https://sourceware.org/ml/libc-alpha/2017-09/msg00238.html https://sourceware.org/ml/libc-alpha/2017-09/msg00423.html Below are some examples of how it works, Crashes when use-after-free: $ cat test.c #include <unistd.h> #include <stdlib.h> #define SAFE_FREE(x) do { if((x) != 0x0) { free(x); (x)=(void *)0x1; } } while(0) struct unicorn_counter { int num; }; int main() { struct unicorn_counter* p_unicorn_counter; int* run_calc = malloc(sizeof(int)); *run_calc = 0; SAFE_FREE(run_calc); //SAFE_FREE(run_calc); p_unicorn_counter = malloc(sizeof(struct unicorn_counter)); p_unicorn_counter->num = 42; if (*run_calc) // use-after-free execlp("/usr/bin/id", "id", 0); } $ gcc test.c $ ./a.out Segmentation fault $ gdb ./a.out gdb$ r ... 0x4005ed <main+87>: mov eax,DWORD PTR [rax] Stopped reason: SIGSEGV 0x00000000004005ed in main () gdb$ print /x $rax $1 = 0x1 Crashes when double-free, by uncommenting 2nd SAFE_FREE(run_calc): $ cat test.c #include <unistd.h> #include <stdlib.h> #define SAFE_FREE(x) do { if((x) != 0x0) { free(x); (x)=(void *)0x1; } } while(0) struct unicorn_counter { int num; }; int main() { struct unicorn_counter* p_unicorn_counter; int* run_calc = malloc(sizeof(int)); *run_calc = 0; SAFE_FREE(run_calc); SAFE_FREE(run_calc); // double-free p_unicorn_counter = malloc(sizeof(struct unicorn_counter)); p_unicorn_counter->num = 42; if (*run_calc) execlp("/usr/bin/id", "id", 0); } $ gcc test.c $ gdb ./a.out gdb$ r ... 0x7ffff7aad614 <__GI___libc_free+20>: mov rax,QWORD PTR [rdi-0x8] Stopped reason: SIGSEGV __GI___libc_free (mem=0x1) at malloc.c:2929 warning: Source file is more recent than executable. $ print /x $rdi $1 = 0x1 I pressed enter before entering a description, so the actual description is comment 1. Sorry for that. Federico Bento. Given the retitling, I'll confirm this as an enhancement. (In reply to Federico Bento from comment #1) > Hello, > > This a request for an exploit mitigation to be added to the compiler, > possibly when making use of FORTIFY_SOURCE. > > Something like the below, but at the compiler level: > > #define SAFE_FREE(x) do { if((x) != 0x0) { free(x); (x) = (void *)0x1; } } > while(0) > > After free(x), we set x to an address that will crash when dereferenced > (use-after-free), and will also crash when it's an argument to free(). > Note that NULL isn't used, because free(NULL) does nothing, which might > hide potential double-free bugs. > > This will detect use-after-free and double-free bugs by having the program > crash instead of allowing various heap grooms and further exploitation. > > After discussion with Martin Sebor and Florian Weimer in the libc-alpha > list, it was pointed out to me to post the request here for further interest. > > https://sourceware.org/ml/libc-alpha/2017-09/msg00238.html > https://sourceware.org/ml/libc-alpha/2017-09/msg00423.html > In this, Martin said, "David Malcolm has done some preliminary work on a GCC maaloc/free optimization and diagnostic pass that might be well suited to this sort of instrumentation," so cc-ing him. (In reply to Eric Gallager from comment #5) > (In reply to Federico Bento from comment #1) > > > > https://sourceware.org/ml/libc-alpha/2017-09/msg00238.html > > https://sourceware.org/ml/libc-alpha/2017-09/msg00423.html > > > > In this, Martin said, "David Malcolm has done some preliminary work > on a GCC maaloc/free optimization and diagnostic pass that might be > well suited to this sort of instrumentation," so cc-ing him. The static analyzer he's developing might also be relevant for things like this |