I have an application that has both two external kernel modules and a userspace daemon. I want to load the modules from the daemon code, written in C, at startup, and unload them on clean exit. Can I load them in a cleaner way than doing system("modprobe module");
and unload them using the corresponding rmmod
?

- 347,512
- 102
- 1,199
- 985

- 601
- 1
- 6
- 10
-
1Even if you can avoid `modprobe` you probably should not – Basile Starynkevitch Mar 17 '18 at 11:22
5 Answers
init_module
/ remove_module
minimal runnable example
Tested on a QEMU + Buildroot VM and Ubuntu 16.04 host with this simple parameter printer module .
We use the init_module
/ finit_module
and remove_module
Linux system calls.
The Linux kernel offers two system calls for module insertion:
init_module
finit_module
and:
man init_module
documents that:
The finit_module() system call is like init_module(), but reads the module to be loaded from the file descriptor fd. It is useful when the authenticity of a kernel module can be determined from its location in the filesystem; in cases where that is possible, the overhead of using cryptographically signed modules to determine the authenticity of a module can be avoided. The param_values argument is as for init_module().
finit
is newer and was added only in v3.8. More rationale: https://lwn.net/Articles/519010/
glibc does not seem to provide a C wrapper for them, so we just create our own with 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;
}
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;
}
Busybox source interpretation
Busybox provides insmod
, and since it is designed for minimalism, we can try to deduce how it is done from there.
On version 1.24.2, the entry point is at modutils/insmod.c
function insmod_main
.
The IF_FEATURE_2_4_MODULES
is optional support for older Linux kernel 2.4 modules, so we can just ignore it for now.
That just forwards to modutils.c
function bb_init_module
.
bb_init_module
attempts two things:
mmap
the file to memory throughtry_to_mmap_module
.This always sets
image_size
to the size of the.ko
file as a side effect.if that fails,
malloc
the file to memory withxmalloc_open_zipped_read_close
.This function optionally unzips the file first if it is a zip, and just mallocs it otherwise.
I don't understand why this zipping business is done, since we can't even rely on it because the
try_to_mmap_module
does not seem to unzip things.
Finally comes the call:
init_module(image, image_size, options);
where image
is the executable that was put into memory, and options are just ""
if we call insmod file.elf
without further arguments.
init_module
is provided above by:
#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
is an embedded libc implementation, and it seems to provide init_module
.
If it is not present, I think glibc is assumed, but as man init_module
says:
The init_module() system call is not supported by glibc. No declaration is provided in glibc headers, but, through a quirk of history, glibc does export an ABI for this system call. Therefore, in order to employ this system call, it is sufficient to manually declare the interface in your code; alternatively, you can invoke the system call using syscall(2).
BusyBox wisely follows that advice and uses syscall
, which glibc provides, and which offers a C API for system calls.

- 347,512
- 102
- 1,199
- 985
-
1thanks for that! I am writing a C++ program to work with virtual i2c protocol and I used your code to load the kernel module on my machine – Felipe Oct 24 '18 at 07:47
-
1@FelipeOliveiraGutierrez boa Felipe! Se tiver algum problema com o repo, abre um issue la que agente da um jeito. – Ciro Santilli OurBigBook.com Oct 24 '18 at 07:55
-
https://stackoverflow.com/users/895245/ciro-santilli-%e6%96%b0%e7%96%86%e6%94%b9%e9%80%a0%e4%b8%ad%e5%bf%83-%e5%85%ad%e5%9b%9b%e4%ba%8b%e4%bb%b6-%e6%b3%95%e8%bd%ae%e5%8a%9f . Se voce tiver um tempo livre poderia me ajudar nessa questao em como escrever e ler no i2c usando C++? Obrigado https://stackoverflow.com/questions/52966483/writing-and-reading-from-a-virtual-i2c-using-c-and-i2c-tools – Felipe Oct 24 '18 at 10:20
-
Santilli - Eu solucionei usando o codigo de wiringPiI2C com algumas modificacoes para o meu i2c virtual https://stackoverflow.com/questions/52966483/writing-and-reading-from-a-virtual-i2c-using-c-and-i2c-tools/52971432#52971432 . Obrigado pela dica! Agora eu nao estou conseguindo remover o modulo. Quero dizer: se eu faco a sequincia AddModule > DeleteModule. Funciona. Se eu faco a sequencia AddModule > writeI2C > ReadI2C > DeleteModule. o DeleteModule nao funciona. meu erro: `delete_module: Resource temporarily unavailable`. Ja' tentei colocar um sleep de 1 segundo mas nao funciona. – Felipe Oct 24 '18 at 14:28
insmod/rmmod use the functions init_module
and delete_module
to do this, which also have a man-page available. They both declare the functions as extern
instead of including a header, but the man-page says they should be in <linux/module.h>
.

- 30,840
- 6
- 50
- 48
I'd recommend against the use of system()
in any daemon code that runs with root permissions as it's relatively easy to exploit from a security standpoint. modprobe
and rmmod
are, indeed, the right tools for the job. However, it'd be a bit cleaner and much more secure to use an explicit fork()
+ exec()
to invoke them.

- 7,779
- 24
- 25
-
1Do you think.. by using fork and exec the process becomes cleaner to remove module.? – kzs Mar 27 '13 at 02:51
I'm not sure there's a cleaner way than system
.
But for sure, if you want to load/unload the modules from your userspace daemon, then you force yourself to run the daemon as root*, which may not be considered as secure.
*: or you can add the explicit commands in the sudoers file, but this will be a nightmare to manage when deploying your application.

- 36,376
- 13
- 83
- 122
You can perform the same tasks that modprobe
and Co. do, but I doubt that could be characterized as cleaner.

- 39,737
- 6
- 87
- 123