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

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

问题描述

我检查了内核API,第1部分:调用用户 - 空间从内核的应用程序,并<一href=\"http://stackoverflow.com/questions/5246636/executing-a-user-space-function-from-the-kernel-space\">Executing堆栈溢出 - - 从内核空间的用户空间功能,这里是一个小的内核模块, callmodule.c ,这说明:

  // http://people.ee.ethz.ch/~arkeller/linux/$c$c/usermodehelper.c#包括LT&; Linux的/  -  module.h中GT;
#包括LT&;的Linux / kernel.h&GT;
#包括LT&; Linux的/ init.h中&GT;
#包括LT&; Linux的/ proc_fs.h&GT;
#包括LT&; ASM / uaccess.h中&GT;静态INT __init callmodule_init(无效)
{
    INT RET = 0;
    烧焦userprog [] =/路径/要/ mytest,这时
    的char * argv的[] = {userprog,2,NULL};
    的char * envp [] = {HOME = /,PATH = / sbin目录:/ usr / sbin目录:/ bin中:在/ usr / bin中,NULL};    printk的(callmodule:初始化%S \\ n,userprog);
    / *最后一个参数:1 - &GT;等到执行完毕之后,0继续前进,而无需等待* /
    / *返回0,如果用户模式进程已成功启动,否则errorvalue * /
    / *没有方法可行获取用户模式进程的返回值* /
    RET = call_usermodehelper(userprog,ARGV,envp,UM​​H_WAIT_EXEC);
    如果(RET!= 0)
        printk的(呼叫错误usermodehelper:%I \\ N,RET);
    其他
        printk的(一切都还好吗\\ n);
        返回0;
}静态无效__exit callmodule_exit(无效)
{
    printk的(callmodule:退出\\ n);
}宏module_init(callmodule_init);
宏module_exit(callmodule_exit);
MODULE_LICENSE(GPL);

...与的Makefile

  OBJ-M + = callmodule.o所有:
        使-C / lib / modules目录/ $(壳使用uname -r)/建造M = $(PWD)模块清洁:
        使-C / lib / modules目录/ $(壳使用uname -r)/建造M = $(PWD)清洁

当我通过运行这个须藤insmod的./callmodule.ko&放大器;&安培;须藤rmmod的callmodule ,我得到的/ var / log / syslog的

  2月10日零时42分45秒MYPC内核:[71455.260355] callmodule:初始化/路径/要/ mytest,这时
2月10日零时42分45秒MYPC内核:[71455.261218]一切都还好吗
2月10日零时42分45秒MYPC内核:[71455.286131] callmodule:退出

...这显然意味着一切都很好。 (使用Linux 2.6.38-16泛型#67 Ubuntu的SMP)

我的问题是 - 我怎么能得到一个内核模块实例化进程的PID?难道还有比 call_usermodehelper 其他类似的过程,这将让我实例化内核空间用户空间的过程,并获得它的PID?


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

回复:call_usermodehelper的PID? - Linux内核新手


  

    

      

我要创建一个内部用户空间程序
      一个内核模块,并能杀死它,发信号
      它,等...


      
      

我可以知道它的PID?


    
  
  
  

没有,你不能。但由于里面执行PID是已知的,
  补丁,使得它可不会太硬(注意,错误
  总是在内核消极和PID的是积极的,仅限于2 ** 16)。
  你将不得不修改成功期望0,虽然所有呼叫者。


我捅了周围的来源了一下,似乎最终还是调用链: call_usermodehelper - > call_usermodehelper_setup - > __ call_usermodehelper ,它看起来像:

 静态无效__call_usermodehelper(结构work_struct *工作)
{
    结构subprocess_info * sub_info =
        container_of(工作,结构subprocess_info,工作);
    // ...
    如果(等待== 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_struct 也不 subprocess_info 有一个 PID 字段( 的task_struct 做,但这里似乎没有任何使用的task_struct )。这个记录PID需要改变内核源代码 - 和我想避免这种情况,这是为什么我也有兴趣在比 call_usermodehelper 其他方法的原因..


解决方案

从我的 kmod.c

如果你看看的code call_usermodehelper 你会看到它调用 call_usermodehelper_setup 然后 call_usermodehelper_exec

call_usermodehelper_setup 需要为参数,将之前刚 do_execve 执行的初始化函数。我相信电流当初始化函数被执行会得到你的的task_struct 用户进程。

因此​​,为了得到你需要将PID:


  1. 复制 call_usermodehelper 的实施在code。

  2. 定义一个初始化函数,你将通过作为参数传递给 call_usermodehelper_setup

  3. 在初始化函数检索当前的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\n", 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\n", ret);
    else
        printk("everything all right\n");
        return 0;
}

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

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天全站免登陆