【问题标题】:Executing an ELF in Linux kernel with workqueue or kthread在 Linux 内核中使用 workqueue 或 kthread 执行 ELF
【发布时间】:2019-09-20 13:07:06
【问题描述】:

当接收到网络消息时,我正在尝试在内核中启动用户空间进程(执行 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?谢谢。

【问题讨论】:

    标签: c linux-kernel elf


    【解决方案1】:

    您应该为此使用 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 结构中,而不仅仅是复制指针。

    【讨论】:

    • 当我用您提供的代码替换 do_execve 时,它可以工作。但我不认为内核恐慌是由req-&gt;exe_path 被释放引起的。我在call_usermodehelper 中使用过,效果很好。我还用字符串和do_execve 替换了req-&gt;exe_path,它也有故障。我猜在工作队列中执行do_execve 时可能有问题。
    • 是的,do_execve() 将当前线程替换为新执行的线程,因此您绝对不想在工作队列中这样做。
    猜你喜欢
    • 2015-02-19
    • 1970-01-01
    • 2011-07-04
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-20
    相关资源
    最近更新 更多