如何从shell触发内核模块?

时间:2015-03-21 14:17:43

标签: c linux linux-kernel kernel-module

我正在使用Ubuntu和VirtualBox。 我正在为我的shell定义一个新命令来输出子进程的一些特性(如兄弟树等)。为了输出这些特性,我创建了一个内核模块并使用了task_struct。我还测试了我的shell之外的内核模块,它可以工作。 现在我的问题是如何在我的shell中触发这个内核模块(在C代码中),以便加载我的内核模块?

我搜索并发现我需要使用modprobe或insmod等系统调用,但不知道如何使用它们。我尝试了下面的代码,但它不起作用:

  

的setuid(0);

     

system(“/ sbin / insmod /.../ mymodule.ko”);

感谢您的帮助。

1 个答案:

答案 0 :(得分:8)

使用system()

加载模块

您正试图在应用程序中成为 root (通过执行setuid(0)),但您没有权限(如果您以常规用户身份运行程序)。相反,您应该检查您的程序是否从root运行(使用getuid())。此外,最好测试您的模块文件是否存在。以下是此类代码的示例(经过测试并需要进行所有检查):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

#define ROOT_UID    0
#define INSMOD_PATH "/sbin/insmod"
#define MOD_PATH    "/.../mymodule.ko"

int main(void)
{
    uid_t uid;
    int res;

    /* Check if program being run by root */
    uid = getuid();
    if (uid != ROOT_UID) {
        fprintf(stderr, "Error: Please run this program as root\n");
        return EXIT_FAILURE;
    }

    /* Check if module file exists */
    if (access(MOD_PATH, F_OK) == -1) {
        fprintf(stderr, "Error: File \"%s\" doesn't exist\n", MOD_PATH);
        return EXIT_FAILURE;
    }

    /* Load module */
    res = system(INSMOD_PATH " " MOD_PATH);
    if (res != 0) {
        fprintf(stderr, "Error loading module: %d\n", res);
        return EXIT_FAILURE;
    }

    printf("Module \"%s\" was successfully loaded\n", MOD_PATH);

    return EXIT_SUCCESS;
}

将此代码保存为main.c文件。请务必将MOD_PATH定义替换为模块文件的实际路径。

使用下一个命令编译它:

$ gcc -Wall -O2 main.c -o load_module

现在进行下一步:

$ su
# ./load_module
  1. 第一个命令将用户切换为 root (系统会要求您输入root密码)。如果您不知道 root 密码,请尝试使用sudo -s命令而不是su
  2. 第二个命令运行您的程序。
  3. 请注意命令提示符下的最后一个字符:

    • #表示您此时拥有 root 权限
    • $表示您只拥有常规用户权限。

    使用finit_module()

    加载模块

    在C中使用system()函数通常被认为是一种不好的做法(因为它需要花费大量时间来执行,而且基本上只是尝试替换更简单的Bash脚本)。

    如果要在不使用system()的情况下在C中加载内核模块,可以查看insmod工具的源代码。请参阅libkmod/libkmod-module.c文件,kmod_module_insert_module()功能。您可以看到这些来源here

    注意finit_module()函数调用。有关此system call的详细说明,请参见手册页:

    $ man finit_module
    

    以下是如何使用finit_module()系统调用的示例:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/syscall.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define ROOT_UID    0
    #define MOD_PATH    "/.../mymodule.ko"
    
    static inline int finit_module(int fd, const char *uargs, int flags)
    {
        return syscall(__NR_finit_module, fd, uargs, flags);
    }
    
    int main(void)
    {
        uid_t uid;
        long res;
        int fd;
    
        /* Check if program being run by root */
        uid = getuid();
        if (uid != ROOT_UID) {
            fprintf(stderr, "Error: Please run this program as root\n");
            return EXIT_FAILURE;
        }
    
        /* Check if module file exists */
        if (access(MOD_PATH, F_OK) == -1) {
            fprintf(stderr, "Error: File \"%s\" doesn't exist\n", MOD_PATH);
            return EXIT_FAILURE;
        }
    
        /* Load module */
        fd = open(MOD_PATH, O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
            perror("Unable to open module file");
            return EXIT_FAILURE;
        }
        res = finit_module(fd, "", 0);
        if (res != 0) {
            perror("Error when loading module");
            close(fd);
            return EXIT_FAILURE;
        }
        close(fd);
    
        printf("Module \"%s\" was successfully loaded\n", MOD_PATH);
    
        return EXIT_SUCCESS;
    }