acolor
acolor

Reputation: 31

Is kfree parts of memory valid or not?

I am debugging a memory corruption issue and found that Linux kernel seems to accept user to "free parts of buffer". Textbook always teaches us to call alloc/free in pairs. I get confused! So I write a small test running in Linux kernel.

char *p_buf, *p_buf2;

p_buf = kmalloc(1024, GFP_KERNEL);     //alloc 1024
printk("malloc(1024) = %p\n", p_buf); 

kfree(p_buf+256);                      //free from offset 256(equals to free 768)
printk("kfree(%p)\n", p_buf+256);

p_buf2 = kmalloc(1024-256, GFP_KERNEL);  // alloc 768
printk("malloc(%d) = %p\n", 1024-256, p_buf2);

kfree(p_buf);
kfree(p_buf2);

And result (running on Linux 3.16)

malloc(1024) = ce52b800   //alloc 1024
kfree(ce52b900)           //free 768  ---(1)
malloc(768) = ce52b900    //alloc 768 ---(2)

You can see that (1) and (2) addresses are the same. Is it correct? Does it mean that Linux divide the buffer into two pieces as I expect ? I know this code is definitely wrong but I just want to know how Linux kernel handle it - how Linux free an address which is not the same as from alloc.

Thanks in advanced.

Upvotes: 1

Views: 3382

Answers (1)

tofro
tofro

Reputation: 6063

An operating system kernel may decide to safely assume module developers know what they are doing (as opposed to application development which should never be able to compromise the OS).

Apparently, Linux has decided (probably for reasons of run-time efficiency) to not check whether the address handed over to kfree() was originally allocated by kmalloc() (A strong hint is that kfree()'s signature doesn't even allow it to return an error code).

All memory allocated within the kernel needs to be monitored somewhere (most typically in a sort of block header just preceeding the piece of memory it hands back to you) in order to be able to properly release the memory again. kmalloc() initializes this somewhere (with information like size of allocated block, usage, belonging to what instance, and so on). If you kfree() something that was not allocated by kmalloc(), this somewhere will simply not exist and will make the kernel interpret arbitrary regions of memory as somewhere - Leading to all sorts of undefined behavior and, finally, kernel meltdown. Whether such misbehaving code is going to crash sooner or later, is only determined by the amount of dynamics in your running kernel. It might work until someone decides to unload your module or even only because kernel memory is getting tight.

And my (admittedly old) man page to kfree clearly states

Don't free memory not originally allocated by kmalloc or you will run into trouble.

If you want to free parts of a buffer (at the end), you should use krealloc(), but always with the original pointer returned by kmalloc()

BTW: A fast way to find such mis-uses is to arm your source code with macros or functions defining kmymalloc() and kmyfree() that would allocate some more memory, and set up a memory guard at the beginning of the allocated area like

void  *kmymalloc(...)
    unsigned long *area = kmalloc (...<size+sizeof (unsigned long)>)
    *area = 0xdeadbeef;
    return (void*) &(area[1]);
}
void *kmyfree(...){
    unsigned long *area = *(ptr - sizeof (unsigned long));
    if (*area != 0xdeadbeef)
        ... print a stack trace, shutdown system, or whatever
    else
       kfree (area)
}

Upvotes: 2

Related Questions