Chapter 1. Working with kernel modules
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: 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: 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 Select a kernel module you want to load. The modules are located in the /lib/modules/USD(uname -r)/kernel/<SUBSYSTEM>/ directory. Load the relevant kernel module: 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. Optionally, verify the relevant module was loaded: If the module was loaded correctly, this command displays the relevant kernel module. For example: 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 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 . Unload the relevant kernel module: 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. Optionally, verify the relevant module was unloaded: 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 Select a kernel module you want to load during the boot process. The modules are located in the /lib/modules/USD(uname -r)/kernel/<SUBSYSTEM>/ directory. Create a configuration file for the module: 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. Optionally, after reboot, verify the relevant module was loaded: 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 Select a kernel module that you want to put in a denylist: 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. Create a configuration file for a denylist: 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. Create a backup copy of the current initial ramdisk image before rebuilding: 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: Generate a new initial ramdisk image to reflect the changes: 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: Reboot the system: 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. For more information on preventing automatic loading of kernel modules at system boot time on Red Hat Enterprise Linux 8 and earlier versions, see How do I prevent a kernel module from loading automatically? 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: Have the relevant utilities installed on your system . Authenticate a kernel module . Generate a public and private key pair . Import the public key on the target system . Sign the kernel module with the private key . Load the signed kernel module . 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 Utility Provided by package Used on Purpose 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 keys User ability to add keys UEFI Secure Boot state Keys 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. The following is a shortened example output from a Red Hat Enterprise Linux 7 system where UEFI Secure Boot is enabled. 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. 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 signed Public key found and signature valid UEFI Secure Boot state sig_enforce Module load Kernel 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. Create a configuration file with parameters for the key pair generation: Create an X.509 public and private key pair as shown in the following example: 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. 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: Request the addition of your public key to the MOK list: You will be asked to enter and confirm a password for this MOK enrollment request. 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. 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: 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. 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" . Verify what keys have been added to the system key ring on the current boot: Since your public key has not been enrolled yet, it should not be displayed in the output of the command. Request enrollment of your public key: Reboot, and complete the enrollment at the UEFI console: Verify the keys on the system key ring again: Copy the module into the /extra/ directory of the kernel you want: Update the modular dependency list: Load the kernel module and verify that it was successfully loaded: Optionally, to load the module on boot, add it to the /etc/modules-loaded.d/my_module.conf file:
# yum install kmod # 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] 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, modprobe < MODULE_NAME > lsmod | grep < MODULE_NAME > lsmod | grep serio_raw serio_raw 16384 0 modprobe -r < MODULE_NAME > lsmod | grep < MODULE_NAME > echo < MODULE_NAME > > /etc/modules-load.d/< MODULE_NAME >.conf lsmod | grep < MODULE_NAME > lsmod Module Size Used by fuse 126976 3 xt_CHECKSUM 16384 1 ipt_MASQUERADE 16384 1 uinput 20480 1 xt_conntrack 16384 1 ... 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 ... cp /boot/initramfs-USD(uname -r).img /boot/initramfs-USD(uname -r).bak.USD(date +%m-%d-%H%M%S).img cp /boot/initramfs-< SOME_VERSION >.img /boot/initramfs-< SOME_VERSION >.img.bak.USD(date +%m-%d-%H%M%S) dracut -f -v dracut -f -v /boot/initramfs-< TARGET_VERSION >.img < CORRESPONDING_TARGET_KERNEL_VERSION > reboot 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 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 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 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 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 mokutil --import my_signing_key_pub.der perl /usr/src/kernels/USD(uname -r)/scripts/sign-file sha256 my_signing_key.priv my_signing_key_pub.der my_module.ko keyctl list %:.system_keyring mokutil --import my_signing_key_pub.der reboot keyctl list %:.system_keyring cp my_module.ko /lib/modules/USD(uname -r)/extra/ depmod -a modprobe -v my_module lsmod | grep my_module echo "my_module" > /etc/modules-load.d/my_module.conf