【发布时间】:2015-11-29 04:39:26
【问题描述】:
我有一个内核模块,它删除了写保护位来修改系统调用表,以便挂钩任何系统调用——比如sys_rmdir。该模块在 64 位系统上按预期工作,但对于 32 位系统,为什么内核在访问 系统调用表的地址后会出现恐慌并给出 oops?
此时模块有问题:
#ifdef __x86_64__
#define CR0_WP 0x00010000 // Write Protect Bit (CR0:16)
#else
#define CR0_WP 0x10000 // Write Protect Bit (CR0:16)
#endif
...
unsigned long cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);
...
unsigned long addr = (unsigned long)syscall_table; //Where syscall_table is c059a170, same exists in /proc/kallsyms
if(set_memory_rw(PAGE_ALIGN(addr) - PAGE_SIZE, 3))
{
...
return -1;
}
orig_sys_rmdir = syscall_table[__NR_rmdir]; //where orig_sys_rmdir is declared as : long (*orig_sys_rmdir)(const char *filename);
syscall_table[__NR_rmdir] = my_sys_rmdir; //Kerenl goes panic here, I guess. my_sys_rmdir is a simple wrapper for sys_rmdir
...
内核版本为 2.6.X-X-generic,Ubuntu 10.04。仅在 32 位系统上出现此故障的原因可能是什么?
感谢您的宝贵时间。
编辑:
错误日志:
BUG: unable to handle kernel NULL pointer dereference at 00000005
IP: [<c035834a>] strncmp+0x1a/0x40
*pde = 32090067 *pte = 00000000
Oops: 0000 [#2] SMP
imklog 4.2.0, log source = /proc/kmsg started.
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Linux version 2.6.32-74-generic (buildd@allspice) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) ) #142-Ubuntu SMP Tue Apr 28 10:02:35 UTC 2015 (Ubuntu 2.6.32-74.142-generic 2.6.32.63+drm33.26)
【问题讨论】:
-
你能把它附加到 gdb 以确定它在哪里崩溃吗?
-
@icbytes,我添加了日志
-
由于调试信息太少,我猜是加载的模块没有编译到你认为的目标。
-
这是在 64 位上调试的?在调试期间手动收集所有信息?我们可以在 *pte 中看到什么?我假设,如果为 64 位构建并且它在 32 位上失败并且 *pte 被清零,并且在 32 位中没有,则应该驻留在 pte 中的值在 64 位上的 8 字节 int 值中可能太大,即在 32 位的 4 字节 int 中以某种方式减少到零。
-
该模块是为加载它的同一台机器编译的。
标签: c linux linux-kernel kernel kernel-module