04 November 2007

double free()

So, while writing an exploit for a publicly known bug at work I stumbled across another one, a double free(). Then I started looking into how exactly one exploit's a double free, and it looked grim. The program has to survive a double free, meaning that it cannot crash. The default action for glibc is to print an error message such as:

glibc detected *** double free or corruption (fasttop): 0x12345678 ***



and then call abort(), which terminates the program. So it looked like it was not exploitable, and just a DoS, so I looked at BSD libc and the libc from Solaris, neither of them appeared to be affected by double free's either. So I went back and looked in glibc's source code to determine what exactly it checks to detect a double free (There are a couple different checks depending on type, I'm only covering one here because it is what pertains to my situation and the others are essentially the same with a few other easily bypassed checks).

So, glibc has the concept of fast bin's, or arrays where it stores free chunks of memory under certain conditions, most importantly chunks that are less than 512 bytes in length. So I looked at the glibc code in malloc/malloc.c and find the following relevant section:

[...]
fb = &(av->fastbins[fastbin_index(size)]);
/* Another simple check: make sure the top of the bin is not the
record we are going to add (i.e., double free). */
if (__builtin_expect (*fb == p, 0))
{
errstr = "double free or corruption (fasttop)";
goto errout;
}




Here we have something interesting, let me explain the code first though. In the first line we take the variable 'fb' and make it point to the address of the element in the fast bin array for the size of the chunk in question. In other words, the fast bin array is sorted by size of chunks, and we are assigning the fb variable to the address of the index for the given size of our current chunk. Then we check to see if what that address points to (*fb) is the address of the current chunk being free'd (p), if so we've found the chunk being free'd in the list of free chunks and we have a double free situation (or linked list corruption).

But what if? What if another chunk of the same size and thus in the same fast bin has been deallocated since the current chunk was free'd, for instance, what if we have:

ptr0 = malloc(siz);
ptr1 = malloc(siz);

// presume both calls succeed

free(ptr0);
free(ptr1);



Then the top entry in the list won't be ptr0, it will be ptr1, and (assuming no other chunks in that list have been deallocated) ptr0 will be the second end on the linked list and the check will succeed and we will be able to free the pointer again, not have abort() called and potentially exploit the situation for our advantage.


#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
void *ptr0;

ptr0 = malloc((size_t)64);

if (NULL == ptr0) {
perror("malloc()");
return EXIT_FAILURE;
}

if (1 < argc) {

void *ptr1;

ptr1 = malloc((size_t)64);

if (NULL == ptr1) {
perror("malloc()");
return EXIT_FAILURE;
}

free(ptr0);
free(ptr1);
free(ptr0);

} else {

free(ptr0);
free(ptr0);

}

return EXIT_SUCCESS;
}




I've got a bit more on the glibc heap implementation, some of which I thought myself clever for finding only to realize it's been documented in a recent paper, others which just are redundant to mention at this point.

3 comments:

Jaz said...

Hmmm, interesting. Nice to know.

But how would one prevent/detect double freeing? Is it possible to check if memory was freed in the past?

not_me said...

@Miroslav -- its a difficult subject the minute threads get involved. You need to have some concept of 'thread ownership' of the block in order to be able to stop it; i noted from another blog that there have been recent changes to some of the code and it may prevent some of what i talked of here. Bottom line is however, if thread a allocates, then free's, then thread b allocates and get the same chunk, then thread a double free's, theres no clean way to detect it.

Anonymous said...

This rain that blinds the windows with its mists,Will gladden in suburbs no more to be found,
the kirefg88 black grapes on a vine there overhead.
Wholesale New Era Hats
Cheap 59fifty Hats
Cheap New Era Hats
New Era Snapback Hats
New Era Fitted Hats