insmod/rmmod menggunakan fungsi init_module
dan delete_module
untuk melakukan ini, yang juga menyediakan halaman manual. Keduanya mendeklarasikan fungsi sebagai extern
alih-alih menyertakan tajuk, tetapi halaman manual mengatakan mereka harus dalam <linux/module.h>
.
init_module
/ remove_module
contoh minimal yang dapat dijalankan
Diuji pada host QEMU + Buildroot VM dan Ubuntu 16.04 dengan modul printer parameter sederhana ini.
Kami menggunakan init_module
/ finit_module
dan remove_module
Panggilan sistem Linux.
Kernel Linux menawarkan dua panggilan sistem untuk penyisipan modul:
init_module
finit_module
dan:
man init_module
dokumen yang:
Panggilan sistem finit_module() seperti init_module(), tetapi membaca modul yang akan dimuat dari deskriptor file fd. Ini berguna ketika keaslian modul kernel dapat ditentukan dari lokasinya di sistem berkas; dalam kasus yang memungkinkan, penggunaan modul yang ditandatangani secara kriptografis untuk menentukan keaslian modul dapat dihindari. Argumen param_values adalah untuk init_module().
finit
lebih baru dan ditambahkan hanya di v3.8. Alasan lainnya:https://lwn.net/Articles/519010/
glibc sepertinya tidak menyediakan pembungkus C untuk mereka, jadi kami hanya membuatnya sendiri dengan 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.
Interpretasi sumber busybox
Busybox menyediakan insmod
, dan karena dirancang untuk minimalis, kita dapat mencoba menyimpulkan cara melakukannya dari sana.
Pada versi 1.24.2, titik masuknya ada di modutils/insmod.c
fungsi insmod_main
.
IF_FEATURE_2_4_MODULES
adalah dukungan opsional untuk modul kernel Linux 2.4 lama, jadi kita dapat mengabaikannya untuk saat ini.
Itu hanya meneruskan ke modutils.c
fungsi bb_init_module
.
bb_init_module
mencoba dua hal:
-
mmap
file ke memori melaluitry_to_mmap_module
.Ini selalu menyetel
image_size
dengan ukuran.ko
file sebagai efek samping. -
jika gagal,
malloc
file ke memori denganxmalloc_open_zipped_read_close
.Fungsi ini secara opsional membuka zip file terlebih dahulu jika itu adalah zip, dan hanya mallocs sebaliknya.
Saya tidak mengerti mengapa bisnis zipping ini dilakukan, karena kami bahkan tidak dapat mengandalkannya karena
try_to_mmap_module
sepertinya tidak meng-unzip sesuatu.
Akhirnya datang panggilan:
init_module(image, image_size, options);
di mana image
adalah executable yang dimasukkan ke dalam memori, dan pilihannya hanya ""
jika kita memanggil insmod file.elf
tanpa argumen lebih lanjut.
init_module
disediakan di atas oleh:
#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
adalah implementasi libc tersemat, dan tampaknya menyediakan init_module
.
Jika tidak ada, saya pikir glibc diasumsikan, tetapi sebagai man init_module
mengatakan:
Panggilan sistem init_module() tidak didukung oleh glibc. Tidak ada deklarasi yang disediakan di header glibc, tetapi, melalui kekhasan sejarah, glibc mengekspor ABI untuk panggilan sistem ini. Oleh karena itu, untuk menggunakan panggilan sistem ini, cukup mendeklarasikan antarmuka secara manual dalam kode Anda; sebagai alternatif, Anda dapat menjalankan panggilan sistem menggunakan syscall(2).
BusyBox dengan bijak mengikuti saran itu dan menggunakan syscall
, yang disediakan oleh glibc, dan yang menawarkan C API untuk panggilan sistem.