【问题标题】:Hooking into syscall table with module使用模块连接到系统调用表
【发布时间】: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/_exitprintks 确实出现了,但是当我以任何方式对内核执行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


【解决方案1】:

查看arch/mips/kernel/ftrace.c 让我相信您需要使用名为“sys32_call_table”的表

【讨论】:

  • 在 3.10 源码树中没有提到 sys32_call_table,这似乎是最近的事情?
  • 确实在 3.10 中没有,但我认为您需要检查系统调用参数。看起来对于 O32,您需要从系统调用号中减去 __NR_O32_Linux?我不太确定,因为我没有使用过 MIPS。 kernel.googlesource.com/pub/scm/linux/kernel/git/stable/… 无论哪种方式,您都可以直接在“fs/ioctl.c”和“fs/compat_ioctl.c”中实现您的钩子。如果你想要一个模块,你可以通过 security_file_ioctl 实现一个可加载的安全模块,如 SELinux 或 Tomoyo
【解决方案2】:

我做错了什么?

您正试图从内核模块修改系统调用表。这是不安全且不受支持的。不要这样做。

如果您想检查系统调用,内核中有许多更好的工具可用,例如ftraceperfSystemTap。哪一个最适合您将取决于您的具体要求。

【讨论】:

  • 完全意识到这是不正当的做法。将进一步研究 ftrace 以查看是否可以帮助我们。其他两个选项在目标系统(硬化嵌入式内核)上不可用。
【解决方案3】:

@alexst 提供了真实答案! 根据 linux/unistd.h 的 MIPS 架构:

#define __NR_Linux 4000
...
#define __NR_ioctl (__NR_Linux + 54)

所以你需要从 __NR_ioctl 中减去 __NR_Linux,例如:

ioctl_orig = (void*)sct[__NR_ioctl-__NR_Linux];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多