如何在Linux内核模块中创建新任务(进程)
Linux内核模块创建新任务(进程/线程)的实现方法
之前实现方案的错误原因
- 直接引用
syscalls.h调用系统调用的方案不可行:内核态不允许直接调用面向用户态的系统调用接口,这类接口没有做内核上下文的适配,符号导出也有限制,你遇到的编译报错就是因为对应系统调用函数没有导出给内核模块使用。 - 手动修改
proc文件系统的方案无效:proc是内核进程信息的暴露层而非控制层,ps命令读取的是内核全局task_struct任务链表的信息,手动创建的proc文件不会被内核识别为合法任务,自然无法被ps查询到。
正确实现方案
场景1:创建内核态任务(内核线程)
使用内核原生提供的kthread系列API即可,不需要手动操作proc或者调用系统调用。
依赖头文件
#include <linux/kthread.h> #include <linux/sched.h> #include <linux/module.h>
核心API说明
kthread_run(threadfn, data, namefmt, ...):创建并立即启动内核线程,返回任务对应的struct task_struct指针threadfn:线程执行的函数,原型为int (*threadfn)(void *data)data:传给线程函数的自定义参数namefmt:线程名称,支持格式化字符串
kthread_should_stop(void):在线程函数内调用,检查是否收到线程停止信号,收到时返回truekthread_stop(struct task_struct *k):向指定内核线程发送停止信号,等待线程退出后返回
示例代码
static struct task_struct *my_task; static int my_task_fn(void *args) { // 线程运行逻辑 while (!kthread_should_stop()) { printk(KERN_INFO "自定义内核线程运行中\n"); // 休眠1秒,避免占满CPU set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } printk(KERN_INFO "自定义内核线程即将退出\n"); return 0; } static int __init my_module_init(void) { // 创建并启动线程 my_task = kthread_run(my_task_fn, NULL, "my_custom_kthread"); if (IS_ERR(my_task)) { printk(KERN_ERR "创建内核线程失败\n"); return PTR_ERR(my_task); } return 0; } static void __exit my_module_exit(void) { // 停止线程 if (my_task) { kthread_stop(my_task); } } MODULE_LICENSE("GPL"); module_init(my_module_init); module_exit(my_module_exit);
该线程创建后可直接通过ps aux | grep my_custom_kthread查询到对应条目。
场景2:创建用户态进程
如果需要在内核模块中启动用户空间的可执行程序,使用call_usermodehelper系列API即可。
示例代码
#include <linux/umh.h> static int __init my_module_init(void) { char *argv[] = { "/bin/echo", "内核模块启动的用户进程", NULL }; char *envp[] = { "HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL }; int ret; // 同步等待用户进程执行完成 ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); if (ret < 0) { printk(KERN_ERR "启动用户进程失败: %d\n", ret); return ret; } return 0; }
注意事项
- 不要直接调用
sys_fork/sys_clone等系统调用函数,这类接口未适配内核模块调用场景,极易触发内核崩溃 - 内核线程默认没有用户地址空间,无法直接执行用户态代码,有用户态执行需求请使用
call_usermodehelper接口
内容的提问来源于stack exchange,提问作者Ori
相关产品推荐
相关产品推荐

