系统调用挂钩时出现问题

发布于 2024-12-06 16:14:14 字数 1649 浏览 1 评论 0原文

我使用以下模块代码来挂钩系统调用(代码归功于其他人,例如 Linux内核:系统调用挂钩示例)。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>

void **sys_call_table;

asmlinkage int (*original_call) (const char*, int, int);

asmlinkage int our_sys_open(const char* file, int flags, int mode)
{
   printk(KERN_ALERT "A file was opened\n");
   return original_call(file, flags, mode);
}

int set_page_rw(long unsigned int _addr)
{
   struct page *pg;
   pgprot_t prot;
   pg = virt_to_page(_addr);
   prot.pgprot = VM_READ | VM_WRITE;
   return change_page_attr(pg, 1, prot);
}

int init_module()
{
    // sys_call_table address in System.map
    sys_call_table = (void*)0xffffffff804a1ba0;
    original_call = sys_call_table[1024];
    set_page_rw(sys_call_table);
    sys_call_table[1024] = our_sys_open;
    return 0;
}

void cleanup_module()
{
   // Restore the original call
   sys_call_table[1024] = original_call;
}

当 insmod 已编译的 .ko 文件时,终端会抛出“Killed”。当查看“cat /proc/modules”文件时,我得到了“正在加载”状态。

my_module 10512 1 - Loading 0xffffffff882e7000 (P)

正如预期的那样,我无法 rmmod 这个模块,因为它抱怨它正在使用。系统将重新启动以获取全新状态。

后来,注释掉上述源码中的两行代码sys_call_table[1024] = our_sys_open;sys_call_table[1024] = original_call;后,就可以成功insmod了。更有趣的是,当取消这两行注释(改回原来的代码)时,编译后的模块就可以insmod成功。我不太明白为什么会出现这种情况?有没有办法可以成功编译代码并直接insmod它?

我在使用 linux 内核 2.6.24.6 的 Redhat 上完成了这一切。

I use the following module code to hooks syscall, (code credited to someone else, e.g., Linux Kernel: System call hooking example).

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>

void **sys_call_table;

asmlinkage int (*original_call) (const char*, int, int);

asmlinkage int our_sys_open(const char* file, int flags, int mode)
{
   printk(KERN_ALERT "A file was opened\n");
   return original_call(file, flags, mode);
}

int set_page_rw(long unsigned int _addr)
{
   struct page *pg;
   pgprot_t prot;
   pg = virt_to_page(_addr);
   prot.pgprot = VM_READ | VM_WRITE;
   return change_page_attr(pg, 1, prot);
}

int init_module()
{
    // sys_call_table address in System.map
    sys_call_table = (void*)0xffffffff804a1ba0;
    original_call = sys_call_table[1024];
    set_page_rw(sys_call_table);
    sys_call_table[1024] = our_sys_open;
    return 0;
}

void cleanup_module()
{
   // Restore the original call
   sys_call_table[1024] = original_call;
}

When insmod the compiled .ko file, terminal throws "Killed". When looking into 'cat /proc/modules' file, I get the Loading status.

my_module 10512 1 - Loading 0xffffffff882e7000 (P)

As expected, I can not rmmod this module, as it complains its in use. The system is rebooted to get a clean-slate status.

Later on, after commenting two code lines in the above source sys_call_table[1024] = our_sys_open; and sys_call_table[1024] = original_call;, it can insmod successfully. More interestingly, when uncommenting these two lines (change back to the original code), the compiled module can be insmod successfully. I dont quite understand why this happens? And is there any way to successfully compile the code and insmod it directly?

I did all this on Redhat with linux kernel 2.6.24.6.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沙沙粒小 2024-12-13 16:14:14

我认为您应该查看 kprobes API,该 API 在 Documentation/krpobes.txt 中有详细记录。它使您能够在每个地址(例如系统调用条目)上安装处理程序,以便您可以执行您想要的操作。额外的好处是您的代码将更加可移植。

如果您只对跟踪这些系统调用感兴趣,您可以使用审计子系统,编写自己的用户态守护程序,该守护程序将能够从审计 kthread 接收 NETLINK 套接字上的事件。 libaudit 提供了一个简单的 API 来注册/读取事件。

如果您确实有充分的理由不使用 kprobes/audit,我建议您检查您尝试写入的值是否不在您设置可写的页面之上。快速计算表明:

offset_in_sys_call_table * sizeof(*sys_call_table) = 1024 * 8 = 8192

如果您使用 4K 页面,则它是您设置为可写的页面之后的两页

I think you should take a look to the kprobes API, which is well documented in Documentation/krpobes.txt. It gives you the ability to install handler on every address (e.g. syscall entry) so that you can do what you want. Added bonus is that your code would be more portable.

If you're only interested in tracing those syscalls you can use the audit subsystem, coding your own userland daemon which will be able to receive events on a NETLINK socket from the audit kthread. libaudit provides a simple API to register/read events.

If you do have a good reason with not using kprobes/audit, I would suggest that you check that the value you are trying to write to is not above the page that you set writable. A quick calculation shows that:

offset_in_sys_call_table * sizeof(*sys_call_table) = 1024 * 8 = 8192

which is two pages after the one you set writable if you are using 4K pages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文