init_module(2) System Calls Manual init_module(2)

init_module, finit_module - ładuje moduł jądra

Standardowa biblioteka C (libc, -lc)

#include <linux/module.h>    /* Definicja stałych MODULE_* */
#include <sys/syscall.h>     /* Definicja stałych SYS_* */
#include <unistd.h>
int syscall(SYS_init_module, void module_image[.len], unsigned long len,
            const char *param_values);
int syscall(SYS_finit_module, int fd,
            const char *param_values, int flags);

Uwaga: glibc nie udostępnia opakowania dla tych wywołań systemowych, co wymusza użycie syscall(2).

init_module() ładuje obraz ELF do przestrzeni jądra, przeprowadzając wszelkie niezbędne przesunięcia symboli, inicjuje parametry modułu zgodnie z wartościami przekazanymi przez wywołującego, a następnie uruchamia funkcję init modułu. To wywołanie systemowe wymaga uprzywilejowania.

Argument module_image wskazuje na bufor zawierający obraz binarny, który ma być załadowany; len określa rozmiar tego bufora. Obraz modułu powinien być prawidłowym obrazem ELF, zbudowanym do aktualnie działającego jądra.

Argument param_values jest łańcuchem zawierającym wartości parametrów modułu (zdefiniowanych wewnątrz modułu za pomocą module_param() i module_param_array()), rozdzielone spacją. Jądra analizuje ten łańcuch i inicjuje podane parametry. Określenie każdego z parametrów ma postać:

name[ =value [,value...]]

Parametr nazwa jest jednym ze zdefiniowanych wewnątrz modułu za pomocą module_param() (zob. plik źródeł jądra Linux include/linux/moduleparam.h). Parametr wartość jest opcjonalny w przypadku parametrów bool i invbool. Wartości parametrów tablicy są podawane w liście rozdzielonej przecinkami.

Wywołanie systemowe finit_module() jest podobne do init_module(), lecz odczytuje moduł, który ma być załadowany, z deskryptora pliku fd. Ma to zastosowanie, gdy autentyczność modułu jądra można określić na podstawie jego położenia w systemie plików; w przypadku gdy jest to możliwe, można w ten sposób uniknąć narzutu wynikającego z używania modułów podpisanych kryptograficznie. Argument param_values jest taki sam jak do init_module().

Argument flags modyfikuje działanie finit_module(). Jest maską bitową wartości, utworzoną przez zsumowanie (OR) zera lub więcej poniższych znaczników:

Ignoruje skróty wersji symboli.
Ignoruje magię wersji jądra.
Używa modułu dekompresji w jądrze.

W module są wbudowane pewne mechanizmy bezpieczeństwa zapewniające, że będzie on pasował do jądra, do którego jest załadowywany. Są one zapisywane przy budowaniu modułu i weryfikowane przy jego ładowaniu. Po pierwsze, moduł zapisuje łańcuch „vermagic” zawierający łańcuch z numerem wersji jądra i głównymi cechami (takimi jak typ procesora). Po drugie, jeśli moduł zbudowano z włączoną opcją konfiguracyjną CONFIG_MODVERSIONS, to zapisywany jest skrót (hash) wersji każdego symbolu, którego używa moduł. Skrót ten zależy od typów argumentów i zwracanej przez funkcję, nazwaną przez symbol, wartości. W niniejszym przypadku, numer wersji jądra w „vermagic” jest ignorowany przyjmując, że skróty wersji symboli są wystarczająco wiarygodne.

Użycie znacznika MODULE_INIT_IGNORE_VERMAGIC wskazuje, że łańcuch „vermagic” ma być zignorowany, natomiast znacznik MODULE_INIT_IGNORE_MODVERSIONS wskazuje, że skróty wersji symboli mają być zignorowane. Jeśli jądro zbudowano w sposób umożliwiający wymuszone ładowanie modułów (tj. skonfigurowano je z opcją CONFIG_MODULE_FORCE_LOAD), to ładowanie będzie kontynuowane, w przeciwnym przypadku zawiedzie z błędem ENOEXEC, jak jest to spodziewane wobec nieprawidłowych modułów.

Jeśli jądro zbudowano z opcją CONFIG_MODULE_DECOMPRESS, można skorzystać z funkcji dekompresji w jądrze. Kod w przestrzeni użytkownika może sprawdzić, czy jądro obsługuje dekompresję odczytując atrybut /sys/module/compression. Jeśli jądro obsługuje dekompresję, skompresowany plik można podać bezpośrednio do finit_module() za pomocą znacznika MODULE_INIT_COMPRESSED_FILE. Moduł dekompresji w jądrze obsługuje następujące algorytmy kompresji:

gzip (od Linuksa 5.17)
xz (od Linuksa 5.17)
zstd (od Linuksa 6.2)

Jądro implementuje jedynie pojedynczą metodę dekompresji. Wybiera się ją przy generowaniu modułu, zgodnie z metodą kompresji użytą w konfiguracji jądra.

W przypadku powodzenia, te wywołania zwracają 0. W razie wystąpienia błędu zwracane jest -1 i ustawiane errno wskazując błąd.

Podpis modułu jest nieprawidłowo sformatowany.
Nastąpiło przeterminowanie, przy próbie rozwiązania referencji symbolu przez ten moduł.
Argument adresu odnosi się do położenia, znajdującego się poza dostępną przestrzenią adresową procesu.
Podpis modułu jest nieprawidłowy albo jądro nie ma klucza do tego modułu. Błąd jest zwracany tylko, jeśli jądro skonfigurowano z opcją CONFIG_MODULE_SIG_FORCE; w przeciwnym wypadku nieprawidłowy lub niepodpisany moduł jedynie zatruwa (taint) jądro.
Brak pamięci.
Wywołujący nie był uprzywilejowany (nie posiadał przywileju (ang. capability) CAP_SYS_MODULE) lub ładowanie modułów jest wyłączone (zob. /proc/sys/kernel/modules_disabled w proc(5)).

Mogą wystąpić następujące dodatkowe błędy dla init_module():

Załadowano już moduł o takiej nazwie.
param_values jest nieprawidłowe albo pewne fragmenty obrazu module_image są niespójne.
Obraz binarny podany w module_image nie jest obrazem ELF albo jest nieprawidłowym lub przeznaczonym do innej architektury obrazem ELF.

Mogą wystąpić następujące dodatkowe błędy dla finit_module():

Plik, do którego odnosi się fd , nie jest otwarty do odczytu.
Plik, do którego odnosi się fd, jest zbyt duży.
Znaczniki flags są nieprawidłowe.
Przy ładowaniu spakowanego modułu ze znacznikiem MODULE_INIT_COMPRESSED_FILE, zawiodło sprawdzanie poprawności przeprowadzone przez dekompresor.
fd nie odnosi się do otwartego pliku.
Ustawiono znacznik MODULE_INIT_COMPRESSED_FILE w celu załadowania spakowanego modułu, lecz jądro zbudowano bez CONFIG_MODULE_DECOMPRESS.
Plik, do którego odnosi się fd, jest otwarty do odczytu i zapisu.

Oprócz powyższych błędów, jeśli wykonana funkcja init modułu zwróci błąd, to init_module() lub finit_module() zawiodą, a errno zostanie ustawione na wartość zwróconą przez funkcję init.

Linux.

Linux 3.8.

Wywołanie systemowe init_module() nie jest obsługiwane przez glibc. W nagłówkach glibc nie ma jego deklaracji, ale z powodów pewnych zaszłości historycznych wersje glibc przed glibc 2.23 eksportowały ABI dla tego wywołania systemowego. Z tego powodu, aby go użyć wystarczy (przed glibc 2.23) manualnie zadeklarować interfejs w swoim kodzie; alternatywnie można wywołać to wywołanie systemowe za pomocą syscall(2).

W Linuksie 2.4 i wcześniejszych wywołanie systemowe init_module() było wyraźnie odmienne:

#include <linux/module.h>

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

(Aplikacje w przestrzeni użytkownika mogą wykryć dostępną wersję init_module() przez wywołanie query_module(); to ostatnie wywołanie zawiedzie z błędem ENOSYS w Linuksie 2.6 i późniejszych).

Starsza wersja tego wywołania systemowego ładowała przesunięty obraz jądra, na który wskazywało image do przestrzeni jądra i uruchamiało funkcję init modułu. To wywołujący był odpowiedzialny za udostępnienie przesuniętego obrazu (od Linuksa 2.6, to wywołanie systemowe init_module() dokonuje przesunięcia).

Obraz modułu rozpoczyna się od struktury modułu, po której następują, odpowiednio, kod i dane. Od Linuksa 2.2 struktura modułu jest zdefiniowana następująco:


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
};

Wszystkie pola wskazujące, oprócz next i refs, powinny wskazywać na adresy w ciele modułu i zostać zainicjalizowane odpowiednio dla przestrzeni adresowej jądra, tzn. przesunięte wraz z resztą modułu.

Informacje o obecnie załadowanych modułach są dostępne w /proc/modules oraz w strukturze plików zawartej w podkatalogach, przypisanych poszczególnym modułom, w katalogu /sys/module.

Więcej przydatnych informacji „od kuchni” znajduje się w pliku źródeł jądra Linux include/linux/module.h.

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

Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.

2 maja 2024 r. Linux man-pages 6.8