Inside Linux Kernel Modules

Modules are pieces of code that extend the Linux kernel‘s functionality. They enable custom features to be added or removed dynamically without needing to rebuild the entire kernel. This modularity and flexibility is a key advantage of the Linux kernel design.

Common types of modules include:

  • Device drivers – To support hardware like graphics cards, printers, Wi-Fi adapters
  • File systems – For mounting disks formatted with ext4, XFS, Btrfs
  • Network protocols – Adding support for IPv6, VPN tunnels, container networking
  • Security frameworks – Such as SElinux, AppArmor and Seccomp policies

Modules allow Linux to natively handle an incredible variety of hardware configurations quickly and efficiently. Hotplugging devices will automatically trigger module loading. By keeping modules independent of the core kernel code, bugs and crashes can be isolated and avoided from spreading system-wide.

Anatomy of a Kernel Module

While functionally extensions of the kernel, modules actually run in user space. Communication with the kernel is handled via module interfaces. These require no modifications to the base kernel source itself.

Diagram showing kernel space vs user space

Structurally, a module consists of object code from compiled C source code. The module binary will export initialization and exit functions to integrate into kernel runtime operations. Important metadata is also embedded into the module itself:

module/
  |-- /description - Purpose of module  
  |-- /author - Creator  
  |-- /license - Usage rights  
  |-- /srcversion - Compile version 
  |-- /depends - Kernel dependencies
  |-- /init - Initialization tasks

When loading a module, the kernel will check these dependencies to ensure consistency. The next section covers managing modules in more detail with modprobe.

Meet Modprobe: The Module Manager

The modprobe utility streamlines working with modules from user space. It serves as an intelligent wrapper around manual insmod commands. While insmod inserts modules directly, it does not resolve dependencies itself. This is the advantage of modprobe – it will handle dependency checks and recursive loading automatically.

Common modprobe operations include:

  • Listing currently loaded modules
  • Printing metadata and help text for unloaded modules
  • Loading modules by filename or module name
  • Removing or unloading modules
  • Blacklisting and removing modules from future loading

In addition to dependency management, modprobe allows module loading operations to be run by non-privileged users via configuration file rules. The main files controlling module behavior are:

/etc/modprobe.conf
/etc/modprobe.d/*.conf

For distributions like Debian, module configuration is typically handled by the package manager upon install. But for upstream kernel code, modules will need configuration to allow user-space loading. This helps avoid needing root privileges for common use cases like storage drivers.

Where Modules Are Stored on Debian

When installed via a package manager, modules reside in the following standardized path. This is populated by dkms tooling:

/lib/modules/$(uname -r)/
└── kernel
    ├── drivers
    ├── fs
    ├── sound
    └── more categories...

The $(uname -r) pattern always points to modules matched to your current kernel release. As kernel versions increment with Debian updates, old module directories are preserved to prevent breaking upgrades. Running uname -r returns the active release number.

Now with the basics covered, let‘s move on to day-to-day module management.

Managing Modules

Listing Loaded Modules

Check currently loaded modules using lsmod, like so:

$ lsmod

This prints active modules with their memory footprint, dependencies, and usage counts. A zero means no other modules rely on it, while 2+ indicates other module subscribers:

lsmod sample output

You can see this sparse output produces a quick yet information-rich summary. Now use modinfo to learn more on any module present.

Inspecting Module Details

The modinfo command reveals insightful metadata like descriptions, authors, parameters, and licenses. It surfaces everything defined in the module binary itself. Try it out:

$ modinfo snd_pcm

Detailed modinfo output

I frequently use modinfo to lookup module functionality and runtime traits prior to loading new code. The dependency chain info is also useful to have during troubleshooting. Now let‘s move on to loading modules.

Loading Modules with Modprobe

Modprobe inserts modules intelligently, resolving dependency chains needed by the target module. For example, to activate the btrfs driver:

$ sudo modprobe btrfs

This will auto-load the intermediate xor and raid6_pq modules as well. We can validate everything loaded properly with the earlier lsmod command:

btrfs successfully loaded

Loading modules dynamically like this prevents rebooting or rebuilding initramfs images. Both of those operations have higher overhead. Let‘s discuss how to properly clean things up next.

Removing Modules

To reverse module loading, utilize the modprobe -r option instead of rmmod. This will recursively unload dependencies and handle the unwinding automatically:

$ sudo modprobe -r btrfs  

Success is quickly verified by piping lsmod through grep to check the target module was removed:

$ lsmod | grep btrfs
(No output means module successfully unloaded)

I prefer modprobe‘s recursion because it prevents orphaned children modules causing issues. Now we‘ll explore some advanced topics and best practices.

Advanced Module Management

Preventing Future Loads with Blacklisting

If you need to prevent automatic module loading, leverage blacklist config files. Simply add a conf under modprobe.d overriding the target module:

$ cat /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau

This guarantees the nouveau video driver will never load again for the configured hardware. Creating selective blacklists is wise if particular modules cause stability issues or other bugs.

Hardening with Signed Modules

From a security perspective, ensure any new modules come properly signed by a trusted party like the Debian maintainers. Unsigned code can not enforce integrity checks or non-repudiation. Attempting to load unsigned modules by default will fail:

Requirement of signatures prevents arbitrary code or malware from running with kernel space privileges. Modules altered after installation also correctly error out. This protects against supply-chain attacks via compromised mirrors.

Streamlining Updates using DKMS

As a final best practice, leverage DKMS to centrally manage module updates synchronized to kernel revisions. This dynamical kernel module support framework tracks module version dependencies, automatically recompiling against new kernels. DKMS integration helps ensure smooth upgrades across machines.

For custom modules not originating from a Debian package, integrating with DKMS prevents needing to manually reinstall each Linux kernel release. Take advantage of this automation!

Conclusion

Mastering modprobe provides extensive control over Linux modules with efficiency and safety. Follow the recommendations covered to reap flexibility benefits while avoiding stability and security pitfalls. Let me know if any part of leveraging modules remains unclear!

Similar Posts