Chapter 1. Working with kernel modules

This Chapter explains:

  • What is a kernel module.
  • How to use the kmod utilities to manage modules and their dependencies.
  • How to configure module parameters to control behavior of the kernel modules.
  • How to load modules at boot time.
Note

In order to use the kernel module utilities described in this chapter, first ensure the kmod package is installed on your system by running, as root:

# yum install kmod

1.1. What is a kernel module?

The Linux kernel is monolithic by design. However, it is compiled with optional or additional modules as required by each use case. This means that you can extend the kernel’s capabilities through the use of dynamically-loaded kernel modules. A kernel module can provide:

  • A device driver which adds support for new hardware.
  • Support for a file system such as GFS2 or NFS.

Like the kernel itself, modules can take parameters that customize their behavior. Though the default parameters work well in most cases. In relation to kernel modules, user-space tools can do the following operations:

  • Listing modules currently loaded into a running kernel.
  • Querying all available modules for available parameters and module-specific information.
  • Loading or unloading (removing) modules dynamically into or from a running kernel.

Many of these utilities, which are provided by the kmod package, take module dependencies into account when performing operations. As a result, manual dependency-tracking is rarely necessary.

On modern systems, kernel modules are automatically loaded by various mechanisms when needed. However, there are occasions when it is necessary to load or unload modules manually. For example, when one module is preferred over another although either is able to provide basic functionality, or when a module performs unexpectedly.

1.2. Kernel module dependencies

Certain kernel modules sometimes depend on one or more other kernel modules. The /lib/modules/<KERNEL_VERSION>/modules.dep file contains a complete list of kernel module dependencies for the respective kernel version.

The dependency file is generated by the depmod program, which is a part of the kmod package. Many of the utilities provided by kmod take module dependencies into account when performing operations so that manual dependency-tracking is rarely necessary.

Warning

The code of kernel modules is executed in kernel-space in the unrestricted mode. Because of this, you should be mindful of what modules you are loading.

Additional resources

  • For more information about /lib/modules/<KERNEL_VERSION>/modules.dep, refer to the modules.dep(5) manual page.
  • For further details including the synopsis and options of depmod, see the depmod(8) manual page.

1.3. Listing currently-loaded modules

You can list all kernel modules that are currently loaded into the kernel by running the lsmod command, for example:

# lsmod
Module                  Size  Used by
tcp_lp                 12663  0
bnep                   19704  2
bluetooth             372662  7 bnep
rfkill                 26536  3 bluetooth
fuse                   87661  3
ebtable_broute         12731  0
bridge                110196  1 ebtable_broute
stp                    12976  1 bridge
llc                    14552  2 stp,bridge
ebtable_filter         12827  0
ebtables               30913  3 ebtable_broute,ebtable_nat,ebtable_filter
ip6table_nat           13015  1
nf_nat_ipv6            13279  1 ip6table_nat
iptable_nat            13011  1
nf_conntrack_ipv4      14862  4
nf_defrag_ipv4         12729  1 nf_conntrack_ipv4
nf_nat_ipv4            13263  1 iptable_nat
nf_nat                 21798  4 nf_nat_ipv4,nf_nat_ipv6,ip6table_nat,iptable_nat
[output truncated]

The lsmod output specifies three columns:

  • Module

    • The name of a kernel module currently loaded in memory.
  • Size

    • The amount of memory the kernel module uses in kilobytes.
  • Used by

    • A decimal number representing how many dependencies there are on the Module field.
    • A comma separated string of dependent Module names. Using this list, you can first unload all the modules depending on the module you want to unload.

Finally, note that lsmod output is less verbose and considerably easier to read than the content of the /proc/modules pseudo-file.

1.4. Displaying information about a module

You can display detailed information about a kernel module using the modinfo <MODULE_NAME> command.

Note

When entering the name of a kernel module as an argument to one of the kmod utilities, do not append a .ko extension to the end of the name. Kernel module names do not have extensions; their corresponding files do.

Example 1.1. Listing information about a kernel module with lsmod

To display information about the e1000e module, which is the Intel PRO/1000 network driver, enter the following command as root:

# modinfo e1000e
filename:       /lib/modules/3.10.0-121.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
version:        2.3.2-k
license:        GPL
description:    Intel(R) PRO/1000 Network Driver
author:         Intel Corporation,

1.5. Loading kernel modules at system runtime

The optimal way to expand the functionality of the Linux kernel is by loading kernel modules. The following procedure describes how to use the modprobe command to find and load a kernel module into the currently running kernel.

Prerequisites

  • Root permissions.
  • The kmod package is installed.
  • The respective kernel module is not loaded. To ensure this is the case, see Listing Currently Loaded Modules.

Procedure

  1. Select a kernel module you want to load.

    The modules are located in the /lib/modules/$(uname -r)/kernel/<SUBSYSTEM>/ directory.

  2. Load the relevant kernel module:

    # modprobe <MODULE_NAME>
    Note

    When entering the name of a kernel module, do not append the .ko.xz extension to the end of the name. Kernel module names do not have extensions; their corresponding files do.

  3. Optionally, verify the relevant module was loaded:

    $ lsmod | grep <MODULE_NAME>

    If the module was loaded correctly, this command displays the relevant kernel module. For example:

    $ lsmod | grep serio_raw
    serio_raw              16384  0
Important

The changes described in this procedure will not persist after rebooting the system. For information on how to load kernel modules to persist across system reboots, see Loading kernel modules automatically at system boot time.

Additional resources

  • For further details about modprobe, see the modprobe(8) manual page.

1.6. Unloading kernel modules at system runtime

At times, you find that you need to unload certain kernel modules from the running kernel. The following procedure describes how to use the modprobe command to find and unload a kernel module at system runtime from the currently loaded kernel.

Prerequisites

  • Root permissions.
  • The kmod package is installed.

Procedure

  1. Execute the lsmod command and select a kernel module you want to unload.

    If a kernel module has dependencies, unload those prior to unloading the kernel module. For details on identifying modules with dependencies, see Listing Currently Loaded Modules and Kernel module dependencies.

  2. Unload the relevant kernel module:

    # modprobe -r <MODULE_NAME>

    When entering the name of a kernel module, do not append the .ko.xz extension to the end of the name. Kernel module names do not have extensions; their corresponding files do.

    Warning

    Do not unload kernel modules when they are used by the running system. Doing so can lead to an unstable or non-operational system.

  3. Optionally, verify the relevant module was unloaded:

    $ lsmod | grep <MODULE_NAME>

    If the module was unloaded successfully, this command does not display any output.

Important

After finishing this procedure, the kernel modules that are defined to be automatically loaded on boot, will not stay unloaded after rebooting the system. For information on how to counter this outcome, see Preventing kernel modules from being automatically loaded at system boot time.

Additional resources

  • For further details about modprobe, see the modprobe(8) manual page.

1.7. Loading kernel modules automatically at system boot time

The following procedure describes how to configure a kernel module so that it is loaded automatically during the boot process.

Prerequisites

  • Root permissions.
  • The kmod package is installed.

Procedure

  1. Select a kernel module you want to load during the boot process.

    The modules are located in the /lib/modules/$(uname -r)/kernel/<SUBSYSTEM>/ directory.

  2. Create a configuration file for the module:

    # echo <MODULE_NAME> > /etc/modules-load.d/<MODULE_NAME>.conf
    Note

    When entering the name of a kernel module, do not append the .ko.xz extension to the end of the name. Kernel module names do not have extensions; their corresponding files do.

  3. Optionally, after reboot, verify the relevant module was loaded:

    $ lsmod | grep <MODULE_NAME>

    The example command above should succeed and display the relevant kernel module.

Important

The changes described in this procedure will persist after rebooting the system.

Additional resources

  • For further details about loading kernel modules during the boot process, see the modules-load.d(5) manual page.

1.8. Preventing kernel modules from being automatically loaded at system boot time

The following procedure describes how to add a kernel module to a denylist so that it will not be automatically loaded during the boot process.

Prerequisites

  • Root permissions.
  • The kmod package is installed.
  • Ensure that a kernel module in a denylist is not vital for your current system configuration.

Procedure

  1. Select a kernel module that you want to put in a denylist:

    $ lsmod
    
    Module                  Size  Used by
    fuse                  126976  3
    xt_CHECKSUM            16384  1
    ipt_MASQUERADE         16384  1
    uinput                 20480  1
    xt_conntrack           16384  1
    …​

    The lsmod command displays a list of modules loaded to the currently running kernel.

    • Alternatively, identify an unloaded kernel module you want to prevent from potentially loading.

      All kernel modules are located in the /lib/modules/<KERNEL_VERSION>/kernel/<SUBSYSTEM>/ directory.

  2. Create a configuration file for a denylist:

    # vim /etc/modprobe.d/blacklist.conf
    
    	# Blacklists <KERNEL_MODULE_1>
    	blacklist <MODULE_NAME_1>
    	install <MODULE_NAME_1> /bin/false
    
    	# Blacklists <KERNEL_MODULE_2>
    	blacklist <MODULE_NAME_2>
    	install <MODULE_NAME_2> /bin/false
    
    	# Blacklists <KERNEL_MODULE_n>
    	blacklist <MODULE_NAME_n>
    	install <MODULE_NAME_n> /bin/false
    	…​

    The example shows the contents of the blacklist.conf file, edited by the vim editor. The blacklist line ensures that the relevant kernel module will not be automatically loaded during the boot process. The blacklist command, however, does not prevent the module from being loaded as a dependency for another kernel module that is not in a denylist. Therefore the install line causes the /bin/false to run instead of installing a module.

    The lines starting with a hash sign are comments to make the file more readable.

    Note

    When entering the name of a kernel module, do not append the .ko.xz extension to the end of the name. Kernel module names do not have extensions; their corresponding files do.

  3. Create a backup copy of the current initial ramdisk image before rebuilding:

    # cp /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).bak.$(date +%m-%d-%H%M%S).img

    The command above creates a backup initramfs image in case the new version has an unexpected problem.

    • Alternatively, create a backup copy of other initial ramdisk image which corresponds to the kernel version for which you want to put kernel modules in a denylist:

      # cp /boot/initramfs-<SOME_VERSION>.img /boot/initramfs-<SOME_VERSION>.img.bak.$(date +%m-%d-%H%M%S)
  4. Generate a new initial ramdisk image to reflect the changes:

    # dracut -f -v
    • If you are building an initial ramdisk image for a different kernel version than you are currently booted into, specify both target initramfs and kernel version:

      # dracut -f -v /boot/initramfs-<TARGET_VERSION>.img <CORRESPONDING_TARGET_KERNEL_VERSION>
  5. Reboot the system:

    $ reboot
Important

The changes described in this procedure will take effect and persist after rebooting the system. If you improperly put a key kernel module in a denylist, you can face an unstable or non-operational system.

Additional resources

  • For further details concerning the dracut utility, refer to the dracut(8) manual page.

1.9. Signing kernel modules for secure boot

Red Hat Enterprise Linux 7 includes support for the UEFI Secure Boot feature, which means that Red Hat Enterprise Linux 7 can be installed and run on systems where UEFI Secure Boot is enabled. Note that Red Hat Enterprise Linux 7 does not require the use of Secure Boot on UEFI systems.

If Secure Boot is enabled, the UEFI operating system boot loaders, the Red Hat Enterprise Linux kernel, and all kernel modules must be signed with a private key and authenticated with the corresponding public key. If they are not signed and authenticated, the system will not be allowed to finish the booting process.

The Red Hat Enterprise Linux 7 distribution includes:

  • Signed boot loaders
  • Signed kernels
  • Signed kernel modules

In addition, the signed first-stage boot loader and the signed kernel include embedded Red Hat public keys. These signed executable binaries and embedded keys enable Red Hat Enterprise Linux 7 to install, boot, and run with the Microsoft UEFI Secure Boot Certification Authority keys that are provided by the UEFI firmware on systems that support UEFI Secure Boot.

Note

Not all UEFI-based systems include support for Secure Boot.

The information provided in the following sections describes the steps to self-sign privately built kernel modules for use with Red Hat Enterprise Linux 7 on UEFI-based build systems where Secure Boot is enabled. These sections also provide an overview of available options for importing your public key into a target system where you want to deploy your kernel modules.

To sign and load kernel modules, you need to:

1.9.1. Prerequisites

To be able to sign externally built kernel modules, install the utilities listed in the following table on the build system.

Table 1.1. Required utilities

UtilityProvided by packageUsed onPurpose

openssl

openssl

Build system

Generates public and private X.509 key pair

sign-file

kernel-devel

Build system

Perl script used to sign kernel modules

perl

perl

Build system

Perl interpreter used to run the signing script

mokutil

mokutil

Target system

Optional utility used to manually enroll the public key

keyctl

keyutils

Target system

Optional utility used to display public keys in the system key ring

Note

The build system, where you build and sign your kernel module, does not need to have UEFI Secure Boot enabled and does not even need to be a UEFI-based system.

1.9.2. Kernel module authentication

In Red Hat Enterprise Linux 7, when a kernel module is loaded, the module’s signature is checked using the public X.509 keys on the kernel’s system key ring, excluding keys on the kernel’s system black-list key ring. The following sections provide an overview of sources of keys/keyrings, examples of loaded keys from different sources in the system. Also, the user can see what it takes to authenticate a kernel module.

1.9.2.1. Sources for public keys used to authenticate kernel modules

During boot, the kernel loads X.509 keys into the system key ring or the system black-list key ring from a set of persistent key stores as shown in the table below.

Table 1.2. Sources for system key rings

Source of X.509 keysUser ability to add keysUEFI Secure Boot stateKeys loaded during boot

Embedded in kernel

No

-

.system_keyring

UEFI Secure Boot "db"

Limited

Not enabled

No

Enabled

.system_keyring

UEFI Secure Boot "dbx"

Limited

Not enabled

No

Enabled

.system_keyring

Embedded in shim.efi boot loader

No

Not enabled

No

Enabled

.system_keyring

Machine Owner Key (MOK) list

Yes

Not enabled

No

Enabled

.system_keyring

If the system is not UEFI-based or if UEFI Secure Boot is not enabled, then only the keys that are embedded in the kernel are loaded onto the system key ring. In that case you have no ability to augment that set of keys without rebuilding the kernel.

The system black list key ring is a list of X.509 keys which have been revoked. If your module is signed by a key on the black list then it will fail authentication even if your public key is in the system key ring.

You can display information about the keys on the system key rings using the keyctl utility. The following is a shortened example output from a Red Hat Enterprise Linux 7 system where UEFI Secure Boot is not enabled.

# keyctl list %:.system_keyring
3 keys in keyring:
...asymmetric: Red Hat Enterprise Linux Driver Update Program (key 3): bf57f3e87...
...asymmetric: Red Hat Enterprise Linux kernel signing key: 4249689eefc77e95880b...
...asymmetric: Red Hat Enterprise Linux kpatch signing key: 4d38fd864ebe18c5f0b7...

The following is a shortened example output from a Red Hat Enterprise Linux 7 system where UEFI Secure Boot is enabled.

# keyctl list %:.system_keyring
6 keys in keyring:
...asymmetric: Red Hat Enterprise Linux Driver Update Program (key 3): bf57f3e87...
...asymmetric: Red Hat Secure Boot (CA key 1): 4016841644ce3a810408050766e8f8a29...
...asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed...
...asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e...
...asymmetric: Red Hat Enterprise Linux kernel signing key: 4249689eefc77e95880b...
...asymmetric: Red Hat Enterprise Linux kpatch signing key: 4d38fd864ebe18c5f0b7...

The above output shows the addition of two keys from the UEFI Secure Boot "db" keys as well as the Red Hat Secure Boot (CA key 1), which is embedded in the shim.efi boot loader. You can also look for the kernel console messages that identify the keys with an UEFI Secure Boot related source. These include UEFI Secure Boot db, embedded shim, and MOK list.

# dmesg | grep 'EFI: Loaded cert'
[5.160660] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a9290239...
[5.160674] EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309b...
[5.165794] EFI: Loaded cert 'Red Hat Secure Boot (CA key 1): 4016841644ce3a8...

1.9.2.2. Kernel module authentication requirements

This section explains what conditions have to be met for loading kernel modules on systems with enabled UEFI Secure Boot functionality.

If UEFI Secure Boot is enabled or if the module.sig_enforce kernel parameter has been specified, you can only load signed kernel modules that are authenticated using a key on the system key ring. In addition, the public key must not be on the system black list key ring.

If UEFI Secure Boot is disabled and if the module.sig_enforce kernel parameter has not been specified, you can load unsigned kernel modules and signed kernel modules without a public key. This is summarized in the table below.

Table 1.3. Kernel module authentication requirements for loading

Module signedPublic key found and signature validUEFI Secure Boot statesig_enforceModule loadKernel tainted

Unsigned

-

Not enabled

Not enabled

Succeeds

Yes

Not enabled

Enabled

Fails

-

Enabled

-

Fails

-

Signed

No

Not enabled

Not enabled

Succeeds

Yes

Not enabled

Enabled

Fails

-

Enabled

-

Fails

-

Signed

Yes

Not enabled

Not enabled

Succeeds

No

Not enabled

Enabled

Succeeds

No

Enabled

-

Succeeds

No

1.9.3. Generating a public and private X.509 key pair

You need to generate a public and private X.509 key pair to succeed in your efforts of using kernel modules on a Secure Boot-enabled system. You will later use the private key to sign the kernel module. You will also have to add the corresponding public key to the Machine Owner Key (MOK) for Secure Boot to validate the signed module. For instructions to do so, see Section 1.9.4.2, “System administrator manually adding public key to the MOK list”.

Some of the parameters for this key pair generation are best specified with a configuration file.

  1. Create a configuration file with parameters for the key pair generation:

    # cat << EOF > configuration_file.config
    [ req ]
    default_bits = 4096
    distinguished_name = req_distinguished_name
    prompt = no
    string_mask = utf8only
    x509_extensions = myexts
    
    [ req_distinguished_name ]
    O = Organization
    CN = Organization signing key
    emailAddress = E-mail address
    
    [ myexts ]
    basicConstraints=critical,CA:FALSE
    keyUsage=digitalSignature
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid
    EOF
  2. Create an X.509 public and private key pair as shown in the following example:

    # openssl req -x509 -new -nodes -utf8 -sha256 -days 36500 \
    -batch -config configuration_file.config -outform DER \
    -out my_signing_key_pub.der \
    -keyout my_signing_key.priv

    The public key will be written to the my_signing_key_pub.der file and the private key will be written to the my_signing_key.priv file.

  3. Enroll your public key on all systems where you want to authenticate and load your kernel module.

    For details, see Section 1.9.4, “Enrolling public key on target system”.

Warning

Apply strong security measures and access policies to guard the contents of your private key. In the wrong hands, the key could be used to compromise any system which is authenticated by the corresponding public key.

1.9.4. Enrolling public key on target system

When Red Hat Enterprise Linux 7 boots on a UEFI-based system with Secure Boot enabled, the kernel loads onto the system key ring all public keys that are in the Secure Boot db key database, but not in the dbx database of revoked keys. The sections below describe different ways of importing a public key on a target system so that the system key ring is able to use the public key to authenticate a kernel module.

1.9.4.1. Factory firmware image including public key

To facilitate authentication of your kernel module on your systems, consider requesting your system vendor to incorporate your public key into the UEFI Secure Boot key database in their factory firmware image.

1.9.4.2. System administrator manually adding public key to the MOK list

The Machine Owner Key (MOK) facility feature can be used to expand the UEFI Secure Boot key database. When Red Hat Enterprise Linux 7 boots on a UEFI-enabled system with Secure Boot enabled, the keys on the MOK list are also added to the system key ring in addition to the keys from the key database. The MOK list keys are also stored persistently and securely in the same fashion as the Secure Boot database keys, but these are two separate facilities. The MOK facility is supported by shim.efi, MokManager.efi, grubx64.efi, and the Red Hat Enterprise Linux 7 mokutil utility.

Enrolling a MOK key requires manual interaction by a user at the UEFI system console on each target system. Nevertheless, the MOK facility provides a convenient method for testing newly generated key pairs and testing kernel modules signed with them.

To add your public key to the MOK list:

  1. Request the addition of your public key to the MOK list:

    # mokutil --import my_signing_key_pub.der

    You will be asked to enter and confirm a password for this MOK enrollment request.

  2. Reboot the machine.

    The pending MOK key enrollment request will be noticed by shim.efi and it will launch MokManager.efi to allow you to complete the enrollment from the UEFI console.

  3. Enter the password you previously associated with this request and confirm the enrollment.

    Your public key is added to the MOK list, which is persistent.

Once a key is on the MOK list, it will be automatically propagated to the system key ring on this and subsequent boots when UEFI Secure Boot is enabled.

1.9.5. Signing kernel module with the private key

Assuming you have your kernel module ready:

  • Use a Perl script to sign your kernel module with your private key:

    # perl /usr/src/kernels/$(uname -r)/scripts/sign-file \
    sha256 \
    my_signing_key.priv\
    my_signing_key_pub.der\
    my_module.ko
    Note

    The Perl script requires that you provide both the files that contain your private and the public key as well as the kernel module file that you want to sign.

    Your kernel module is in ELF image format and the Perl script computes and appends the signature directly to the ELF image in your kernel module file. The modinfo utility can be used to display information about the kernel module’s signature, if it is present. For information on using modinfo, see Section 1.4, “Displaying information about a module”.

    The appended signature is not contained in an ELF image section and is not a formal part of the ELF image. Therefore, utilities such as readelf will not be able to display the signature on your kernel module.

    Your kernel module is now ready for loading. Note that your signed kernel module is also loadable on systems where UEFI Secure Boot is disabled or on a non-UEFI system. That means you do not need to provide both a signed and unsigned version of your kernel module.

1.9.6. Loading signed kernel module

Once your public key is enrolled and is in the system key ring, use mokutil to add your public key to the MOK list. Then manually load your kernel module with the modprobe command.

  1. Optionally, verify that your kernel module will not load before you have enrolled your public key.

    For details on how to list currently loaded kernel modules, see Section 1.3, “Listing currently-loaded modules”.

  2. Verify what keys have been added to the system key ring on the current boot:

    # keyctl list %:.system_keyring

    Since your public key has not been enrolled yet, it should not be displayed in the output of the command.

  3. Request enrollment of your public key:

    # mokutil --import my_signing_key_pub.der
  4. Reboot, and complete the enrollment at the UEFI console:

    # reboot
  5. Verify the keys on the system key ring again:

    # keyctl list %:.system_keyring
  6. Copy the module into the /extra/ directory of the kernel you want:

    # cp my_module.ko /lib/modules/$(uname -r)/extra/
  7. Update the modular dependency list:

    # depmod -a
  8. Load the kernel module and verify that it was successfully loaded:

    # modprobe -v my_module
    # lsmod | grep my_module
    1. Optionally, to load the module on boot, add it to the /etc/modules-loaded.d/my_module.conf file:

      # echo "my_module" > /etc/modules-load.d/my_module.conf