insmod/rmmod 関数 init_module
を使用します と delete_module
これを行うには、マンページも利用できます。どちらも関数を extern
として宣言しています ヘッダーを含める代わりに、マンページには <linux/module.h>
.
init_module
/ remove_module
最小限の実行可能な例
この単純なパラメーター プリンター モジュールを使用して、QEMU + Buildroot VM および Ubuntu 16.04 ホストでテスト済み。
init_module
を使用します / finit_module
と remove_module
Linux システム コール。
Linux カーネルは、モジュール挿入用に 2 つのシステム コールを提供します:
init_module
finit_module
そして:
man init_module
ドキュメント:
<ブロック引用>finit_module() システム コールは init_module() に似ていますが、ロードするモジュールをファイル記述子 fd から読み取ります。ファイルシステム内の場所からカーネルモジュールの信頼性を判断できる場合に役立ちます。それが可能な場合は、モジュールの真正性を判断するために暗号で署名されたモジュールを使用するオーバーヘッドを回避できます。 param_values 引数は init_module() と同じです。
finit
は新しく、v3.8 でのみ追加されました。さらなる根拠:https://lwn.net/Articles/519010/
glibc はそれらの C ラッパーを提供していないようなので、 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 アップストリーム。
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 アップストリーム。
Busybox ソースの解釈
Busybox は insmod
を提供します 、そしてミニマリズムのために設計されているので、そこからどのように行われるかを推測することができます.
バージョン 1.24.2 では、エントリ ポイントは modutils/insmod.c
にあります。 関数 insmod_main
.
IF_FEATURE_2_4_MODULES
は、古い Linux カーネル 2.4 モジュールのオプション サポートであるため、今のところ無視して構いません。
modutils.c
に転送するだけです 関数 bb_init_module
.
bb_init_module
2 つのことを試みます:
-
mmap
try_to_mmap_module
を介してファイルをメモリに .これは常に
image_size
を設定します.ko
のサイズに -
それが失敗した場合、
malloc
xmalloc_open_zipped_read_close
でファイルをメモリに .この関数はオプションで、zip の場合は最初にファイルを解凍し、それ以外の場合は単に malloc します。
try_to_mmap_module
物事を解凍していないようです.
最後に呼び出しが来ます:
init_module(image, image_size, options);
どこで image
メモリに入れられた実行可能ファイルで、オプションは ""
だけです insmod file.elf
を呼び出す場合 それ以上の引数はありません。
init_module
上記は以下によって提供されます:
#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
組み込みの libc 実装であり、init_module
を提供しているようです .
無ければglibcを想定していると思いますが、 man init_module
のように 言います:
init_module() システム コールは、glibc ではサポートされていません。 glibc ヘッダーでは宣言は提供されませんが、歴史の癖により、glibc はこのシステム コールの ABI をエクスポートします。したがって、このシステム コールを使用するには、コード内でインターフェイスを手動で宣言するだけで十分です。または、syscall(2) を使用してシステム コールを呼び出すこともできます。
BusyBox は賢明にもそのアドバイスに従い、syscall
を使用します。 、glibc が提供し、システム コール用の C API を提供します。