How to Use Signed Kernel Modules

in Oracle Linux
Published January 2012

Loadable kernel modules allow you to add code to a running Linux kernel. Oracle's Unbreakable Enterprise Kernel provides signed kernel modules to further protect the kernel. This article explains how to use this feature.

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.

Use Cases

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.

Examples

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 enforcemodulesig Option

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
Unsigned Ok EKEYREJECTED
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
Corrupt signature EBADMSG EBADMSG
Corrupt file ELIBBAD ELIBBAD

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 /proc/modules.

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 lsmod output.

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 /var/log/messages:


Oct 25 18:17:54 localhost kernel: An attempt to load unsigned module was rejected

Conclusion

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.

See Also

About the Author

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