使用模块挂接到系统调用表

问题描述 投票:0回答:4

在我早期的内核编程工作中,我试图替换/挂钩 ioctl 系统调用,目的是记录并最终检查完成的每个 ioctl 调用。

目标系统是内核为3.10的mips(o32)系统。

基于我在基于 x86 的系统上看到的类似项目/示例,我得出了一个我认为可行的基本片段。我无权访问 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");

显然这是行不通的,否则我就不会在这里刮墙了。该模块加载良好,来自

printk
/
_enter
_exit
确实出现了,但是当我以任何方式对内核执行 ioctl 时,没有任何反应(我希望看到来自
ioctl_new 的“拦截的 ioctl”消息) 
),这让我相信我修改了错误的位置。

问题:

  • 显然:我做错了什么?
  • 我可以依靠
    /proc/kallsyms
    提供指向系统调用表开头的正确指针吗?
  • 我的假设是否正确,即
    sys_ioctl
    中与
    /proc/kallsyms
    相关的值应该与
    *sct[__NR_ioctl]
    匹配,还是我遗漏了某些内容?
  • 我的投射正确吗?
  • 这种修改 sctable 的方法是否适用于 mips?
c linux-kernel system-calls kernel-module
4个回答
0
投票

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


0
投票

我做错了什么?

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

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


0
投票

@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];

0
投票

我最近在旧内核上挂接了内核函数,上面的答案帮助我解决了我的问题。 我的系统环境是Linux(无)3.17.2 mips32 Little-Endian

错误用法

__sys_call_table[__NR_kill] = (unsigned long) hacked_kill;

正确使用方法

__sys_call_table[__NR_kill - __NR_O32_Linux] = (unsigned long) hacked_kill;
© www.soinside.com 2019 - 2024. All rights reserved.