table of contents
init_module(2) | System Calls Manual | 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ć:
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.
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 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 (niewydane) |