zoukankan      html  css  js  c++  java
  • call_usermodehelper内核中运行用户应用程序

    init是用户空间第一个程序,在调用init前程序都运行在内核态,之后运行init时程序运行到用户态。

    操作系统上,一些内核线程在内核态运行,它们永远不会进入用户态。它们也根本没有用户态的内存空间。它的线性地址空间就是共享内核的线性地址空间。一些用户进程通常在用户态运行。有时因为系统调用而进入内核态,调用内核提供的系统调用处理函数。

    但有时,我们的内核模块或者内核线程希望能够调用用户空间的进程,就像系统启动之初init_post函数做的那样。

    如,一个驱动从内核得到了主从设备号,然后需要使用mknod命令创建相应的设备文件,以供用户调用该设备。

    如,一个内核线程想神不知鬼不觉地偷偷运行个有特权的后门程序。

    等等之类的需求。

    linux kernel提供了call_usermodehelper,用于内核中直接新建和运行用户空间程序,并且该程序具有root权限。

    函数原型

    call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait);
    enum umh_wait {
        UMH_NO_WAIT = -1,       /* don't wait at all */
        UMH_WAIT_EXEC = 0,      /* wait for the exec, but not the process */
        UMH_WAIT_PROC = 1,      /* wait for the process to complete */
     };

    默认为UMH_WAIT_EXEC,内核exec用户空间进程后就退出;UMH_WAIT_PROC会一直等到用户空间进程结束为止。

    call_usermodehelper函数的参数用法和execve函数一致,

    argv是字符串数组,是将被传输到新程序的参数。

    envp是字符串数组,格式是key=value,是传递给新程序的环境变量。

    argv和envp都必须以NULL字符串结束。以此来实现对字符串数组的大小统计。

    这就意味着,argv的第一个参数也必须是程序名。也就是说,新程序名要在execve函数的参数中传递两次。

    函数原理

    call_usermodehelper()执行之后会在工作队列khelper_wq中加入一个工作线程__call_usermodehelper, 这个工作队列上的线程运行之后,会根据wait的类型,调用kernel_thread启用相应类型的线程wait_for_helper()或者 ____call_usermodehelper(),之所以调用kernel_thread生成新的线程,目的在于让并行运行实现最大化,充分利用 cpu.
    部分代码如下:
    if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
    pid = kernel_thread(wait_for_helper, sub_info,
                     CLONE_FS | CLONE_FILES | SIGCHLD);
    else
    pid = kernel_thread(____call_usermodehelper, sub_info,
                     CLONE_VFORK | SIGCHLD);
    线程wait_for_helper()或者____call_usermodehelper()最终调用kernel_execve()启动用户空间的应用程序,并把参数传给该应用程序,如:"/sbin/hotplug",由此可知call_usermodehelper()是内核驱动程序向外界应用程序程序传递内核信息的好手段,但是因为内核驱动会产生相当多的hotplug事件,所以后来就使用"/sbin/udevsend"临时代替,到了2.6.15内核之后,高效的netlink广播接口开始被采用,逐渐取代"/sbin/hotplug""/sbin/udevsend"的部分角色,成为一个新亮点,悄悄地登上了历史舞台。

    使用示例

    驱动中实现调用。

        #include <linux/init.h>  
        #include <linux/module.h>  
        #include <linux/moduleparam.h>  
        #include <linux/kernel.h>  
        #include <linux/sched.h>  
          
        MODULE_LICENSE("DualBSD/GPL");  
          
        static __init int hello_init(void)  
        {  
                int result = 0;  
                char cmd_path[] = "/usr/bin/touch";  
                char *cmd_argv[] = {cmd_path, "/home/yu/test.txt", NULL};  
                char *cmd_envp[] = {"HOME=/", "PATH=/sbin:/bin:/user/bin", NULL};  
          
                result = call_usermodehelper(cmd_path, cmd_argv, cmd_envp, UMH_WAIT_PROC);  
                printk(KERN_DEBUG"THe result of call_usermodehelper is %d
    ", result);  
                return result;  
        }  
          
          
        static __exit void hello_exit(void)  
        {  
                int result = 0;  
                char cmd_path[] = "/bin/rm";  
                char *cmd_argv[] = {cmd_path, "/home/yu/test.txt", NULL};  
                char *cmd_envp[] = {"HOME=/", "PATH=/sbin:/bin:/user/bin", NULL};  
          
                result = call_usermodehelper(cmd_path, cmd_argv, cmd_envp,  
                                UMH_WAIT_PROC);  
                printk(KERN_DEBUG"THe result of call_usermodehelper is %d
    ", result);  
        }  
          
        module_init(hello_init);  
        module_exit(hello_exit);  
        obj-m := hello.o  
        KDIR := /lib/modules/$(shell uname -r)/build  
        PWD := $(shell pwd)  
        default:  
                $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules  
        clean:  
                rm -rf *.o *.ko *.mod* *.order *.sym*  

     

    参考:

    1. 使用call_usermodehelper在Linux内核中直接运行用户空间程序

    2. Linux call_usermodehelper()

    3. Invoking user-space applications from the kernel(IBM)

  • 相关阅读:
    大数据量分表时 两个表查询比较快的方式
    开启SQL Server执行占用时间显示和逻辑读取次数显示
    【转】SQL Server海量数据库的索引、查询优化及分页算法
    Exchange无法发送邮件 未找到匹配的连接器来路由外部收件人解决办法
    HTML介绍&常用的标签
    关于HTML文件、JS文件、CSS文件
    python命名空间和作用域
    pymysql
    存储过程、视图、触发器、函数
    多表查询
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/7439984.html
Copyright © 2011-2022 走看看