Table of Contents
Introduction
Kernel modules let the Linux kernel gain new features without rebuilding or rebooting the whole system. They are pieces of code that the kernel can load into memory when needed and remove again later. This flexibility is one of the reasons Linux can run on tiny embedded boards, desktop systems, and large servers with very different hardware, yet use the same base kernel.
This chapter focuses on the practical and conceptual aspects that are specific to kernel modules: what they are, how they are built and named, how they are discovered and loaded, and how to inspect and manage them from a running system. Broader topics such as general kernel concepts and kernel compilation are covered elsewhere in this part of the course and will not be repeated here.
What Kernel Modules Are
A kernel module is compiled code that runs in kernel space and integrates directly with the kernel once loaded. In most systems modules are stored as files with the .ko extension, which stands for “kernel object”. When a module is inserted, it becomes part of the kernel image in memory and can provide capabilities such as hardware drivers, filesystems, network protocols, or security features.
Modules are closely tied to a specific kernel version. The kernel exposes internal interfaces, and modules must match those interfaces. This means a module compiled for one kernel release usually cannot be loaded into a different one. On normal distributions, modules for each installed kernel are stored under a directory that includes the kernel version, such as:
/lib/modules/$(uname -r)/
Inside this directory you find subdirectories for different types of modules, for example kernel/drivers, kernel/fs, and kernel/net. The kernel and user space tools search these locations when you request a module to be loaded.
Kernel modules run in kernel space with full privileges. A buggy or malicious module can crash the system or compromise security completely.
Static vs Modular Kernel Features
A feature can exist in the kernel in one of two ways. It can be built in, which means it is part of the monolithic kernel image and is always present as long as that kernel is running. Or it can be built as a module, which means the kernel has support for that feature only when the module is loaded.
From the perspective of kernel configuration and compilation, this distinction is important, but here we focus on what it means at runtime. For a built in feature there is no module to load or unload. For a modular feature you will find a .ko file and can use module management tools to control it.
A common pattern in distributions is to build many hardware drivers as modules. This reduces the core kernel size and allows on demand loading, which becomes helpful especially during boot when only some of the available hardware is present.
Inspecting Loaded Modules with `lsmod`
To see which modules are currently active in a running system, use the lsmod command. This utility reads from /proc/modules and formats the information into a readable table. A typical invocation is just:
lsmod
The output columns show the module name, the size in bytes, and how many references to it exist through other modules. Some distributions also show the module’s dependencies on the right.
If a module has a nonzero “Used by” count, this usually means that other modules or parts of the kernel are using it, and it cannot be safely removed until those users are gone. Understanding this count is important when you attempt to unload modules.
lsmod is read only. It does not change system state. It is safe to run at any time and is a key first step when you troubleshoot hardware or kernel related behavior because you can verify whether the expected driver or feature module is actually loaded.
Loading Modules Manually: `insmod` and `modprobe`
To introduce a new module into the running kernel, you can use either insmod or modprobe. These commands serve similar purposes but behave quite differently.
insmod is a very low level tool that inserts a single specified .ko file into the kernel. It does not perform dependency resolution, path searching, or intelligent parameter handling. You invoke it with a direct path to the module file, such as:
sudo insmod /lib/modules/$(uname -r)/kernel/drivers/.../driver_name.ko
If this module depends on other modules, you must load those first yourself. For this reason insmod is mostly used in controlled or experimental scenarios, for example when testing a freshly compiled module that has not been installed into the usual directory tree.
modprobe is the higher level and more user friendly interface. It knows where to search for modules, reads configuration from /etc/modprobe.d/, and can automatically load required dependencies. For most administrative work you should use:
sudo modprobe module_name
Here you specify the module by its name, not its path. modprobe looks up the correct path and the dependency chain using information that depmod prepares in the modules.dep files under /lib/modules/$(uname -r)/.
modprobe also supports passing module parameters on the command line. These parameters change how the module behaves once loaded. They are often documented in the module’s own help text, documentation files, or kernel documentation. For example:
sudo modprobe module_name option1=value option2=value2
When working with modules in a distribution environment, prefer modprobe over insmod to benefit from dependency handling and configuration integration.
Removing Modules: `rmmod` and `modprobe -r`
To detach a module from the running kernel, you can remove it with rmmod or with modprobe -r. As with insertion, one of these is low level and one is higher level.
rmmod expects a module name and tries to unload it directly:
sudo rmmod module_name
If the module is in use, removal will fail. The kernel will not allow you to remove a module that has active references, because doing so could crash the system. To see what is using a module, you can inspect the “Used by” column of lsmod. In some cases you can stop the service or unload the dependent modules first.
modprobe -r is more sophisticated and can handle dependency chains. When you run:
sudo modprobe -r module_name
it attempts to remove the requested module and any modules that depend only on it, in the correct order. This makes it easier to cleanly remove a stack of related modules such as USB or filesystem layers.
Both removal mechanisms respect basic safety checks. However, removing core modules on a live system can still cause disruption. For normal day to day administration, unloading hardware drivers on a production machine is rare and should be done with care.
Discovering Module Information with `modinfo`
The modinfo tool displays metadata about a kernel module. This metadata is embedded when the module is built and can include the module description, author, license, supported devices, and parameter names.
You can run modinfo in two main ways. If the module is installed in the standard directories, you can just give its name:
modinfo module_name
modinfo will search under /lib/modules/$(uname -r)/ and show the information for the matching file. Alternatively, you can provide an explicit path to a .ko file that you have compiled or obtained separately:
modinfo ./my_module.ko
The output includes useful fields such as:
filename which shows the absolute path to the module file.
license which indicates the license terms. The kernel treats some licenses specially.
description a short text about what the module does.
alias patterns that connect the module to certain hardware identifiers or subsystems.
parm parameters that can be set when loading the module or through sysfs. Each parameter entry usually includes its type and a short description.
modinfo is particularly important when you need to know which options you can pass to a module at load time, or when you are examining a module binary that was built externally.
Automatic Module Loading and `udev`
Although manual insertion and removal are useful for learning and troubleshooting, most kernel modules are loaded and unloaded automatically as the system interacts with hardware and features. The kernel, together with the userspace device manager, uses hardware identifiers and modalias strings to select suitable modules.
When new hardware appears, such as when you plug in a USB device, the kernel generates a uevent. udev, the userspace component that manages device nodes under /dev, receives this event and examines attributes like vendor and product IDs. It then compares these attributes to modalias rules that associate device patterns with kernel modules.
If a matching modalias is found, udev calls modprobe with the appropriate module name. This way, the right driver module is loaded without user involvement. The inverse can happen when hardware is removed. In some setups the system unloads drivers that are no longer needed, although many distributions leave drivers loaded to avoid churn.
Modalias information is visible in a few places. For example, some entries under /sys contain strings that indicate which module alias patterns match the device. The modinfo aliases show the space of devices that a module supports. When modprobe is asked to load a module using a modalias, it finds the correct module even if you do not know its exact name.
For administrators, this means that in many cases it is enough to ensure that the appropriate module packages are installed. The system itself will take care of detecting hardware and loading the modules using the udev and modprobe integration.
Module Parameters and Configuration
Kernel modules frequently expose parameters that fine tune behavior. These parameters can control aspects such as debugging verbosity, performance trade offs, default options, and device specific quirks. You can set parameters when you load the module or, for many parameters, change them at runtime via sysfs.
To load a module with parameters, pass them after the name in the modprobe command:
sudo modprobe module_name param1=value param2=value
The valid parameter names and types can be discovered using modinfo in the parm entries. Some parameters are simple booleans, others are integers, strings, or arrays.
For persistent configuration, distributions provide the /etc/modprobe.d/ directory. You can create configuration files here that instruct modprobe how to treat certain modules every time they are loaded. The syntax usually follows a line oriented format, for example:
options module_name param1=value param2=value
or
alias shortname real_module_name
These files are read whenever modprobe operates, including when it is invoked indirectly by udev. This allows you to set consistent driver behavior across reboots without touching kernel command lines or updating compiled modules.
Many module parameters appear in the sysfs tree under /sys/module/module_name/parameters/. If a parameter is read write, you can change it during runtime by echoing new values into the corresponding file. For example:
echo 1 | sudo tee /sys/module/module_name/parameters/debug
This approach lets you adjust tunables without reloading the module, although not every parameter supports this mode. Reading the parameter file shows the current value.
Be careful when changing module parameters, especially on production systems. Some settings can severely degrade performance or cause hardware or protocol misbehavior.
Blacklisting Modules
Sometimes you need to prevent a specific module from loading. This can be necessary when a driver conflicts with another, when a particular module is unstable on your hardware, or when security policy requires that support for some functionality stay disabled.
You can instruct modprobe not to load a module by blacklisting it in a configuration file under /etc/modprobe.d/. For example, a line like:
blacklist module_name
tells modprobe to refuse loading that module when requested by alias resolution. You can still explicitly load the module via direct commands in some configurations, but automatic loading by modalias will be blocked.
Another pattern is to override the module’s alias or name with a harmless stub using install directives, for example:
install module_name /bin/false
which makes any attempt to load that module simply execute /bin/false instead. This is stricter than a simple blacklist and can be used where a stronger guarantee is desired.
After blacklisting or overriding modules, you typically do not need to regenerate any indexes, but you might need to rebuild your initramfs if the module is referenced early in the boot process in the initramfs image. That process is part of kernel boot management and is treated elsewhere.
Blacklisting does not remove a module that is already loaded. It only applies to future load operations. To enforce the effect immediately, you also remove the module with modprobe -r or rmmod if it is not in use.
Module Dependency Management with `depmod`
Modules often rely on other modules. For example, a particular filesystem driver might depend on a generic block driver, or a USB peripheral driver might depend on a core USB subsystem module. The kernel and modprobe need to know this dependency graph so they can load modules in the correct order.
The depmod tool scans the module tree under /lib/modules/$(uname -r)/ and reads the module binaries to discover which symbols they require and export. It then writes out files such as modules.dep that map each module to the list of other modules it depends upon. These files are what modprobe uses when it calculates which modules to load when you request a single name.
In normal distribution workflows depmod runs automatically whenever you install a new kernel or new modules. For example, when you install a driver from a package, the post installation scripts usually call depmod -a to refresh the dependency listing. If you compile and place a module manually in the correct directory tree, you can run sudo depmod yourself to ensure the system will recognize the new dependency information.
If dependency information is out of date, modprobe might fail to load the necessary supporting modules, which can lead to confusing errors. Knowing that depmod is the tool that maintains these indexes helps you troubleshoot such problems when they arise.
Custom Modules and Out-of-Tree Drivers
Modules are not only built as part of the kernel source tree. Many vendors and developers provide out of tree modules. These are drivers or features that are maintained separately from the mainline kernel and shipped as binary or source packages that plug into an existing kernel.
As an administrator, you may sometimes install such modules, often for specialized hardware or proprietary functionality. The installation process usually places the .ko file under an appropriate subdirectory in /lib/modules/$(uname -r)/extra/ or a similar path. It then runs depmod and sometimes rebuilds the initramfs.
Because these modules must match the exact kernel build, updating the kernel often requires corresponding updated versions of the out of tree modules. Distribution tooling sometimes automates this rebuilding, for example through DKMS (Dynamic Kernel Module Support). DKMS automatically recompiles registered modules whenever a new kernel is installed, provided the module source is available.
The details of compiling modules and integrating them with DKMS are part of broader kernel compilation and packaging topics. In the context of this chapter it is important to understand that out of tree modules behave at runtime like any other module. You use the same modprobe, lsmod, modinfo, and related tools to manage them.
Security and Stability Considerations
Loading a kernel module introduces code that runs with full system privileges. From a security perspective, this is equivalent to modifying the kernel itself. Because of this, modern kernels and distributions offer mechanisms to control who can load modules and which modules are accepted.
Some systems use mechanisms such as module signature verification, where modules are signed with cryptographic keys and the kernel will load only modules signed by keys in its trusted keyring. Combined with secure boot on UEFI systems, this can ensure that only trusted modules run in kernel space.
In addition to formal verification, administrative policy plays a role. Restricting root access, limiting the availability of module building tools on production systems, and using blacklists for unnecessary drivers all contribute to a more controlled kernel environment.
From a stability standpoint, poorly written modules can cause system crashes, deadlocks, memory corruption, or subtle data integrity issues. Because modules operate at the same privilege level as the core kernel, they do not benefit from the isolation that protects normal user processes. Whenever you load third party modules in sensitive environments, evaluate their quality and support status carefully.
Treat loading a new kernel module on a production system as a significant change. Plan, test, and monitor as you would with a kernel upgrade.
Summary
Kernel modules are the mechanism that lets the Linux kernel adapt dynamically to different hardware and features. They live as .ko files under /lib/modules/$(uname -r)/ and can be loaded, configured, and unloaded while the system runs.
You inspect modules with lsmod, query their metadata with modinfo, insert them with modprobe or insmod, and remove them with modprobe -r or rmmod. Automatic loading through udev and modalias matching handles most hardware scenarios without manual intervention, while configuration under /etc/modprobe.d/ lets you set parameters, aliases, and blacklists persistently.
Dependency management with depmod, integration of out of tree modules, and security controls around module loading round out the practical toolkit. Understanding these aspects prepares you to work confidently with kernel modules, which is essential when you manage diverse Linux systems and need precise control over how the kernel interacts with hardware and extensions.