Kernel modules are code components that can be loaded and unloaded by the kernel when required. They are used to extend the functionality of the kernel without the need to reboot the system. One of the main applications of kernel modules are writing device drivers. In this article, I will show you how to write and compile a simple kernel module that writes an alert to the kernel log.
I will be writing my code against Ubuntu running version 4.10.0–28-generic of the Linux kernel. There are a few options in terms of setting up a kernel development environment. The easiest way is to install a distribution of Linux and use the kernel that comes compiled on it. Alternatively, you can visit a webpage like kernel.org to download and build the latest kernel version.
The example I will be showing is written in C. There are two main components we need to write our kernel module, the source code of the module, and a makefile to compile the module. The general idea of our module will be to execute code when the module is loaded and removed from the kernel. When the module is added, we will print “Hello World” to the kernel log as an alert. When the module is removed, we will print “Goodbye World” to the kernel log as an alert.
Starting at the top of the code, we need to import linux/init.h and linux/module.h into our code, to give us the components required for loading and removing the kernel module. The MODULE_LICENSE line isn’t particularly important, it just informs the kernel that this module is open source. After the initial setup, we define two functions. The hello_init(void) function is the one we will call when the module is loaded to the kernel and the hello_exit(void) function is the one we will call when the module is removed from the kernel. To link these functions to their corresponding events, we use module_init and module_exit. The function module_init takes in a function, and links it to the module load event. Similarly, the module_exit function takes in a function and links it to the module remove event. On either of these events, the linked function is executed.
The actual logic of the functions is not too complex. The function printk is a special implementation of print, which writes the provided text to the kernel log. KERN_ALERT defines the format of the text being printed, which is an alert level log line. We use this because the printf function is not available in kernel mode, so printing to the log using printk is the next best option.
Now that we have defined all the logic of the actual module, we can create the makefile to compile it.
The general idea of the makefile is to point the build process towards the kernel directory. If you try inputting uname -r you will see that the command writes your linux kernel version. When this makefile is run, it produces the proper files required to enable this module.
Now that we have the files we need, we can load them into the kernel. To load a module into the kernel, we use the insmod command. To remove a module, we use the rmmod command. Please note that in order to run these commands, you must be using a root account.
To see the results of this kernel module, we need to navigate to the kernel log and read it. On most Linux systems, this can be found at /var/log/kern.log. Inside of here, you should see the Hello world and Goodbye world messages.
This shows us that the module we wrote was successfully added and removed from the kernel!