【问题标题】:How to trigger a kernel module from shell?如何从 shell 触发内核模块?
【发布时间】:2015-12-09 05:40:47
【问题描述】:

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

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

setuid(0);

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

感谢您的帮助。

【问题讨论】:

  • 你遇到了什么问题?你不明白什么? modprobeinsmod 是 shell 内置函数,而不是系统调用。
  • 我尝试使用 system("/sbin/insmod /.../mymodule.ko");但它没有用。我的意思是它没有成功加载我的内核模块。
  • 你用过root吗?尝试在 shell 中加载它,看看会发生什么。
  • 不明白你说的root是什么意思?如果您问我是否尝试过“sudo”命令,我尝试过。 system("/usr/bin/sudo /sbin/insmod ./.../mymodule.ko");但它也没有用。
  • 没有。这可能会要求您输入密码。你需要用 sudo 运行你的问题。 sudo ./your_program。并摆脱内部的。

标签: c linux linux-kernel kernel-module


【解决方案1】:

使用system()加载模块

您正试图在您的应用程序中成为 root(通过执行 setuid(0)),但您没有这样做的权限(如果您以普通用户身份运行您的程序)。相反,您应该检查您的程序是否从根目录运行(使用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. 第二个命令运行您的程序。

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

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

使用finit_module()加载模块

在 C 中使用 system() 函数通常被认为是一种不好的做法(因为它需要很长时间才能执行,而且基本上只是试图替换一个更简单的 Bash 脚本)。

如果你想在 C 中加载内核模块而不使用 system(),你可以查看 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;
}

【讨论】:

    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多