如何从shell触发内核模块?

cec*_*lly 3 c linux kernel-module linux-kernel

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

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

的setuid(0);

system("/ sbin/insmod /.../mymodule.ko");

谢谢您的帮助.

Sam*_*nko 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;
}
Run Code Online (Sandbox Code Playgroud)

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

使用next命令编译它:

$ gcc -Wall -O2 main.c -o load_module
Run Code Online (Sandbox Code Playgroud)

现在做下一个:

$ su
# ./load_module
Run Code Online (Sandbox Code Playgroud)
  1. 第一个命令将用户切换为root(将要求您输入root密码).如果您不知道root密码,请尝试使用sudo -s命令而不是su.
  2. 第二个命令运行您的程序.

请注意命令提示符下的最后一个字符:

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

加载模块使用 finit_module()

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

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

注意finit_module()功能调用.有关此系统调用的详细说明,参见手册页:

$ man finit_module
Run Code Online (Sandbox Code Playgroud)

以下是如何使用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;
}
Run Code Online (Sandbox Code Playgroud)