【发布时间】:2017-11-20 22:43:29
【问题描述】:
在我早期的内核编程工作中,我尝试替换/挂钩到 ioctl 系统调用,目的是记录并最终检查完成的每个 ioctl 调用。
目标系统是内核 3.10 的 mips (o32) 系统。
基于我在基于 x86 的系统中看到的类似项目/示例,我得出了一个我认为可行的基本 sn-p。我无权访问 System.map,但我注意到 sys_call_table 地址,因此我的尝试基于在目标系统上找到的地址 /proc/kallsyms。我知道这个地址会随着内核构建而改变,但这并不重要;这仅用于实验目的。
整个模块:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
static u32 **sct = (u32**)0x80008660; // `grep sys_call_table /proc/kallsyms`
asmlinkage int (*ioctl_orig)(s32 fd, u32 cmd, void* addr);
asmlinkage int ioctl_new(s32 fd, u32 cmd, void* addr)
{
printk("[IOC] Intercepted ioctl 0x%x to addr 0x%p\n", cmd, addr);
return ioctl_orig(fd, cmd, addr);
}
static int __init _enter(void)
{
ioctl_orig = (void*)sct[__NR_ioctl];
sct[__NR_ioctl] = (u32*)ioctl_new;
printk("[IOC] Original IOCTL addr: %p\n", ioctl_orig);
printk("[IOC] New IOCTL addr: %p\n", sct[__NR_ioctl]);
return 0;
}
static void __exit _exit(void)
{
sct[__NR_ioctl] = (u32 *)ioctl_orig;
printk("[IOC] Unloaded\n");
}
module_init(_enter);
module_exit(_exit);
MODULE_LICENSE("GPL");
显然这不起作用,否则我不会在这里刮墙。该模块加载正常,来自_enter/_exit 的printks 确实出现了,但是当我以任何方式对内核执行ioctls 时没有任何反应(我希望看到来自@987654327 的“Intercepted ioctl”消息@),这让我相信我在修改错误的位置。
问题:
- 显然:我做错了什么?
- 我能否依靠
/proc/kallsyms提供指向系统调用表开头的正确指针? - 我的假设是否正确,即
/proc/kallsyms中与sys_ioctl关联的值应该与*sct[__NR_ioctl]匹配,还是我遗漏了什么? - 我的投射是否正确?
- 这种修改 sctable 的方法是否也适用于 mips?
【问题讨论】:
-
“我做错了什么?”在 x86 上,要这样做,您必须通过一些 asm 行禁用页面保护。我认为 mips 上有一些等价物。
-
"我可以依赖
/proc/kallsyms...吗?"您的系统上是否存在函数kallsyms_lookup_name("sys_call_table")?它应该返回你想要的。 (stackoverflow.com/a/39202118/1212012) -
我知道 x86 上的 cr0 页面保护位,尽管我没有发现任何证据表明 MIPS 上存在类似机制。
-
另外,不幸的是,kallsyms_lookup_name 没有在我正在使用的内核中导出,所以不要去那里。
标签: c linux-kernel system-calls kernel-module