INIT_MODULE - Linux手册页

Linux程序员手册 第2部分
更新日期: 2017-09-15

备注

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

Glibc不为finit_module()提供包装。使用syscall(2)调用它。

关于当前加载的模块的信息可以在/ proc / modules和/ sys / module下每个模块子目录下的文件树中找到。

有关一些有用的背景信息,请参见Linux内核源文件include / linux / module.h。

Linux 2.4 and earlier

在Linux 2.4和更早版本中,init_module()系统调用非常不同:

#包括

int init_module(const char 名称,结构模块image);

(用户空间应用程序可以通过调用query_module()来检测init_module()的哪个版本可用;在Linux 2.6和更高版本上,后一个调用失败,并显示错误ENOSYS。)

较旧的系统调用版本将映像所指向的重定位模块映像加载到内核空间中,并运行模块的init函数。调用者负责提供重定位的映像(从Linux 2.6开始,init_module()系统调用进行重定位)。

模块映像以模块结构开始,并在适当时跟随代码和数据。从Linux 2.2开始,模块结构定义如下:

struct module {
    unsigned long         size_of_struct;
    struct module        *next;
    const char           *name;
    unsigned long         size;
    long                  usecount;
    unsigned long         flags;
    unsigned int          nsyms;
    unsigned int          ndeps;
    struct module_symbol *syms;
    struct module_ref    *deps;
    struct module_ref    *refs;
    int                 (*init)(void);
    void                (*cleanup)(void);
    const struct exception_table_entry *ex_table_start;
    const struct exception_table_entry *ex_table_end;
#ifdef __alpha__
    unsigned long gp;
#endif
};

除next和refs外,所有指针字段均应指向模块主体内,并根据内核空间进行适当的初始化,即与模块的其余部分一起重定位。

语法

int init_module(void *module_image, unsigned long len,
                const char *param_values);

int finit_module(int fd, const char *param_values,
                 int flags);

注意:glibc没有提供init_module()的头文件声明,也没有为finit_module()提供包装函数。请参阅注释。

遵循规范

init_module()和finit_module()特定于Linux。

另外参见

create_module(2),delete_module(2),query_module(2),lsmod(8),modprobe(8)

名称

init_module,finit_module-加载内核模块

说明

init_module()将ELF映像加载到内核空间中,执行任何必要的符号重定位,将模块参数初始化为调用方提供的值,然后运行模块的init函数。此系统调用需要特权。

module_image参数指向包含要加载的二进制图像的缓冲区; len指定该缓冲区的大小。模块映像应该是为正在运行的内核构建的有效ELF映像。

param_values参数是一个字符串,其中包含模块参数值的空格分隔规范(使用module_param()和module_param_array()在模块内部定义)。内核解析该字符串并初始化指定的参数。每个参数规范都具有以下形式:

名称[=值[,值...]]

参数名称是使用module_param()在模块内定义的名称之一(请参阅Linux内核源文件include / linux / moduleparam.h)。对于bool和invbool参数,参数值是可选的。数组参数的值指定为逗号分隔的列表。

finit_module()

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

flags参数修改finit_module()的操作。它是通过对以下零个或多个标志进行"或"运算而创建的位掩码值:

MODULE_INIT_IGNORE_MODVERSIONS
忽略符号版本哈希。
MODULE_INIT_IGNORE_VERMAGIC
忽略内核版本魔术。

模块中内置了一些安全检查,以确保其与加载该模块的内核匹配。这些检查在构建模块时记录,并在加载模块时进行验证。首先,模块记录一个" vermagic"字符串,其中包含内核版本号和突出的功能(例如CPU类型)。其次,如果模块是在启用CONFIG_MODVERSIONS配置选项的情况下构建的,则将为模块使用的每个符号记录版本哈希。该哈希基于符号类型的参数的类型和返回值。在这种情况下," vermagic"字符串中的内核版本号将被忽略,因为假定符号版本哈希是足够可靠的。

使用MODULE_INIT_IGNORE_VERMAGIC标志指示将忽略" vermagic"字符串,而MODULE_INIT_IGNORE_MODVERSIONS标志指示将忽略符号版本哈希。如果将内核构建为允许强制加载(即使用CONFIG_MODULE_FORCE_LOAD配置),则加载将继续进行,否则将失败,并出现错误ENOEXEC,这是格式错误的模块所期望的。

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

错误说明

EBADMSG(since Linux 3.7)
模块签名格式错误。
EBUSY
尝试解决此模块的符号引用时超时。
EFAULT
地址自变量引用的位置在进程的可访问地址空间之外。
ENOKEY(since Linux 3.7)
模块签名无效或内核没有该模块的密钥。仅当内核配置了CONFIG_MODULE_SIG_FORCE时,才返回此错误。如果内核未配置此选项,则无效或未签名的模块只会污染内核。
ENOMEM
内存不足。
EPERM
调用方没有特权(没有CAP_SYS_MODULE功能),或者模块加载被禁用(请参见proc(5)中的/ proc / sys / kernel / modules_disabled)。

对于init_module(),可能还会发生以下错误:

EEXIST
具有该名称的模块已经加载。
EINVAL
param_values无效,或module_image中ELF图像的某些部分包含不一致之处。
ENOEXEC
module_image中提供的二进制映像不是ELF映像,或者是无效的或用于其他体系结构的ELF映像。

对于finit_module(),可能还会发生以下错误:

EBADF
fd引用的文件未打开以供读取。
EFBIG
fd引用的文件太大。
EINVAL
标志无效。
ENOEXEC
fd不引用打开的文件。

除上述错误外,如果执行模块的init函数并返回错误,则init_module()或finit_module()失败,并且errno设置为init函数返回的值。

版本

从Linux 3.8开始,finit_module()可用。

返回值

成功时,这些系统调用将返回0。错误时,将返回-1并正确设置errno。

日期:2019-08-20 17:58:43 来源:oir作者:oir