使用 workqueue 或 kthread 在 Linux 内核中执行 ELF
Executing an ELF in Linux kernel with workqueue or kthread
我正在尝试在收到网络消息时在内核中启动用户空间进程(执行 ELF 二进制文件)。在网络事件处理程序中,我启动了一个工作队列。在工作队列处理函数中,我调用 do_execve
但出现内核恐慌:
[ 113.305996] Unable to handle kernel paging request at virtual address ffffffffffffffd8
[ 113.306375] pgd = ffff8000f9d06000
[ 113.306520] [ffffffffffffffd8] *pgd=0000000000000000
[ 113.306915] Internal error: Oops: 96000004 [#1] SMP
代码:
static void clone_thread(struct work_struct *_work)
{
struct pcn_kmsg_work *work = (struct pcn_kmsg_work *)_work;
network_request_t *req = work->msg;
int ret = 0;
PSPRINTK("%s: exe_path %s\n", __func__, req->exe_path);
ret = do_execve(getname_kernel(req->exe_path), NULL, NULL);
PSPRINTK("%s: filename %p\n", __func__, getname_kernel(req->exe_path));
PSPRINTK("%s: ret %d\n", __func__, ret);
}
static int handle_network_request(struct pcn_kmsg_message *msg)
{
network_request_t *req = (network_request_t *)msg;
struct pcn_kmsg_work *work = kmalloc(sizeof(*work), GFP_ATOMIC);
BUG_ON(!work);
work->msg = req;
INIT_WORK((struct work_struct *)work, clone_thread);
queue_work(pcn_wq, (struct work_struct *)work);
return 0;
}
... ...
然后我尝试在内核线程中调用do_execve
。但是由于某些原因,内核线程只执行printk
,从不执行do_execve
。
所以我想知道如何在 Linux 内核中执行 ELF?谢谢。
为此您应该使用 call_usermodehelper()
内部内核 API:
#include <linux/kmod.h>
/* ... */
{
char ∗argv[] = { req->exe_path, NULL };
static char ∗envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_EXEC );
}
在我看来,您的 struct pcn_kmsg_message
可能在工作队列运行之前被释放 - 您可能需要将 exe_path
字符串复制到 pcn_kmsg_work
结构中,而不仅仅是复制指针。
我正在尝试在收到网络消息时在内核中启动用户空间进程(执行 ELF 二进制文件)。在网络事件处理程序中,我启动了一个工作队列。在工作队列处理函数中,我调用 do_execve
但出现内核恐慌:
[ 113.305996] Unable to handle kernel paging request at virtual address ffffffffffffffd8
[ 113.306375] pgd = ffff8000f9d06000
[ 113.306520] [ffffffffffffffd8] *pgd=0000000000000000
[ 113.306915] Internal error: Oops: 96000004 [#1] SMP
代码:
static void clone_thread(struct work_struct *_work)
{
struct pcn_kmsg_work *work = (struct pcn_kmsg_work *)_work;
network_request_t *req = work->msg;
int ret = 0;
PSPRINTK("%s: exe_path %s\n", __func__, req->exe_path);
ret = do_execve(getname_kernel(req->exe_path), NULL, NULL);
PSPRINTK("%s: filename %p\n", __func__, getname_kernel(req->exe_path));
PSPRINTK("%s: ret %d\n", __func__, ret);
}
static int handle_network_request(struct pcn_kmsg_message *msg)
{
network_request_t *req = (network_request_t *)msg;
struct pcn_kmsg_work *work = kmalloc(sizeof(*work), GFP_ATOMIC);
BUG_ON(!work);
work->msg = req;
INIT_WORK((struct work_struct *)work, clone_thread);
queue_work(pcn_wq, (struct work_struct *)work);
return 0;
}
... ...
然后我尝试在内核线程中调用do_execve
。但是由于某些原因,内核线程只执行printk
,从不执行do_execve
。
所以我想知道如何在 Linux 内核中执行 ELF?谢谢。
为此您应该使用 call_usermodehelper()
内部内核 API:
#include <linux/kmod.h>
/* ... */
{
char ∗argv[] = { req->exe_path, NULL };
static char ∗envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_EXEC );
}
在我看来,您的 struct pcn_kmsg_message
可能在工作队列运行之前被释放 - 您可能需要将 exe_path
字符串复制到 pcn_kmsg_work
结构中,而不仅仅是复制指针。