init_module(2)
๐ init_module โ bestie's guide to yeeting kernel modules into the kernel ๐
ok so this is the init_module(2) and finit_module(2) page, and honestly? it's giving "you have root or you have nothing." It lives in the System Calls Manual, no cap. Let's get into it. โจ
๐ธ NAME ๐ธ
init_module, finit_module โ load a kernel module ๐ง
๐ LIBRARY ๐
Standard C library (libc, -lc)
โจ SYNOPSIS โจ
#include <linux/module.h> /* Definition of MODULE_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
int syscall(unsigned long size;
SYS_init_module,
void module_image[size], unsigned long size,
const char *param_values);
int syscall(SYS_finit_module, int fd,
const char *param_values, int flags);
๐จ bestie listen: glibc provides no wrappers for these system calls, so you literally have to use syscall(2). That's just how it is. ๐
๐ฆ DESCRIPTION ๐ฆ
init_module() loads an ELF image into kernel space, does any necessary symbol relocations, initializes the module parameters to whatever values the caller handed over, and then runs the module's init function. โก This system call requires privilege, so don't even try it as a rando user.
The module_image argument points at a buffer holding the binary image you wanna load; size says how big that buffer is. The module image should be a valid ELF image, built for the running kernel. no exceptions.
The param_values argument is a string with space-delimited specs of the values for module parameters (those get defined inside the module using module_param() and module_param_array()). The kernel parses this string and initializes the parameters you named. Each parameter spec looks like this:
name[=value[,value...]]
The parameter name is one of the ones defined inside the module using module_param() (peep the Linux kernel source file include/linux/moduleparam.h). The parameter value is optional for bool and invbool parameters. Values for array parameters get written as a comma-separated list. periodt. ๐
๐ finit_module() ๐
The finit_module() system call is basically init_module()'s twin, except it reads the module that's being loaded from the file descriptor fd. It's the move when you can tell a kernel module is authentic just from where it sits in the filesystem; when that's true, you get to skip the overhead of using cryptographically signed modules to determine authenticity. Felt. ๐
The param_values argument works exactly like for init_module().
The flags argument modifies how finit_module() operates. It's a bit mask made by ORing together zero or more of these flags:
MODULE_INIT_IGNORE_MODVERSIONSโ ignore symbol version hashes. ๐MODULE_INIT_IGNORE_VERMAGICโ ignore kernel version magic. ๐MODULE_INIT_COMPRESSED_FILE(since Linux 5.17) โ use in-kernel module decompression. ๐ฅ
There are some safety checks baked into a module to make sure it matches the kernel it's being loaded against. These checks get recorded when the module is built and verified when the module is loaded. First: the module records a "vermagic" string containing the kernel version number and prominent features (like the CPU type). Second: if the module was built with the CONFIG_MODVERSIONS configuration option enabled, a version hash gets recorded for each symbol the module uses. That hash is based on the types of the arguments and the return value for the function the symbol names. In that case, the kernel version number inside the "vermagic" string is ignored, because the symbol version hashes are assumed to be sufficiently reliable.
Using the MODULE_INIT_IGNORE_VERMAGIC flag means "ignore the "vermagic" string," and the MODULE_INIT_IGNORE_MODVERSIONS flag means "ignore the symbol version hashes." If the kernel is built to permit forced loading (i.e., configured with CONFIG_MODULE_FORCE_LOAD), loading continues. Otherwise it fails with the error ENOEXEC, exactly as expected for malformed modules. ๐ญ
If the kernel was built with CONFIG_MODULE_DECOMPRESS, you can use the in-kernel decompression feature. User-space code can check whether the kernel supports decompression by reading the /sys/module/compression attribute. If the kernel does support decompression, you can pass the compressed file straight to finit_module() using the MODULE_INIT_COMPRESSED_FILE flag. The in-kernel module decompressor supports these compression algorithms:
gzip(since Linux 5.17) ๐xz(since Linux 5.17) ๐zstd(since Linux 6.2) ๐
The kernel only implements a single decompression method. It gets selected during module generation according to whatever compression method was chosen in the kernel configuration.
๐ RETURN VALUE ๐
On success, these system calls return 0. โจ On error, -1 is returned and errno is set to indicate the error. That's the whole thing bestie.
๐ ERRORS ๐
EBADMSG(since Linux 3.7) โ Module signature is misformatted.EBUSYโ Timeout while trying to resolve a symbol reference by this module.EFAULTโ An address argument referred to a location that is outside the process's accessible address space.ENOKEY(since Linux 3.7) โ Module signature is invalid, or the kernel doesn't have a key for this module. This error is returned only if the kernel was configured withCONFIG_MODULE_SIG_FORCE; if the kernel wasn't configured with this option, then an invalid or unsigned module just taints the kernel. ๐ซENOMEMโ Out of memory.EPERMโ The caller wasn't privileged (didn't have theCAP_SYS_MODULEcapability), or module loading is disabled (see/proc/sys/kernel/modules_disabledinproc(5)).
These next ones may additionally occur for init_module():
EEXISTโ A module with this name is already loaded.EINVALโparam_valuesis invalid, or some part of the ELF image inmodule_imagecontains inconsistencies.ENOEXECโ The binary image supplied inmodule_imageis not an ELF image, or is an ELF image that is invalid or for a different architecture.
And these next ones may additionally occur for finit_module():
EBADFโ The file referred to byfdis not opened for reading.EFBIGโ The file referred to byfdis too large.EINVALโflagsis invalid.EINVALโ The decompressor sanity checks failed, while loading a compressed module with flagMODULE_INIT_COMPRESSED_FILEset.ENOEXECโfddoes not refer to an open file.EOPNOTSUPP(since Linux 5.17) โ The flagMODULE_INIT_COMPRESSED_FILEis set to load a compressed module, and the kernel was built withoutCONFIG_MODULE_DECOMPRESS.ETXTBSY(since Linux 4.7) โ The file referred to byfdis opened for read-write.
๐ one more thing: on top of all the errors above, if the module's init function actually runs and returns an error, theninit_module()orfinit_module()fails, anderrnogets set to the value returned by the init function.
๐ STANDARDS ๐
Linux. that's it, that's the standard. ๐ง
๐ HISTORY ๐
finit_module() โ Linux 3.8.
The init_module() system call is not supported by glibc. No declaration is provided in glibc headers, but through a quirk of history, glibc versions before glibc 2.23 did export an ABI for this system call. So to use this system call, it's (before glibc 2.23) enough to manually declare the interface in your code; alternatively you can invoke the system call using syscall(2). โจ
๐ง Linux 2.4 and earlier ๐ง
In Linux 2.4 and earlier, the init_module() system call was rather different:
#include <linux/module.h>
int init_module(const char *name, struct module *image);
(User-space applications can detect which version of init_module() is available by calling query_module(); the latter call fails with the error ENOSYS on Linux 2.6 and later.)
The older version of the system call loads the relocated module image pointed to by image into kernel space and runs the module's init function. The caller is responsible for providing the relocated image (since Linux 2.6, the init_module() system call does the relocation).
The module image begins with a module structure and is followed by code and data as appropriate. Since Linux 2.2, the module structure is defined like this:
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;
typeof(int (void)) *init;
typeof(void (void)) *cleanup;
const struct exception_table_entry *ex_table_start;
const struct exception_table_entry *ex_table_end;
#ifdef __alpha__
unsigned long gp;
#endif
};
All of the pointer fields โ with the exception of next and refs โ are expected to point within the module body and be initialized as appropriate for kernel space, that is, relocated with the rest of the module. ๐ซถ
๐ NOTES ๐
Info about the modules currently loaded can be found in /proc/modules and in the file trees under the per-module subdirectories under /sys/module. ๐
Peep the Linux kernel source file include/linux/module.h for some useful background information. ๐
๐ SEE ALSO ๐
create_module(2), delete_module(2), query_module(2), lsmod(8), modprobe(8)
ok that's the whole page bestie you ate it up ๐ this was served fresh from Linux man-pages 6.20, dated 2026-02-08, and yeah it's the init_module(2) page, go forth and load responsibly ๐โจ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 1996, Free Software Foundation, Inc
- Copyright 2012, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms