执行/调用用户空间程序,并从内核模块获取其 pid [英] Execute/invoke user-space program, and get its pid, from a kernel module

查看:15
本文介绍了执行/调用用户空间程序,并从内核模块获取其 pid的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我查看了 内核 API,第 1 部分:调用用户 -来自内核的空间应用程序,以及执行用户- 来自内核空间的空间函数 - 堆栈溢出 - 这是一个小的内核模块,callmodule.c,证明:

//http://people.ee.ethz.ch/~arkeller/linux/code/usermodehelper.c#include #include #include #include #include 静态 int __init callmodule_init(void){int ret = 0;char userprog[] = "/path/to/mytest";char *argv[] = {userprog, "2", NULL };char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };printk("callmodule: init %s
", userprog);/* 最后一个参数:1 ->等待直到执行完成,0 不等待*//* 如果用户模式进程启动成功,则返回 0,否则返回错误值 *//* 不可能得到用户态进程的返回值*/ret = call_usermodehelper(userprog, argv, envp, UMH_WAIT_EXEC);如果(返回!= 0)printk("调用usermodehelper时出错:%i
", ret);别的printk("一切正常
");返回0;}静态无效 __exit callmodule_exit(void){printk("调用模块:退出
");}模块初始化(调用模块初始化);模块退出(调用模块退出);MODULE_LICENSE("GPL");

... 使用 Makefile:

obj-m += callmodule.o全部:make -C/lib/modules/$(shell uname -r)/build M=$(PWD) 模块干净的:make -C/lib/modules/$(shell uname -r)/build M=$(PWD) clean

当我通过 sudo insmod ./callmodule.ko && 运行它时sudo rmmod callmodule,我进入/var/log/syslog:

2 月 10 日 00:42:45 mypc 内核:[71455.260355] callmodule:init/path/to/mytest2 月 10 日 00:42:45 mypc 内核:[71455.261218] 一切正常2 月 10 日 00:42:45 mypc 内核:[71455.286131] callmodule:退出

...这显然意味着一切顺利.(使用 Linux 2.6.38-16-generic #67-Ubuntu SMP)

我的问题是 - 如何获得从内核模块实例化的进程的 PID?除了 call_usermodehelper 之外,还有没有类似的进程可以让我在内核空间实例化一个用户空间进程,并获取它的 pid?

<小时>

请注意,可能无法使用 call_usermodehelper 并获取实例化的进程 PID:

Re:call_usermodehelper 的 pid ?— Linux 内核新手

<块引用><块引用><块引用>

我想从内部创建一个用户空间进程一个内核模块,并能够杀死它,发送信号到它,等等...

我可以知道它的pid吗?

不,你不能.但由于在实现内部,pid 是已知的,使其可用的补丁不会太难(注意,错误内核中始终为负,pid 为正,限制为 2**16).不过,您必须修改所有期望成功为 0 的调用方.

我查了一下资料,似乎最终有一个调用链:call_usermodehelper -> call_usermodehelper_setup -> __call_usermodehelper,看起来像:

static void __call_usermodehelper(struct work_struct *work){struct subprocess_info *sub_info =container_of(work, struct subprocess_info, work);//...如果(等待 == UMH_WAIT_PROC)pid = kernel_thread(wait_for_helper, sub_info,CLONE_FS |CLONE_FILES |SIGCHLD);别的pid = kernel_thread(____call_usermodehelper, sub_info,CLONE_VFORK |SIGCHLD);...

... 所以使用了内核线程的PID,但它没有保存在任何地方;此外,work_structsubprocess_info 都没有 pid 字段(task_struct 有,但这里似乎没有使用 task_struct).记录这个 pid 需要更改内核源代码 - 因为我想避免这种情况,这就是为什么我也对 call_usermodehelper 以外的方法感兴趣的原因 ...

解决方案

根据我对 kmod.c.

如果你查看call_usermodehelper的代码,你会看到它调用了call_usermodehelper_setup,然后是call_usermodehelper_exec.

call_usermodehelper_setup 将一个 init 函数作为参数,该函数将在 do_execve 之前执行.我相信当 init 函数被执行时 current 的值会让你得到用户进程的 task_struct.

所以要获得pid,您需要:

  1. 在您的代码中复制 call_usermodehelper 的实现.
  2. 定义将作为参数传递给 call_usermodehelper_setup 的 init 函数.
  3. 在 init 函数中检索当前的 task_struct 并依次获取 PID.

I checked out Kernel APIs, Part 1: Invoking user - space applications from the kernel, and Executing a user-space function from the kernel space - Stack Overflow - and here is a small kernel module, callmodule.c, demonstrating that:

// http://people.ee.ethz.ch/~arkeller/linux/code/usermodehelper.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

static int __init callmodule_init(void)
{
    int ret = 0;
    char userprog[] = "/path/to/mytest";
    char *argv[] = {userprog, "2", NULL };
    char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };

    printk("callmodule: init %s
", userprog);
    /* last parameter: 1 -> wait until execution has finished, 0 go ahead without waiting*/
    /* returns 0 if usermode process was started successfully, errorvalue otherwise*/
    /* no possiblity to get return value of usermode process*/
    ret = call_usermodehelper(userprog, argv, envp, UMH_WAIT_EXEC);
    if (ret != 0)
        printk("error in call to usermodehelper: %i
", ret);
    else
        printk("everything all right
");
        return 0;
}

static void __exit callmodule_exit(void)
{
    printk("callmodule: exit
");
}

module_init(callmodule_init);
module_exit(callmodule_exit);
MODULE_LICENSE("GPL");

... with Makefile:

obj-m += callmodule.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

When I run this via sudo insmod ./callmodule.ko && sudo rmmod callmodule, I get in /var/log/syslog:

Feb 10 00:42:45 mypc kernel: [71455.260355] callmodule: init /path/to/mytest
Feb 10 00:42:45 mypc kernel: [71455.261218] everything all right
Feb 10 00:42:45 mypc kernel: [71455.286131] callmodule: exit

... which apparently means all went fine. (Using Linux 2.6.38-16-generic #67-Ubuntu SMP)

My question is - how can I get the PID of the process instantiated from a kernel module? Is there a similar process other than call_usermodehelper, that will allow me to instantiate a user-space process in kernel space, and obtain its pid?


Note that it may not be possible to use call_usermodehelper and get the instantiated process PID:

Re: call_usermodehelper's pid ? — Linux Kernel Newbies

I want to create a user space process from within a kernel module, and be able to kill it, send signals to it, etc...

can I know its pid ?

No, you can't. But since inside the implementation the pid is known, patch that makes it available would not be too hard (note, that errors are always negative in kernel and pids are positive, limited to 2**16). You would have to modify all callers that expect 0 on success though.

I poked around the sources a bit, and it seems ultimately there is a call chain: call_usermodehelper -> call_usermodehelper_setup -> __call_usermodehelper, which looks like:

static void __call_usermodehelper(struct work_struct *work)
{
    struct subprocess_info *sub_info =
        container_of(work, struct subprocess_info, work);
    // ...
    if (wait == UMH_WAIT_PROC)
        pid = kernel_thread(wait_for_helper, sub_info,
                    CLONE_FS | CLONE_FILES | SIGCHLD);
    else
        pid = kernel_thread(____call_usermodehelper, sub_info,
                    CLONE_VFORK | SIGCHLD);
...

... so a PID of a kernel thread is used, but it is saved nowhere; also, neither work_struct nor subprocess_info have a pid field (task_struct does, but nothing here seems to use task_struct). Recording this pid would require changing the kernel sources - and as I'd like to avoid that, this is the reason why I'm also interested in approaches other than call_usermodehelper ...

解决方案

A tentative answer from my understanding of the implementation in kmod.c.

If you look at the code of call_usermodehelper you will see it calls call_usermodehelper_setup and then call_usermodehelper_exec.

call_usermodehelper_setup takes as parameter an init function that will be executed just before the do_execve. I believe the value of current when the init function gets executed will get you the task_struct of the user process.

So to get the pid you will need to:

  1. Copy the implementation of call_usermodehelper in your code.
  2. Define an init function that you will pass as parameter to call_usermodehelper_setup.
  3. In the init function retrieves the current task_struct and in turn the PID.

这篇关于执行/调用用户空间程序,并从内核模块获取其 pid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆