call_usermodehelper()函数分析(内核态调用用户态函数)

如何在Linux内核中执行某些用户态程序或系统命令?在用户态中,可以通过execve()实现;在内核态,则可以通过call_usermodehelpere()实现该功能。如果您查阅了call_usermodehelper()内核函数的源码实现,就可以发现该函数最终会执行do_execve()。而execve系统调用在经历内核的系统调用流程后,也会最终调用do_execve()。

 

代码实例

1 内核态调用用户态reboot命令

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

 

static int __init test_init(void){

int ret=-1;

char path[]="/sbin/reboot";

char *argv[]={path,NULL};

char *envp[]={NULL};

printk("call_usermodehelper module isstarting..!\n");

ret = call_usermodehelper(path, argv, envp,UMH_WAIT_PROC);

printk("ret=%d\n", ret);

return 0;

}

static void __exit test_exit(void){

}

 

module_init(test_init);

module_exit(test_exit);

 

MODULE_LICENSE("GPL");

 call_usermodehelper()函数分析(内核态调用用户态函数)

call_usermodehelper()函数分析(内核态调用用户态函数)

 

2 内核态调用用户态mkdir|rm命令

1、无输出的可执行文件测试

 

加载函数demo如下所示:

 

       static int__init call_usermodehelper_init(void)

       {

           int ret = -1;

           char path[] = "/bin/mkdir";

           char *argv[] = {path, "-p","/home/tester/new/new_dir", NULL};

        

           printk("call_usermodehelper module isstarting..!\n");

           ret = call_usermodehelper(path, argv, envp,UMH_WAIT_PROC);

           printk("ret=%d\n", ret);

           return 0;

       }

卸载函数demo如下所示:

 

       static void__exit call_usermodehelper_exit(void)

       {

           int ret = -1;

           char path[] = "/bin/rm";

           char *argv[] = {path, "-r","/home/tester/new", NULL};

           char *envp[] = {NULL};

        

           printk("call_usermodehelper module isstarting..!\n");

           ret = call_usermodehelper(path, argv, envp,UMH_WAIT_PROC);

           printk("ret=%d\n", ret);

       }

 

2、有输出的可执行文件测试

 

如果该可执行文件有输出,则可以利用输出重定向,不过此时的可执行文件应该是/bin/bash,而实际的可执行文件则称为bash的参数。比如如果想在内核执行ls -la命令,并且将其输出重定向到ls_output中,则在上述的argv[]={“/bin/bash”, “-c”, “ls”, “-la”, “>”,“/home/tester/ls_output”, NULL};

 

本文虽然说明的是在内核态如何调用用户态程序,不过可以将这种方法抽象一下,看作是内核态主动向用户态发起通信的一种方式。