by Robert Chase
Published January 2012
What are kernel modules and why would I spend time signing them? One great feature of Linux and the kernel is that users can take the source, and modify it to add their own features, and recompile. However, when recompiling the kernel, you must be careful not to introduce changes that could render the system unbootable.
To minimize such risks, you have the option to add code to a running kernel through the use of kernel modules. Kernel modules were added to the Linux kernel back in 1995 in the 1.2 release. You might have heard these referred to as "Loadable Kernel Modules" or "LKM" for short. The beauty in using LKMs is it allows you to customize your environment without compromising the base kernel environment or the stability of your system.
There are several use cases for kernel modules, but one of the most common is the introduction of new device drivers, because they allow you to integrate new hardware support with limited disruptions to your running system. But, as they say, with great power comes great responsibility, and the use of kernel modules is no exception.
LKMs are not confined to user space and they have full access to critical kernel space resources, which is where signing kernel modules becomes an interesting concept. The ability to use signed kernel modules became available with the Unbreakable Enterprise Kernel with release 2.6.39-300.9.1. This feature, when enabled, will check the module signature against a ring of public keys compiled into the kernel at module load time. If the key is valid, the kernel will load the module. If the key is not valid, the kernel will reject it and the module will not load.
By default, strict checking of signed modules is turned off for compatibility purposes with unsigned third-party modules. Let's take a moment to explore this feature and some examples of how to work with it.
First, you can enable strict checking of signed modules on your system at boot by editing your kernel boot string in the
/etc/grub.conf file. The command used is
enforcemodulesig=1. The strict checking capability is activated at boot time, so a reboot is required to activate it.
Listing 1 is an example of the
grub.conf file from my test system with the
enforcemodulesig option enabled.
vi /boot/grub/grub.conf add enforcemodulesig=1 at the end of your kernel string. title Oracle Linux Server (2.6.39-200.32.1.el6uek.x86_64) root (hd0,0) kernel /vmlinuz-2.6.39-200.32.1.el6uek.x86_64 ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet ignore_loglevel enforcemodulesig=1 initrd /initramfs-2.6.39-200.32.1.el6uek.x86_64.img
Listing 1. Enabling the
To verify that your current running system is running with signed module enforcement turned on, you can use the following command:
dmesg | grep enforcemodulesig=1
No output is an indication it's not enabled. If you feel this is an error, verify your
grub.conf file and make sure you've restarted the system. If the feature is enabled, you should see output similar to the following:
Command line: ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet enforcemodulesig=1 Kernel command line: ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet enforcemodulesig=1
There are two modes of operation: permissive mode and enforcing mode. When you enable the
enforcemodulesig=1 option, the kernel rejects attempts to load any modules that are unsigned or cannot be verified in the key ring.
Table 1, from David Howells' "Module Signature Verification," provides additional information about functionality based on the situation and mode.Table 1. Module States
|Module State||Permissive Mode||Enforcing Mode|
|Signed, no public key||ENOKEY||ENOKEY|
|Validly signed, public key||Ok||Ok|
|Invalidly signed, public key||EKEYREJECTED||EKEYREJECTED|
|Validly signed, expired key||EKEYEXPIRED||EKEYEXPIRED|
|Signed, hash algorithm unavailable||ENOPKG||ENOPKG|
|Signed, pubkey algorithm unavailable||ENOPKG||ENOPKG|
|Signature without sig packet||ENOMSG||ENOMSG|
Let's say we want to enable enforcing mode to prevent unsigned modules from being loaded on our system. First it's important that you consider the modules you are currently running on your system and make sure they are signed, so they are not rejected by the module signing facility. Being rejected might cause you to lose critical functionality. You can see the running modules on your system by using
lsmod or checking
To verify that a compiled module is signed on your system, you can do the following: change to the modules directory for the running kernel and locate the module that you want to check.
In the following example, we are checking a fictitious module called
module.ko by using
readelf to look at the compiled binary. We are doing this so that we can read the module instead of looking at non-human-readable output. The
-S switch shows information in the file's section headers.
cd /lib/modules/$(uname -r) readelf -S module.ko | grep sig.*NOTE
If the module is signed, the output should look similar to this.
[**] .note.module.sig NOTE 0000000000000000 00000***
No output is an indication that the module is unsigned.
While writing LKMs is outside the scope of this document, for testing purposes it might be helpful to put together a simple unsigned LKM for testing. More information about writing a simple "hello world" kernel module can be found at http://www.tldp.org/HOWTO/Module-HOWTO/x839.html.
If a module has been validly signed, it will load with
insmod with no output from the command and it will also be visible in the
Let's test this by trying to load an unsigned module. In the following example, our unsigned module is called
unsignedmodule.ko. We will use
insmod to insert our module into the running kernel. The output shows what will happen when our unsigned module is rejected by the kernel.
[root@localhost ~]# insmod unsignedmodule.ko An attempt to load unsigned module was rejected insmod: error inserting 'unsignedmodule.ko': -1 Key was rejected by service
When the module is rejected, the kernel will log the attempt to
Oct 25 18:17:54 localhost kernel: An attempt to load unsigned module was rejected
As you can see from the examples, signed modules enhance system security by checking modules upon load against the ring of keys compiled into the kernel, preventing invalidly signed modules from being loaded. Enabling enforcing mode on system boot prevents unsigned modules from being loaded, and this can provide additional protection against malicious code being used on the system. While signed kernel modules by themselves won't protect your system, they are an additional layer of defense in making your system more difficult for an attacker to breach.
readelfman page: http://linux.die.net/man/1/readelf
Robert Chase is a member of the Oracle Linux product management team. He has been involved with Linux and open source software since 1996. He has worked with systems as small as embedded devices and with large supercomputer-class hardware.
|Revision 1.0, 12/06/2012|