Skip to main content
Kernel modules are object files (.ko) that can be loaded into and removed from the running kernel without rebooting. They extend the kernel with device drivers, filesystem support, network protocols, and other functionality.

What are kernel modules?

Modules are compiled kernel code that lives outside the main kernel image. When loaded, they run in kernel space with full kernel privileges. Most hardware drivers, filesystem implementations, and many network protocols ship as modules rather than being compiled directly into the kernel (vmlinuz).
# Where modules live
ls /lib/modules/$(uname -r)/kernel/

Managing modules

lsmod

List all currently loaded modules, their sizes, and usage counts.

modprobe

Load or remove a module and automatically handle dependencies.

insmod

Load a module directly from a .ko file, without dependency resolution.

rmmod

Remove a loaded module (must not be in use).

Listing loaded modules

# Show all loaded modules
lsmod

# Output format:
# Module                  Size  Used by
# btrfs                1687552  0
# blake2b_generic        20480  0
# xor                    24576  1 btrfs
# ...
The Used by column shows the use count and which other modules depend on a given module.
# Show detailed info about a module
modinfo ext4
modinfo -p ext4     # show only parameters

Loading modules

# Load a module and its dependencies (preferred)
modprobe e1000e

# Load with parameters
modprobe e1000e SmartPowerDownEnable=1

# Load from a specific .ko file (no dependency resolution)
insmod /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
Use modprobe rather than insmod for everyday use. modprobe reads the module dependency database (modules.dep) and loads any required dependencies automatically.

Unloading modules

# Remove a module
modprobe -r e1000e

# Or:
rmmod e1000e

# Force removal even if in use (dangerous)
rmmod -f e1000e
Force-removing a module with rmmod -f can crash the kernel or corrupt data. It also sets the R taint flag. Only use it when you understand why the module appears in use.

Module parameters

Modules expose parameters that can be set at load time or (for some) at runtime:
# View available parameters
modinfo -p <module>

# Example output for iwlwifi:
# swcrypto:using crypto in software (default 0) (int)
# 11n_disable:disable 11n functionality  (uint)
# power_save:enable WiFi power management (default: disable) (int)

# Set parameters at load time
modprobe iwlwifi power_save=1 11n_disable=0

# View current parameter values after loading
cat /sys/module/iwlwifi/parameters/power_save

# Change runtime-writable parameters
echo 1 > /sys/module/iwlwifi/parameters/power_save

Persistent parameters with modprobe.d

Create a .conf file in /etc/modprobe.d/ to set parameters every time a module is loaded:
# /etc/modprobe.d/iwlwifi.conf
options iwlwifi power_save=1 11n_disable=0

Automatic module loading

udev and module aliases

When hardware is detected, udev reads the device’s vendor/product IDs and looks up the corresponding module via modalias. The kernel then calls request_module() to load it automatically.
# See the modalias for a device
cat /sys/bus/pci/devices/0000:00:1f.3/modalias
# pci:v00008086d0000A348sv000017AAsd00002233bc04sc03i00

# Find which module handles this modalias
modprobe --resolve-alias pci:v00008086d0000A348sv...

/etc/modules-load.d/

For modules that should always be loaded at boot regardless of hardware detection:
# /etc/modules-load.d/tun.conf
tun

# /etc/modules-load.d/loop.conf
loop
On systemd systems, systemd-modules-load.service processes these files during early boot.

Blacklisting modules

Blacklisting prevents a module from being loaded automatically. It does not prevent manual loading with modprobe -f or insmod.
# /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau

# Also block udev from loading it via an alias
install nouveau /bin/false
The install directive replaces the module’s load action with an arbitrary command. Using /bin/false makes any attempt to load the module via modprobe silently fail.
After adding a blacklist entry, regenerate the initramfs so the change takes effect at boot:
# Debian/Ubuntu
update-initramfs -u

# RHEL/Fedora
dracut --force

Module signing

The kernel module signing facility cryptographically signs modules during installation and verifies signatures when modules are loaded. This prevents loading of tampered or malicious modules, and is required for Secure Boot.

How it works

1

Build-time key generation

When CONFIG_MODULE_SIG=y is set, the kernel build system automatically generates a private/public keypair in certs/signing_key.pem (if one does not exist):
openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \
    -config certs/x509.genkey \
    -outform PEM -out certs/signing_key.pem \
    -keyout certs/signing_key.pem
The public key is embedded in the kernel binary. The private key is only needed during the build.
2

Module signing at install time

With CONFIG_MODULE_SIG_ALL=y, all modules are signed automatically during make modules_install.To manually sign a module:
scripts/sign-file sha512 certs/signing_key.pem certs/signing_key.pem module.ko

# General syntax:
# scripts/sign-file <hash> <private-key> <x509-cert> <module.ko>
3

Signature verification at load time

The kernel checks the module’s signature against its built-in keyring (/.builtin_trusted_keys) when the module is loaded. No userspace tools are involved.
# View the kernel's built-in trusted keys
cat /proc/keys | grep -i key

Kernel configuration options

Config optionEffect
CONFIG_MODULE_SIGEnable module signature verification
CONFIG_MODULE_SIG_FORCERefuse to load unsigned or incorrectly signed modules
CONFIG_MODULE_SIG_ALLAutomatically sign all modules at install time
CONFIG_MODULE_SIG_SHA512Use SHA-512 for module signatures
CONFIG_MODULE_SIG_KEYPath to the signing key (default: certs/signing_key.pem)
CONFIG_SYSTEM_TRUSTED_KEYSPEM file with additional trusted certificates

Enforcement modes

If CONFIG_MODULE_SIG_FORCE is off (permissive mode): unsigned modules load but taint the kernel with the E flag. If CONFIG_MODULE_SIG_FORCE is on (or module.sig_enforce=1 is set on the kernel command line): only validly signed modules load; all others are rejected with an error.
# Enable enforcement at boot without recompiling
# Add to bootloader command line:
module.sig_enforce=1

Protecting the private key

The private signing key must be stored securely. Anyone who obtains it can sign malicious modules. After completing a build, either delete the private key or move it to a hardware security module (HSM) or encrypted offline storage.
# Delete the private key after the build
shred -u certs/signing_key.pem

# Or store it separately and reference via CONFIG_MODULE_SIG_KEY
CONFIG_MODULE_SIG_KEY="/path/to/secure/signing_key.pem"

Out-of-tree modules

Modules not included in the mainline kernel source are called out-of-tree (OOT) modules. Common examples include proprietary GPU drivers (NVIDIA), ZFS, VirtualBox kernel modules, and vendor-specific drivers.

Building an out-of-tree module

# Prerequisites: kernel headers for the running kernel
apt install linux-headers-$(uname -r)   # Debian/Ubuntu
dnf install kernel-devel-$(uname -r)    # Fedora/RHEL

# Build against the running kernel
cd /path/to/module/source
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

# Install
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_install
depmod -a

DKMS — Dynamic Kernel Module Support

DKMS automatically rebuilds out-of-tree modules when a new kernel is installed:
# Install DKMS framework
apt install dkms

# Add a module to DKMS management
dkms add -m mymodule -v 1.0
dkms build -m mymodule -v 1.0
dkms install -m mymodule -v 1.0

# Status of all DKMS modules
dkms status

Tainted kernels

The kernel marks itself as “tainted” when certain events occur that may affect its reliability or supportability. Taint flags are visible in kernel oops and panic messages, and via /proc/sys/kernel/tainted.
# Check if the kernel is tainted
cat /proc/sys/kernel/tainted
# 0 = not tainted
# Non-zero = tainted (the value encodes which flags are set)

# Decode the taint value
for i in $(seq 18); do
  echo $((i-1)) $(( $(cat /proc/sys/kernel/tainted) >> (i-1) & 1 ))
done

Taint flag reference

BitFlagValueReason
0P1Proprietary module loaded
1F2Module force-loaded (insmod -f)
2S4Kernel running on out-of-specification hardware
3R8Module force-unloaded (rmmod -f)
4M16Machine Check Exception (MCE) occurred
5B32Bad page reference or unexpected page flags
6U64Taint requested by userspace
7D128Kernel died recently (oops or BUG)
8A256ACPI table overridden by user
9W512Kernel issued a warning
10C1024Staging driver loaded
11I2048Workaround applied for platform firmware bug
12O4096Out-of-tree module loaded
13E8192Unsigned module loaded
14L16384Soft lockup occurred
15K32768Kernel has been live-patched
16X65536Auxiliary taint (used by Linux distributors)
17T131072Kernel built with struct randomization plugin
18N262144In-kernel test (e.g., KUnit) was run
19J524288Userspace used a mutating debug operation via fwctl

Reading taint flags in oops messages

CPU: 0 PID: 4424 Comm: insmod Tainted: P        W  O      6.8.0 #1
In this example:
  • P = proprietary module loaded (bit 0)
  • W = kernel issued a warning (bit 9)
  • O = out-of-tree module loaded (bit 12)
Kernel developers frequently decline to investigate bug reports from tainted kernels, because the taint event itself could be the cause of the bug. Always try to reproduce issues on an untainted kernel before filing a bug report.
The kernel remains tainted even after the triggering event is undone (e.g., unloading a proprietary module) to indicate that the kernel’s state may no longer be fully trustworthy.

Build docs developers (and LLMs) love