Level 2

Kernel module management with modprobe, DKMS, and blacklisting

Maximilian B. 11 min read 10 views

Kernel module management is the mechanism that lets Linux support thousands of hardware devices and features without bloating the base kernel image. In day-to-day administration, you load modules with modprobe, remove them, pass parameters, blacklist problematic ones, and occasionally build out-of-tree drivers with DKMS. This article covers the tools and techniques for reliable kernel module management in production environments running Debian 13.3, Fedora 43, and RHEL 10.1. For foundational context, see the guide on Linux kernel architecture, modules, and version scheme.

Inspecting Kernel Modules: lsmod, modinfo, and the Module Tree

Kernel module management with modprobe, DKMS, and blacklisting visual summary diagram
Visual summary of the key concepts in this guide.

Before changing anything, you need to see what kernel modules are loaded and what is available.

# List all currently loaded modules with size and dependency count
lsmod

# Show detailed information about a specific module
modinfo e1000e
# Output includes: filename, version, description, author, license,
# firmware files needed, parameters, and dependencies (depends: line)

# Show just the parameters a module accepts
modinfo -p e1000e

# Where modules live on disk
ls /lib/modules/$(uname -r)/kernel/
# Subdirectories: arch/ crypto/ drivers/ fs/ lib/ net/ sound/ etc.

# Module dependency database
cat /lib/modules/$(uname -r)/modules.dep | head -10

The modules.dep file maps every module to its dependencies. This file is generated by depmod and is what modprobe uses to resolve dependency chains automatically.

Practical example: finding the right module for a device

When a new piece of hardware does not work, you need to identify which kernel module it needs. The workflow combines lspci with modinfo:

# Identify the PCI device and see if a driver is bound
lspci -k -s 03:00.0
# 03:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200
#     Kernel driver in use: iwlwifi
#     Kernel modules: iwlwifi

# If no driver is in use, check the device's PCI IDs
lspci -n -s 03:00.0
# 03:00.0 0280: 8086:2723

# Search for a matching module by alias
modprobe --show-depends iwlwifi
# Shows the full dependency chain that modprobe would load

Loading and Unloading Modules: modprobe vs insmod

There are two commands for loading kernel modules, and in practice you should always use modprobe.

insmod: the low-level module loader

insmod loads a single module file by its full path. It does not resolve dependencies. If the module depends on another module that is not loaded, insmod fails with "Unknown symbol" errors.

# insmod requires the full .ko file path and handles no dependencies
sudo insmod /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko.xz
# If e1000e depends on another module, this will fail

modprobe reads modules.dep, loads all required dependencies in the correct order, and accepts module names (not file paths).

# Load a module and all its dependencies
sudo modprobe e1000e

# Load a module with specific parameters
sudo modprobe bonding mode=4 miimon=100

# Remove a module (and unused dependencies with -r flag behavior)
sudo modprobe -r e1000e

# Dry-run: show what would happen without actually loading
modprobe -n -v e1000e

For removal, rmmod is the low-level counterpart. It refuses to unload modules that are in use (referenced by other modules or bound to devices). modprobe -r handles dependency cleanup more gracefully.

Making module loading persistent across reboots

Loading a module with modprobe does not survive a reboot. To make it persistent, add the module name to a configuration file:

# Create a file to load modules at boot
# Debian 13.3 / Ubuntu 24.04.3 LTS
echo "bonding" | sudo tee /etc/modules-load.d/bonding.conf

# Fedora 43 / RHEL 10.1 (same location, systemd-modules-load reads these)
echo "bonding" | sudo tee /etc/modules-load.d/bonding.conf

# Verify modules-load.d is processed at boot
systemctl status systemd-modules-load.service

Kernel Module Parameters and Configuration

Many kernel modules accept parameters that change their behavior. You can pass parameters at load time or set defaults in configuration files.

# Pass parameter at load time
sudo modprobe snd-hda-intel power_save=1

# Check current parameter values for a loaded module
cat /sys/module/snd_hda_intel/parameters/power_save

# Set default parameters via modprobe configuration
# Create or edit a file in /etc/modprobe.d/
# File naming: use a descriptive name ending in .conf
# /etc/modprobe.d/snd-hda-intel.conf
options snd-hda-intel power_save=1 power_save_controller=Y

Parameters set in /etc/modprobe.d/*.conf files apply every time the module loads, including at boot. This is the production-safe way to configure module behavior persistently.

Viewing and changing parameters at runtime

Some module parameters can be changed while the module is loaded, without unloading and reloading:

# List all writable parameters for a module
ls -la /sys/module/snd_hda_intel/parameters/
# -rw-r--r-- 1 root root  power_save        (writable)
# -r--r--r-- 1 root root  index             (read-only)

# Change a writable parameter at runtime
echo 0 | sudo tee /sys/module/snd_hda_intel/parameters/power_save

# Verify the change took effect
cat /sys/module/snd_hda_intel/parameters/power_save

The /etc/modprobe.d/ Configuration Directory

This directory holds all modprobe configuration. Files must end in .conf. Common directives:

# Set default options for a module
options iwlwifi power_save=0 11n_disable=1

# Create a module alias (maps a device ID to a module)
alias pci:v00008086d00001533sv*sd*bc*sc*i* igb

# Run a command when a module loads or unloads
install pcspkr /bin/true
remove pcspkr /bin/true

# Blacklist a module (prevent automatic loading)
blacklist nouveau

Distribution packages often ship their own files here. On RHEL 10.1 and Fedora 43, look for files like /etc/modprobe.d/blacklist.conf and distribution-specific tuning files. Always create your own files with descriptive names rather than editing distribution-provided ones; this survives package updates.

Blacklisting Kernel Modules in Linux

Blacklisting kernel modules prevents a module from loading automatically. This is commonly needed when:

  • An open-source driver conflicts with a proprietary one (classic example: nouveau vs nvidia).
  • A buggy module causes kernel panics or hardware lockups on specific hardware.
  • A module loads for hardware you want to pass through to a virtual machine (GPU passthrough with VFIO).
  • Security hardening requires disabling unnecessary modules that expand the kernel's attack surface.
# /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0

The blacklist directive only prevents automatic loading by udev and module aliases. A manual modprobe nouveau still works. If you need to absolutely prevent loading under any circumstances, use the install directive to redirect to /bin/true:

# /etc/modprobe.d/block-nouveau.conf
# This makes any attempt to load nouveau silently succeed with nothing loaded
install nouveau /bin/true

After changing blacklist configuration, rebuild the initramfs so the blacklist takes effect during early boot:

# Debian 13.3 / Ubuntu 24.04.3 LTS
sudo update-initramfs -u

# Fedora 43 / RHEL 10.1
sudo dracut --force

Verifying that a module is properly blacklisted

After applying a blacklist, always verify it works as expected:

# Check if a module is currently loaded
lsmod | grep nouveau

# Check blacklist status in modprobe configuration
modprobe --showconfig | grep nouveau
# Expected: blacklist nouveau
# Expected: install nouveau /bin/true

# Test that modprobe respects the blacklist
modprobe -n -v nouveau
# Should show: install /bin/true

# After reboot, confirm the module did not load
lsmod | grep nouveau   # Should return nothing

depmod: Rebuilding the Linux Module Dependency Database

When you add or remove module files manually (outside the package manager), the dependency database becomes stale. depmod rescans the module tree and regenerates modules.dep, modules.alias, and related index files.

# Rebuild dependency database for the running kernel
sudo depmod -a

# Rebuild for a specific kernel version
sudo depmod -a 6.12.8-custom

# Verify the database (check for missing symbols)
sudo depmod -e

You rarely need to run depmod manually. Package managers and make modules_install call it automatically. The main case is after you copy a .ko file into the module tree by hand, which happens with vendor-supplied binary drivers or during development.

DKMS: Dynamic Kernel Module Support for Out-of-Tree Drivers

DKMS (Dynamic Kernel Module Support) solves a real problem: when you install a kernel update, out-of-tree modules need to be rebuilt against the new kernel headers. Without DKMS, you would have to manually recompile after every kernel update. DKMS automates this entire process.

How DKMS works

DKMS registers a module's source code and a build recipe. When a new kernel is installed, DKMS hooks (triggered by the package manager) automatically build and install the module for the new kernel version.

# Install DKMS
# Debian 13.3 / Ubuntu 24.04.3 LTS
sudo apt install dkms

# Fedora 43 / RHEL 10.1
sudo dnf install dkms

DKMS workflow: add, build, install

Suppose you have a third-party driver source in /usr/src/acme-1.0/ with a dkms.conf file:

# Example /usr/src/acme-1.0/dkms.conf
PACKAGE_NAME="acme"
PACKAGE_VERSION="1.0"
BUILT_MODULE_NAME[0]="acme"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"
MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules"
CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean"
# Register the module source with DKMS
sudo dkms add -m acme -v 1.0

# Build for the running kernel
sudo dkms build -m acme -v 1.0

# Install the built module
sudo dkms install -m acme -v 1.0

# Check status of all DKMS modules
dkms status

# Example output:
# acme/1.0, 6.12.8-200.fc43.x86_64, x86_64: installed
# nvidia/560.35.03, 6.12.8-200.fc43.x86_64, x86_64: installed

Real-world DKMS use cases include NVIDIA GPU drivers, VirtualBox host modules, ZFS on Linux, and WireGuard (before it was merged mainline in 5.6). On RHEL 10.1 with ELRepo, many hardware drivers are distributed as DKMS packages.

Troubleshooting DKMS build failures

When a DKMS build fails after a kernel update, use these steps to diagnose and resolve the issue:

# Check DKMS status to identify failed builds
dkms status
# acme/1.0, 6.13.1-200.fc43.x86_64, x86_64: broken

# View the build log for details
cat /var/lib/dkms/acme/1.0/build/make.log

# Common fix: install the correct kernel headers
# Debian 13.3 / Ubuntu 24.04.3 LTS
sudo apt install linux-headers-$(uname -r)

# Fedora 43 / RHEL 10.1
sudo dnf install kernel-devel-$(uname -r)

# Retry the build
sudo dkms build -m acme -v 1.0 -k $(uname -r)
sudo dkms install -m acme -v 1.0 -k $(uname -r)

Signing Kernel Modules for Secure Boot

With Secure Boot enabled, the kernel refuses to load unsigned modules. This affects any module built outside the distribution's build system, including all DKMS-built modules. For a comprehensive understanding of Secure Boot, see the article on Secure Boot and bootloader hardening on Linux.

The MOK (Machine Owner Key) workflow

# Generate a signing key pair
openssl req -new -x509 -newkey rsa:2048 -keyout /root/mok-signing.key \
  -outform DER -out /root/mok-signing.der -nodes -days 36500 \
  -subj "/CN=Custom Module Signing Key/"

# Enroll the public key in the firmware's MOK database
sudo mokutil --import /root/mok-signing.der
# This prompts for a one-time password. On the next reboot, the UEFI
# shim bootloader will ask you to confirm enrollment.

# Sign a module
sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 \
  /root/mok-signing.key /root/mok-signing.der \
  /lib/modules/$(uname -r)/updates/acme.ko

# On Debian, the sign-file tool is at:
# /usr/lib/linux-kbuild-$(uname -r | cut -d. -f1-2)/scripts/sign-file

For DKMS, you can automate signing by configuring /etc/dkms/framework.conf:

# /etc/dkms/framework.conf (add these lines)
mok_signing_key=/root/mok-signing.key
mok_certificate=/root/mok-signing.der
sign_tool="/usr/lib/linux-kbuild-${kernelver%%-*}/scripts/sign-file"

After this, every dkms install will automatically sign the module. This is critical on Fedora 43 and RHEL 10.1, which enforce Secure Boot more aggressively than many Debian installations.

Verifying module signatures

# Check if a module is signed
modinfo acme | grep sig
# sig_id:     PKCS#7
# signer:     Custom Module Signing Key
# sig_hashalgo: sha256

# Check Secure Boot status
mokutil --sb-state
# SecureBoot enabled

# List enrolled MOK keys
mokutil --list-enrolled

Quick Reference - Cheats

Task Command
List loaded modules lsmod
Module details modinfo <module>
Load module with dependencies sudo modprobe <module>
Load with parameters sudo modprobe <module> param=value
Remove module sudo modprobe -r <module>
Persist module at boot echo "<mod>" > /etc/modules-load.d/<mod>.conf
Blacklist a module echo "blacklist <mod>" > /etc/modprobe.d/blacklist-<mod>.conf
Hard-block a module echo "install <mod> /bin/true" > /etc/modprobe.d/block-<mod>.conf
Rebuild module deps sudo depmod -a
DKMS add/build/install sudo dkms add/build/install -m <name> -v <ver>
DKMS status dkms status
Enroll MOK key sudo mokutil --import <key.der>
Check module parameters cat /sys/module/<mod>/parameters/<param>

Summary

Kernel module management on modern Linux (Debian 13.3, Ubuntu 24.04.3 LTS, Fedora 43, RHEL 10.1) centers on modprobe for loading and unloading, /etc/modprobe.d/ for persistent configuration, and DKMS for keeping out-of-tree modules in sync with kernel updates. Blacklisting kernel modules is straightforward but remember to regenerate the initramfs so changes take effect at early boot. With Secure Boot increasingly enforced, signing custom modules via MOK keys is no longer optional on many production systems. The combination of modprobe, DKMS, and proper module signing gives you reliable module management across kernel updates without manual rebuilds or boot surprises. These skills connect directly to hardware detection with udev, sysfs, and procfs, where modules are loaded in response to hardware events detected by the kernel.

Share this article
X / Twitter LinkedIn Reddit