init_module(2) загружает модуль ядра

Other Alias

finit_module

ОБЗОР

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() загружает образ 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», содержащую номер версии ядра и основные свойства (такие как тип ЦП). Во-вторых, если модуль собран с включённым параметром настройки CONFIG_MODVERSIONS, то он содержит хэш версии для каждого используемого модулем символа. Данный хэш основан на типе аргумента и возвращаемом значении функции с именем символа. В этом случае номер версии ядра в строке «vermagic» игнорируется, так как считается, что хэши версий символов достаточно надёжны.

Использование флага MODULE_INIT_IGNORE_VERMAGIC требует игнорировать строку «vermagic», а флаг MODULE_INIT_IGNORE_MODVERSIONS требует игнорировать хэши версий символов. Если ядро собрано с разрешением принудительной загрузки (параметр настройки CONFIG_MODULE_FORCE_LOAD), то загрузка будет продолжена, в противном случае она завершится с ошибкой ENOEXEC, как и ожидается для некорректных модулей.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

EBADMSG (начиная с Linux 3.7)
Неправильный формат подписи модуля.
EBUSY
Истекло время ожидания попытки определения символьной ссылки данным модулем.
EFAULT
Аргумент адреса ссылается на положение вне доступного адресного пространства процесса.
ENOKEY (начиная с Linux 3.7)
Некорректная подпись или ядро не содержит ключа этого модуля. Данная ошибка возвращается только, если ядро было настроено с параметром CONFIG_MODULE_SIG_FORCE; если ядро собрано без этого параметра, то некорректный или не подписанный модуль просто примешивается (taints) в ядро.
ENOMEM
Не хватает памяти.
EPERM
Вызывающий не имеет прав (не имеет мандата CAP_SYS_MODULE), или отключена загрузка модулей (смотрите /proc/sys/kernel/modules_disabled в proc(5)).

Дополнительно в init_module() могут возникать следующие ошибки:

EEXIST
Модуль с таким именем уже загружен.
EINVAL
Некорректное значение param_values, или какая-то часть образа ELF в module_image содержит противоречивую информацию.
ENOEXEC
Двоичный образ, переданный module_image, не является образом ELF, или образ ELF некорректный или для другой архитектуры.

Дополнительно в finit_module() могут возникать следующие ошибки:

EBADF
Файл, на который ссылается fd, не открыт для чтения.
EFBIG
Файл, на который ссылается fd, слишком большой.
EINVAL
Значение flags неверно.
ENOEXEC
Значение fd не указывает на открытый файл.

Дополнительно к этим ошибкам, если функция модуля init при выполнении возвратила ошибку, то init_module() или finit_module() завершается с ошибкой и в errno записывается значение, полученное от функции init.

ВЕРСИИ

Вызовы finit_module() доступен в Linux, начиная с версии 3.8.

СООТВЕТСТВИЕ СТАНДАРТАМ

Вызовы init_module() и finit_module() есть только в Linux.

ЗАМЕЧАНИЯ

Системный вызов init_module() не поддерживается glibc. В заголовочных файлах glibc он не объявлен, но в недавнем прошлом glibc экспортировал ABI для этого системного вызова. Поэтому чтобы получить данный системный вызов достаточно вручную объявить интерфейс в своём коде; или же вы можете вызвать его через syscall(2).

В glibc нет обёртки для finit_module(); запускайте его с помощью syscall(2).

Информацию по уже загруженным модулями можно найти в файле /proc/modules и в соответствующем каждому модулю подкаталогу в /sys/module.

Дополнительную информацию смотрите в файле include/linux/module.h из исходного кода ядра Linux.

Linux версии 2.4 и более ранние

В Linux версии 2.4 и более ранних системный вызов init_module() был немного другим:

#include <linux/module.h>

int init_module(const char *name, struct module *image);

(Приложения пользовательского пространства могут определить какая из версий init_module() доступна, вызвав query_module(); этот вызов завершается ошибкой ENOSYS в Linux 2.6 и более новых.)

Старая версия системного вызова загружает перемещённый образ модуля image, в пространство ядра и выполняет функцию модуля 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, указывают в тело модуля и будут инициализированы в соответствии с адресным пространством ядра, то есть перемещены с остальной частью модуля.