29. init_module - 加载内核模块 Link to heading
函数介绍 Link to heading
init_module
系统调用用于将编译好的内核模块加载到内核空间中。它是现代Linux系统中加载内核模块的核心系统调用。
函数原型 Link to heading
#include <linux/module.h>
#include <sys/syscall.h>
int init_module(void *module_image, unsigned long len, const char *param_values);
功能 Link to heading
将内核模块映像加载到内核并初始化模块。
参数 Link to heading
void *module_image
: 指向模块二进制映像的指针unsigned long len
: 模块映像的长度(字节)const char *param_values
: 模块参数字符串(如"name=value")
返回值 Link to heading
- 成功时返回0
- 失败时返回-1,并设置errno
特殊限制 Link to heading
- 需要root权限或CAP_SYS_MODULE能力
- 模块必须与内核版本匹配
- 模块签名验证(如果启用)
- 不能加载已存在的同名模块
相似函数 Link to heading
finit_module()
: 通过文件描述符加载模块delete_module()
: 卸载内核模块- 命令行工具
insmod
示例代码 Link to heading
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <linux/module.h>
// init_module系统调用包装
static inline long init_module_wrapper(void *module_image, unsigned long len,
const char *param_values) {
return syscall(__NR_init_module, module_image, len, param_values);
}
// finit_module系统调用包装
static inline long finit_module_wrapper(int fd, const char *param_values, int flags) {
return syscall(__NR_finit_module, fd, param_values, flags);
}
int main() {
printf("=== Init_module函数示例 ===\n");
// 示例1: 基本使用说明
printf("示例1: 基本使用说明\n");
printf("注意:需要root权限才能加载内核模块\n");
printf("普通用户应使用insmod命令\n\n");
// 示例2: 错误处理演示
printf("示例2: 错误处理演示\n");
// 尝试加载无效模块
if (init_module_wrapper(NULL, 0, "") == -1) {
printf("加载无效模块: %s\n", strerror(errno));
// 通常返回EINVAL(参数无效)
}
// 尝试加载不存在的模块文件
int fd = open("/nonexistent/module.ko", O_RDONLY);
if (fd == -1) {
printf("打开模块文件失败: %s\n", strerror(errno));
}
// 示例3: 常见错误类型
printf("示例3: 常见错误类型\n");
printf("init_module可能的错误:\n");
printf("- EPERM: 权限不足(需要root或CAP_SYS_MODULE)\n");
printf("- EINVAL: 参数无效或模块映像损坏\n");
printf("- ENOENT: 模块文件不存在\n");
printf("- EEXIST: 同名模块已加载\n");
printf("- ENOMEM: 内存不足\n");
printf("- EFAULT: 指针地址无效\n");
printf("- ENOEXEC: 模块格式不正确\n\n");
// 示例4: 模块参数传递
printf("示例4: 模块参数传递\n");
printf("模块参数格式示例:\n");
printf("- \"debug=1\": 设置debug参数为1\n");
printf("- \"name=value size=1024\": 多个参数\n");
printf("- \"\": 空参数字符串\n\n");
// 示例5: finit_module vs init_module
printf("示例5: finit_module vs init_module\n");
printf("init_module: 传入内存中的模块映像\n");
printf("finit_module: 通过文件描述符加载模块\n");
printf("finit_module优势: 避免大内存分配\n\n");
// 示例6: 安全考虑
printf("示例6: 安全考虑\n");
printf("安全使用建议:\n");
printf("1. 确保有足够的权限\n");
printf("2. 验证模块来源可信\n");
printf("3. 检查模块与内核版本兼容性\n");
printf("4. 生产环境建议使用modprobe命令\n\n");
// 示例7: 实际使用场景
printf("示例7: 实际使用场景\n");
printf("系统管理员加载驱动模块:\n");
printf("// 1. 读取模块文件到内存\n");
printf("// 2. 调用init_module加载\n");
printf("// 3. 验证加载结果\n\n");
// 演示检查模块状态的方法
printf("检查模块状态的方法:\n");
printf("- 查看/proc/modules文件\n");
printf("- 使用lsmod命令\n");
printf("- 检查/sys/module/目录\n\n");
return 0;
}