insmod/rmmod použijte funkce init_module
a delete_module
k tomu, které mají také k dispozici manuálovou stránku. Oba deklarují funkce jako extern
místo zahrnutí záhlaví, ale manuálová stránka říká, že by měly být v <linux/module.h>
.
init_module
/ remove_module
minimální spustitelný příklad
Testováno na virtuálním počítači QEMU + Buildroot a hostiteli Ubuntu 16.04 s tímto jednoduchým modulem tiskárny parametrů.
Používáme init_module
/ finit_module
a remove_module
Systémová volání Linuxu.
Linuxové jádro nabízí dvě systémová volání pro vložení modulu:
init_module
finit_module
a:
man init_module
dokumenty, které:
Systémové volání finit_module() je jako init_module(), ale čte modul, který se má načíst, z deskriptoru souboru fd. Je to užitečné, když lze pravost modulu jádra určit z jeho umístění v souborovém systému; v případech, kdy je to možné, se lze vyhnout režii používání kryptograficky podepsaných modulů k určení pravosti modulu. Argument param_values je stejný jako u init_module().
finit
je novější a byl přidán až ve verzi 3.8. Více zdůvodnění:https://lwn.net/Articles/519010/
Zdá se, že glibc pro ně neposkytuje obal C, takže jsme si vytvořili vlastní s syscall
.
insmod.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)
int main(int argc, char **argv) {
const char *params;
int fd, use_finit;
size_t image_size;
struct stat st;
void *image;
/* CLI handling. */
if (argc < 2) {
puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
return EXIT_FAILURE;
}
if (argc < 3) {
params = "";
} else {
params = argv[2];
}
if (argc < 4) {
use_finit = 0;
} else {
use_finit = (argv[3][0] != '0');
}
/* Action. */
fd = open(argv[1], O_RDONLY);
if (use_finit) {
puts("finit");
if (finit_module(fd, params, 0) != 0) {
perror("finit_module");
return EXIT_FAILURE;
}
close(fd);
} else {
puts("init");
fstat(fd, &st);
image_size = st.st_size;
image = malloc(image_size);
read(fd, image, image_size);
close(fd);
if (init_module(image, image_size, params) != 0) {
perror("init_module");
return EXIT_FAILURE;
}
free(image);
}
return EXIT_SUCCESS;
}
GitHub upstream.
rmmod.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
int main(int argc, char **argv) {
if (argc != 2) {
puts("Usage ./prog mymodule");
return EXIT_FAILURE;
}
if (delete_module(argv[1], O_NONBLOCK) != 0) {
perror("delete_module");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
GitHub upstream.
Interpretace zdroje Busybox
Busybox poskytuje insmod
, a protože je navržen pro minimalismus, můžeme se z toho pokusit odvodit, jak se to dělá.
Ve verzi 1.24.2 je vstupní bod na modutils/insmod.c
funkce insmod_main
.
IF_FEATURE_2_4_MODULES
je volitelná podpora pro starší moduly linuxového jádra 2.4, takže ji zatím můžeme ignorovat.
To jen přesměruje na modutils.c
funkce bb_init_module
.
bb_init_module
pokusí se o dvě věci:
-
mmap
soubor do paměti přestry_to_mmap_module
.Toto vždy nastaví
image_size
na velikost.ko
soubor jako vedlejší efekt. -
pokud to selže,
malloc
soubor do paměti sxmalloc_open_zipped_read_close
.Tato funkce volitelně nejprve rozbalí soubor, pokud se jedná o zip, a jinak jej pouze mallocuje.
Nechápu, proč se dělá toto zipování, protože se na to ani nemůžeme spolehnout, protože
try_to_mmap_module
nezdá se, že by věci rozepínal.
Konečně přichází hovor:
init_module(image, image_size, options);
kde image
je spustitelný soubor, který byl vložen do paměti, a možnosti jsou pouze ""
pokud zavoláme insmod file.elf
bez dalších argumentů.
init_module
poskytuje výše:
#ifdef __UCLIBC__
extern int init_module(void *module, unsigned long len, const char *options);
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif
ulibc
je vestavěná implementace knihovny libc a zdá se, že poskytuje init_module
.
Pokud není přítomen, myslím, že se předpokládá glibc, ale jako man init_module
říká:
Systémové volání init_module() není podporováno glibc. V hlavičkách glibc není k dispozici žádná deklarace, ale díky historickému vtipu glibc exportuje ABI pro toto systémové volání. Proto, aby bylo možné použít toto systémové volání, stačí ručně deklarovat rozhraní ve vašem kódu; alternativně můžete systémové volání vyvolat pomocí syscall(2).
BusyBox moudře následuje tuto radu a používá syscall
, který poskytuje glibc a který nabízí C API pro systémová volání.