静态变量导致OSX网络kext崩溃

时间:2013-05-08 17:26:07

标签: macos static-variables kernel-extension panic

在mac OS X网络内核扩展中,我注意到如果我有静态分配的缓冲区而不是动态缓冲区,则在调用API函数(如printf()或send(),ctl_enqueuedata()时会导致内核混乱。 ),以及许多其他人。就好像无法从我的代码外部读取或写入静态分配的缓冲区。

例如:

// This is OK
static char* somevar = NULL;
somevar = OSMalloc(50, myOSMallocTag);
bzero(somevar, 50);

// This will create a kernel panic when used outside my code
static char somevar[50];
bzero(somevar, 50);

为什么?

编辑:我即将发布代码,但它很冗长,有效版本与导致恐慌的版本之间的唯一区别如上所述。 我想到的是静态变量和OSMalloc分配的静态变量之间的内存位置的差异。 ctl_enqueuedata()中的代码可以同时访问吗?

以下是发生的事情:

panic(cpu 0 caller 0xffffff802eeb7e95): Kernel trap at 0xffffff802ee28896, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000031, CR3: 0x000000024fbac0a7, CR4: 0x00000000001606e0
RAX: 0x000000007fffff01, RBX: 0x0000000000000000, RCX: 0x0000000000000010, RDX: 0xffffff7fb0d4d573
RSP: 0xffffff811f6fbae0, RBP: 0xffffff811f6fbbe0, RSI: 0x000000007fffffff, RDI: 0x0000000000000073
R8:  0x0000000000000000, R9:  0x0000000000000031, R10: 0x0000000000000000, R11: 0x0000000000000000
R12: 0x0000000000000000, R13: 0x0000000000000019, R14: 0xffffff811f6fbd01, R15: 0x0000000000000031
RFL: 0x0000000000010246, RIP: 0xffffff802ee28896, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000031, Error code: 0x0000000000000000, Fault CPU: 0x0

Backtrace (CPU 0), Frame : Return Address
0xffffff811f6fb780 : 0xffffff802ee1d626 
0xffffff811f6fb7f0 : 0xffffff802eeb7e95 
0xffffff811f6fb9c0 : 0xffffff802eecd4dd 
0xffffff811f6fb9e0 : 0xffffff802ee28896 
0xffffff811f6fbbe0 : 0xffffff802f174a62 
0xffffff811f6fbc00 : 0xffffff7fb0d4cead 
0xffffff811f6fbd40 : 0xffffff7fb0d46101 
0xffffff811f6fbdf0 : 0xffffff802f150525 
0xffffff811f6fbe40 : 0xffffff802f1990b2 
0xffffff811f6fbef0 : 0xffffff802f1a04f2 
0xffffff811f6fbf50 : 0xffffff802f1e063a 
0xffffff811f6fbfb0 : 0xffffff802eecdd23 

1 个答案:

答案 0 :(得分:1)

我不太清楚“你的代码之外”是什么意思,所以如果这个答案没有用,请详细说明。你提供的文字代码是可行的,我猜你已经从实际失败的东西中减少了它?

在这种情况下我可以想到两个可能的问题:

分配生命周期

静态变量的内存在加载kext时分配,在卸载时释放。你确定使用你的记忆是什么,在你的kext卸载之后肯定没有使用它吗?如果它是一个IOKit kext,内核将在加载后很快自动卸载它,除非其中一个人物匹配。这可能不是您和您的代码所期望的。

线程问题

基本上所有内核代码都是多线程的,你无法逃脱它。静态/全局变量特别容易受到竞争条件的影响。如果一个线程写入缓冲区而另一个线程试图通过printf()读取它,那么你就会遇到麻烦。您需要确保正确地序列化对缓冲区的访问,或使用不同的策略来管理缓冲区内存。如果缓冲区应该是临时的,那么在堆栈上分配它们(函数内的非static可能是一个更好的主意,具体取决于大小。正如@ Merlin069所提到的,内核堆栈非常小(<16kiB),因此避免大于几百字节的任何内容。除非它是一个递归函数,否则你的例子中的50字节缓冲区应该没问题。

<强>更新

关于你的子问题“我的想法是静态变量和OSMalloc分配的内存之间的差异.ctl_enqueuedata()中的代码可以同时访问吗?”

访问内核中分配的内存非常类似于在常规程序中执行此操作。 kernel_task有自己的内存映射,只要在内核模式下运行,它就会处于活动状态。内核是单片的,因此在一个kext中有效的指针在另一个kext中也是有效的。只有当你想从内核或用户空间的内核空间访问用户空间内存时,才必须明确地处理映射。

相关问题