c - 为什么内核在访问 32 位系统的内核模块中的系统调用表后会出现 panic ?

标签 c linux linux-kernel kernel kernel-module

我有一个内核模块,它删除了写保护位以修改系统调用表,以便 Hook 任何系统调用 - 比如 sys_rmdir。此模块在 64 位系统上按预期工作,但对于 32 位系统,为什么内核会在访问系统调用表的地址后出现 panic 并发出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)

最佳答案

@NTN 这是你在回答中提出的答案

我不知道为什么以及如何在 64 位系统上运行相同的代码,但在 32 位系统上却不行

Asmlinkage 标签告诉编译器查看 cpu 堆栈上的参数。如果您不使用此标记,则编译器将根据调用约定在寄存器中查看。 对于 32 位系统,您可以在寄存器 %eax,%ecx,%edx 中传递 3 个参数,而在堆栈中传递其他参数(如果有的话)。但在 64 位系统中,您可以使用 6 个寄存器 %rdi、%rsi、%rdx、%rcx、%r8、%r9

这意味着您的系统调用使用了 3 个以上的参数。当您在没有 asmlinkage 的情况下传递它们时,编译器无法在 32 位系统上找到所有参数,但在 64 位系统中它可以轻松找到它们。当您使用 asmlinkage 时,所有参数都通过 cpu 堆栈传递,因此您的代码是成功的。

关于c - 为什么内核在访问 32 位系统的内核模块中的系统调用表后会出现 panic ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32374031/

相关文章:

c - 将字符串中的每个子字符串存储在数组中

c - 使用 libnl-3 发送 Netlink Taskstats 消息

c++ - Linux 和 Windows 构建的应用程序之间的 OpenCV 行为差异

c - 如何修改内核DTB文件

android - 如何在每个 CPU 上运行代码

c - 如何在 C 中设置 Don't Fragment (IP_DF) 标志

使用 C 的 WebKit2Gtk 中的 JavaScriptCore?

linux - Aerospike 进程占用大量内存

linux - ctrl+c 不杀死后台功能

networking - 在 Linux 内核中创建数据包的教程