执行/调用用户空间程序,并从内核模块获取其 pid [英] Execute/invoke user-space program, and get its pid, from a kernel module
问题描述
我查看了 内核 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_struct
和 subprocess_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,您需要:
- 在您的代码中复制
call_usermodehelper
的实现. - 定义将作为参数传递给
call_usermodehelper_setup
的 init 函数. - 在 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:
- Copy the implementation of
call_usermodehelper
in your code. - Define an init function that you will pass as parameter to
call_usermodehelper_setup
. - In the init function retrieves the current
task_struct
and in turn the PID.
这篇关于执行/调用用户空间程序,并从内核模块获取其 pid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!