c - 内存的 kfree 部分是否有效?

标签 c linux linux-kernel linux-device-driver

我正在调试内存损坏问题,发现 Linux 内核似乎接受用户“释放部分缓冲区”。课本上总是教我们成对调用alloc/free。我有点迷惑不解了!所以我写了一个在 Linux 内核中运行的小测试。

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

和结果(在 Linux 3.16 上运行)

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

可以看到(1)和(2)地址是一样的。这是对的吗?这是否意味着 Linux 如我所料将缓冲区分成两部分? 我知道这段代码肯定是错误的,但我只想知道 Linux 内核如何处理它 - Linux 如何释放一个与 alloc 不同的地址。

提前致谢。

最佳答案

操作系统内核可能会安全地假设模块开发人员知道他们在做什么(与应用程序开发相反,应用程序开发应该永远无法损害操作系统)。

显然,Linux 已经决定(可能是出于运行时效率的原因)不检查交给kfree() 的地址是否最初由kmalloc()(一个强烈的暗示是 kfree() 的签名甚至不允许它返回错误代码)。

内核中分配的所有内存都需要在某处进行监控(最典型的是在某种 block 头中,就在它返回给你的那 block 内存之前),以便能够正确释放再次记忆。 kmalloc()某处 初始化这个(使用分配 block 的大小、用途、属于哪个实例等信息)。如果您 kfree() 一些东西不是由 kmalloc() 分配的,那么这个某处 将根本不存在并且将使内核解释任意区域内存作为某处 - 导致各种未定义的行为,最终导致内核崩溃。这种行为不当的代码迟早会崩溃,仅取决于您运行的内核中的动态量。它可能会一直有效,直到有人决定卸载您的模块,或者甚至只是因为内核内存越来越紧张。

我的(公认的旧)kfree 手册页清楚地说明了

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

如果你想释放缓冲区的一部分(在最后),你应该使用 krealloc(),但是总是 返回的原始指针kmalloc()

顺便说一句:找到此类误用的一种快速方法是使用定义 kmymalloc() 和 kmyfree() 的宏或函数来武装您的源代码,这些宏或函数将分配更多内存,并在开始时设置内存保护分配区域如

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

关于c - 内存的 kfree 部分是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35863207/

相关文章:

C:结构声明中允许成员之间的操作吗?

c - 如何在我的 HTTP 代理中查看 TCP、IP header ?

linux - 在本地主机中链接(LAMP)

javascript - 为什么node.js没有加载我需要的模块?

c - 为什么 C 会在 while 循环中卡住?

c++ - 替换 sync() 命令

shell - linux环境下后台进程的优先级是什么

linux - 如何将以太网设备直接连接到 linux 中的交换机?

linux - 从结构文件中获取父目录

c - sigaction 并在 linux 环境中忽略带有 c 的信号