init_module(2)

NAZWA
init_module, finit_module - ładuje moduł jądra

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#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).

OPIS
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ć:

nazwa[ =wartość [,wartość...]]

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.

  finit_module()
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:

MODULE_INIT_IGNORE_MODVERSIONS
    Ignoruje skróty wersji symboli.

MODULE_INIT_IGNORE_VERMAGIC
    Ignoruje magię wersji jądra.

MODULE_INIT_COMPRESSED_FILE (od Linuksa 5.17)
    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.

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

BŁĘDY

EBADMSG (od Linuksa 3.7)
    Podpis modułu jest nieprawidłowo sformatowany.

EBUSY
    Nastąpiło przeterminowanie, przy próbie rozwiązania referencji symbolu przez ten moduł.

EFAULT
    Argument adresu odnosi się do położenia, znajdującego się poza dostępną przestrzenią adresową procesu.

ENOKEY (od Linuksa 3.7)
    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.

ENOMEM
    Brak pamięci.

EPERM
    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():

EEXIST
    Załadowano już moduł o takiej nazwie.

EINVAL
    param_values jest nieprawidłowe albo pewne fragmenty obrazu module_image są niespójne.

ENOEXEC
    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():

EBADF
    Plik, do którego odnosi się fd , nie jest otwarty do odczytu.

EFBIG
    Plik, do którego odnosi się fd, jest zbyt duży.

EINVAL
    Znaczniki flags są nieprawidłowe.

EINVAL
    Przy ładowaniu spakowanego modułu ze znacznikiem MODULE_INIT_COMPRESSED_FILE, zawiodło sprawdzanie poprawności przeprowadzone przez dekompresor.

ENOEXEC
    fd nie odnosi się do otwartego pliku.

EOPNOTSUPP (od Linuksa 5.17)
    Ustawiono znacznik MODULE_INIT_COMPRESSED_FILE w celu załadowania spakowanego modułu, lecz jądro zbudowano bez CONFIG_MODULE_DECOMPRESS.

ETXTBSY (od Linuksa 4.7)
    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.

STANDARDY
Linux.

HISTORIA

finit_module()
    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).

  Linux 2.4 i wcześniejsze
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.

UWAGI
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.

ZOBACZ TAKŻE
create_module(2), delete_module(2), query_module(2), lsmod(8), modprobe(8)

TŁUMACZENIE
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 (https://www.gnu.org/licenses/gpl-3.0.html) 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.