栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何从C代码加载Linux内核模块?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何从C代码加载Linux内核模块?

最小的可运行示例

使用此简单的参数打印机模块,在QEMU
+ Buildroot VM和Ubuntu 16.04主机上进行了测试。

我们使用

init_module
/
finit_module
remove_module

Linux系统调用。

Linux内核为模块插入提供了两个系统调用:

  • init_module
  • finit_module

和:

man init_module

证明文件:

系统调用finit_module()类似于init_module(),但是从文件描述符fd中读取要加载的模块。当可以从内核模块在文件系统中的位置确定内核模块的真实性时,它很有用;在可能的情况下,可以避免使用经过密码签名的模块来确定模块的真实性的开销。param_values参数与init_module()相同。

finit
是较新的版本,仅在v3.8中添加。更多理由:https :
//lwn.net/Articles/519010/

glibc似乎没有为他们提供C包装器,因此我们仅使用创建自己的

syscall

insmod.c

#define _GNU_SOURCE#include <fcntl.h>#include <stdio.h>#include <sys/stat.h>#include <sys/syscall.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)int main(int argc, char **argv) {    const char *params;    int fd, use_finit;    size_t image_size;    struct stat st;    void *image;        if (argc < 2) {        puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");        return EXIT_FAILURE;    }    if (argc < 3) {        params = "";    } else {        params = argv[2];    }    if (argc < 4) {        use_finit = 0;    } else {        use_finit = (argv[3][0] != '0');    }        fd = open(argv[1], O_RDONLY);    if (use_finit) {        puts("finit");        if (finit_module(fd, params, 0) != 0) { perror("finit_module"); return EXIT_FAILURE;        }        close(fd);    } else {        puts("init");        fstat(fd, &st);        image_size = st.st_size;        image = malloc(image_size);        read(fd, image, image_size);        close(fd);        if (init_module(image, image_size, params) != 0) { perror("init_module"); return EXIT_FAILURE;        }        free(image);    }    return EXIT_SUCCESS;}

GitHub上游。

rmmod.c

#define _GNU_SOURCE#include <fcntl.h>#include <stdio.h>#include <sys/stat.h>#include <sys/syscall.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)int main(int argc, char **argv) {    if (argc != 2) {        puts("Usage ./prog mymodule");        return EXIT_FAILURE;    }    if (delete_module(argv[1], O_NONBLOCK) != 0) {        perror("delete_module");        return EXIT_FAILURE;    }    return EXIT_SUCCESS;}

GitHub上游。

Busybox源码解释

Busybox提供了

insmod
,并且由于它是为极简主义而设计的,因此我们可以尝试从那里推断出它是如何完成的。

在版本1.24.2中,入口点位于

modutils/insmod.c
function上
insmod_main

IF_FEATURE_2_4_MODULES
是对老年人的Linux内核2.4模块可选支持,所以我们就可以忽略它。

这只是

modutils.c
功能
bb_init_module

bb_init_module
尝试两件事:

  • mmap
    该文件通过进入内存
    try_to_mmap_module

这总是设置

image_size
.ko
文件的大小,这是一个副作用。

  • 如果失败,则使用
    malloc
    将文件保存到内存
    xmalloc_open_zipped_read_close

如果该文件是zip,则此函数可以选择先解压缩文件,否则仅对malloc进行解压缩。

我不明白为什么要执行此压缩业务,因为我们甚至不能依靠它,因为

try_to_mmap_module
似乎无法解压缩。

终于来了电话:

init_module(image, image_size, options);

image
放在内存中的可执行文件在哪里,而选项就像
""
我们在调用时
insmod file.elf
不带其他参数的情况一样。

init_module
由以上提供:

#ifdef __UCLIBC__extern int init_module(void *module, unsigned long len, const char *options);extern int delete_module(const char *module, unsigned int flags);#else# include <sys/syscall.h># define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)#endif

ulibc
是嵌入式libc实现,它似乎提供
init_module

如果它不存在,我认为是glibc,但是

man init_module
说:

glibc不支持init_module()系统调用。glibc标头中未提供任何声明,但经过一段古怪的历史,glibc确实为此系统调用导出了一个ABI。因此,为了使用此系统调用,在代码中手动声明接口就足够了。或者,您可以使用syscall(2)调用系统调用。

明智地使用BusyBox的建议并使用

syscall
glibc提供的建议和使用,并为系统调用提供C API。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/408783.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号