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 with CONFIG_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 the CAP_SYS_MODULE capability), or module loading is disabled (see /proc/sys/kernel/modules_disabled in proc(5)).

These next ones may additionally occur for init_module():

  • EEXIST โ€” A module with this name is already loaded.
  • EINVAL โ€” param_values is invalid, or some part of the ELF image in module_image contains inconsistencies.
  • ENOEXEC โ€” The binary image supplied in module_image is 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 by fd is not opened for reading.
  • EFBIG โ€” The file referred to by fd is too large.
  • EINVAL โ€” flags is invalid.
  • EINVAL โ€” The decompressor sanity checks failed, while loading a compressed module with flag MODULE_INIT_COMPRESSED_FILE set.
  • ENOEXEC โ€” fd does not refer to an open file.
  • EOPNOTSUPP (since Linux 5.17) โ€” The flag MODULE_INIT_COMPRESSED_FILE is set to load a compressed module, and the kernel was built without CONFIG_MODULE_DECOMPRESS.
  • ETXTBSY (since Linux 4.7) โ€” The file referred to by fd is 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, then init_module() or finit_module() fails, and errno gets 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
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms