public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* use-after-free / double-free exploit mitigation
@ 2017-09-06 12:47 up201407890
  2017-09-07 16:00 ` Florian Weimer
  0 siblings, 1 reply; 6+ messages in thread
From: up201407890 @ 2017-09-06 12:47 UTC (permalink / raw)
  To: libc-alpha

Hello list,

What are your thoughts on adding a SAFE_FREE() macro to glibc:

#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.

The pointer passed to free() isn't always an lvalue we can assign to,  
e.g free(func()), but when a var is used it will detect use-after-free  
and double-free bugs by having the program crash instead of allowing  
various heap grooms and further exploitation.


Here's a trivial example,

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

----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: use-after-free / double-free exploit mitigation
  2017-09-06 12:47 use-after-free / double-free exploit mitigation up201407890
@ 2017-09-07 16:00 ` Florian Weimer
  2017-09-08 12:45   ` Martin Sebor
  0 siblings, 1 reply; 6+ messages in thread
From: Florian Weimer @ 2017-09-07 16:00 UTC (permalink / raw)
  To: up201407890, Martin Sebor; +Cc: libc-alpha

On 09/06/2017 02:46 PM, up201407890@alunos.dcc.fc.up.pt wrote:
> What are your thoughts on adding a SAFE_FREE() macro to glibc:
> 
> #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.

Maybe GCC should optionally do this for the actual call to free.  There
is some debate to what extend pointer *values* remain valid after free.
Martin Sebor may have some thought on that.

In any case, some GCC assistance is needed so that

  free (some_struct->ptr);
  free (some_struct);

actually clobbers some_struct->ptr.  I don't think we want to call out
to explicit_bzero here.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: use-after-free / double-free exploit mitigation
  2017-09-07 16:00 ` Florian Weimer
@ 2017-09-08 12:45   ` Martin Sebor
  0 siblings, 0 replies; 6+ messages in thread
From: Martin Sebor @ 2017-09-08 12:45 UTC (permalink / raw)
  To: Florian Weimer, up201407890, Martin Sebor; +Cc: libc-alpha

On 09/07/2017 10:00 AM, Florian Weimer wrote:
> On 09/06/2017 02:46 PM, up201407890@alunos.dcc.fc.up.pt wrote:
>> What are your thoughts on adding a SAFE_FREE() macro to glibc:
>>
>> #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.
>
> Maybe GCC should optionally do this for the actual call to free.  There
> is some debate to what extend pointer *values* remain valid after free.
> Martin Sebor may have some thought on that.
>
> In any case, some GCC assistance is needed so that
>
>   free (some_struct->ptr);
>   free (some_struct);
>
> actually clobbers some_struct->ptr.  I don't think we want to call out
> to explicit_bzero here.

One of the advantages of doing this in the compiler (besides not
having to change source code) is distinguishing rvalues from lvalues.

Martin

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: use-after-free / double-free exploit mitigation
  2017-09-10 15:41 ` Martin Sebor
@ 2017-09-11 15:36   ` Federico Manuel Bento
  0 siblings, 0 replies; 6+ messages in thread
From: Federico Manuel Bento @ 2017-09-11 15:36 UTC (permalink / raw)
  To: Martin Sebor; +Cc: fweimer, libc-alpha

A 2017-09-10 16:41, Martin Sebor escreveu:
> On 09/09/2017 11:59 AM, Federico Manuel Bento wrote:
>>>>> On 09/06/2017 02:46 PM, up201407890@alunos.dcc.fc.up.pt wrote:
>>>>> What are your thoughts on adding a SAFE_FREE() macro to glibc:
>> 
>>>>> #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.
>> 
>>>> Maybe GCC should optionally do this for the actual call to free. 
>>>> There
>>>> is some debate to what extend pointer *values* remain valid after 
>>>> free.
>>>> Martin Sebor may have some thought on that.
>> 
>>>> In any case, some GCC assistance is needed so that
>> 
>>>> free (some_struct->ptr);
>>>> free (some_struct);
>> 
>>>> actually clobbers some_struct->ptr. I don't think we want to call 
>>>> out
>>>> to explicit_bzero here.
>> 
>>> One of the advantages of doing this in the compiler (besides not
>>> having to change source code) is distinguishing rvalues from lvalues.
>> 
>>> Martin
>> 
>> Perhaps this sould be used when making use of FORTIFY_SOURCE?
> 
> That seems reasonable.  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.  Opening an enhancement
> request in GCC Bugzilla for this would help track interest in
> the feature.
> 
> Martin

Here's the request in GCC's Bugzilla:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82179

Thanks,
Federico Bento.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: use-after-free / double-free exploit mitigation
  2017-09-09 17:59 Federico Manuel Bento
@ 2017-09-10 15:41 ` Martin Sebor
  2017-09-11 15:36   ` Federico Manuel Bento
  0 siblings, 1 reply; 6+ messages in thread
From: Martin Sebor @ 2017-09-10 15:41 UTC (permalink / raw)
  To: Federico Manuel Bento, fweimer; +Cc: libc-alpha

On 09/09/2017 11:59 AM, Federico Manuel Bento wrote:
>>>> On 09/06/2017 02:46 PM, up201407890@alunos.dcc.fc.up.pt wrote:
>>>> What are your thoughts on adding a SAFE_FREE() macro to glibc:
>
>>>> #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.
>
>>> Maybe GCC should optionally do this for the actual call to free. There
>>> is some debate to what extend pointer *values* remain valid after free.
>>> Martin Sebor may have some thought on that.
>
>>> In any case, some GCC assistance is needed so that
>
>>> free (some_struct->ptr);
>>> free (some_struct);
>
>>> actually clobbers some_struct->ptr. I don't think we want to call out
>>> to explicit_bzero here.
>
>> One of the advantages of doing this in the compiler (besides not
>> having to change source code) is distinguishing rvalues from lvalues.
>
>> Martin
>
> Perhaps this sould be used when making use of FORTIFY_SOURCE?

That seems reasonable.  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.  Opening an enhancement
request in GCC Bugzilla for this would help track interest in
the feature.

Martin

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: use-after-free / double-free exploit mitigation
@ 2017-09-09 17:59 Federico Manuel Bento
  2017-09-10 15:41 ` Martin Sebor
  0 siblings, 1 reply; 6+ messages in thread
From: Federico Manuel Bento @ 2017-09-09 17:59 UTC (permalink / raw)
  To: fweimer, msebor; +Cc: libc-alpha

>>> On 09/06/2017 02:46 PM, up201407890@alunos.dcc.fc.up.pt wrote:
>>> What are your thoughts on adding a SAFE_FREE() macro to glibc:

>>> #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.

>> Maybe GCC should optionally do this for the actual call to free. There
>> is some debate to what extend pointer *values* remain valid after 
>> free.
>> Martin Sebor may have some thought on that.

>> In any case, some GCC assistance is needed so that

>> free (some_struct->ptr);
>> free (some_struct);

>> actually clobbers some_struct->ptr. I don't think we want to call out
>> to explicit_bzero here.

> One of the advantages of doing this in the compiler (besides not
> having to change source code) is distinguishing rvalues from lvalues.

> Martin

Perhaps this sould be used when making use of FORTIFY_SOURCE?

Federico.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-09-11 15:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-06 12:47 use-after-free / double-free exploit mitigation up201407890
2017-09-07 16:00 ` Florian Weimer
2017-09-08 12:45   ` Martin Sebor
2017-09-09 17:59 Federico Manuel Bento
2017-09-10 15:41 ` Martin Sebor
2017-09-11 15:36   ` Federico Manuel Bento

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).