Task

The task briefly can be described as:-

Write a linux kernel module that when loaded should print ‘Hello’ in the debug level of the linux. You also need to write the makefile which builds the kernel module against the source file.

Kernel Modules:-

Modules are pieces of code that can be loaded or unloaded as per requirement. As this task talks about inserting module, it is very dangerous to experiment on the kernel you are using. Hence it would be better to try the task in a Virtual machine. Coming back to modules, to get the list of modules you can use the command lsmod . To get information about a specific module you can use modinfo MODULE_NAME

Make

In linux, make is used to build executable programmes and libraries. Makefile  is a file that contains a list of instructions to build programmes and libraries in a particular syntax (in the background it utilizes the make hence its called a makefile)

What is a build process:

  • Compiler taking source code and converting to object files
  • Linker taking the object files and converting them to executable

Syntax of makefile

target: dependencies
<tab> system_command

For example

all:
    g++ main.cpp hello.cpp factorial.cpp -o hello

all is the default target for a make file. if no other target is specified, it will execute this target

Example of target with no system commands(look at all),

all: hello

hello: a.o b.o c.o
    g++ a.0 b.o c.o
a.o: a.cpp
    g++ -c a.cpp
b.o: b.cpp
    g++ -c b.cpp
c.o: c.cpp
    g++ -c c.cpp
clean:
    rm -rf *.o

Here in case to execute all of them you can simple use make to execute one specific target(useful in case when one file is changed)

make target name

another example to make things clear

all: hello

hello: a b c
	@echo "all"
a:
	@echo "a"
b: 
	@echo "b"
c: 
	@echo "c"
clean:
	rm -rf *.o

In the above example command make will print only “all” on the terminal command make a will print only “a” on the terminal

using variable names in makefile its as simple as assigning a variable and accessing using dollar notation for example

CC = gcc

$(CC) to use gcc

Kernel Debug level

There are totally 8 levels of log in linux, from level0 to level7. The level7 is the debug level.

Task

The C code which accomplishes the task: hello_world_module.c

#include <linux/module.h> // included for all kernel modules
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h>   // for the __init  and __exit macors

MODULE_LICENSE("GPL");
MODULE_AUTHOR("RKA");
MODULE_DESCRIPTION("Accomplish Task 1");

static int __init hello_init(void) {
    printk(KERN_DEBUG "Hello \n"); 
    // since the challenge asks to print in the debug level
    return 0;
    // Non zero return implies module couldn't load
}
static void __exit hello_cleanup(void) {
    printk(KERN_DEBUG "Clean module\n");
}

module_init(hello_init); // when module loads
module_exit(hello_cleanup); // when module unloadss

   At the beginning the headers that required are included. Description in comments. The next three lines, give an info about the module. The info about the module can be obtained from the command line using modinfo MODULE_NAME

There are 2 static functions on that runs when module is loaded, and the other when module is unloaded.

Static function is a function that has scope limited to its object file. The advantage of this is that we can use the same name at different files, without any clashes.

The last two lines indicate what functions to be called on loading and unloading of the module. We can also see that here printk is used instead of printf, because we want it to print in the kernel logs.  Also in  printk function defines the log level to which it wants to print. Here since in the task, it is asked to print at debug level, KERN_DEBUG is the first argument.

Now to build this module we need to write a makefile here is its code:Makefile

obj-m += hello_world_module.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
     make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

The first line is called the goal definition. It indicates what files need to be built Run the makefile by typing make in the terminal. We get a list of different files. We need the .ko file. By loading a kernel module means we are inserting this .ko file in the kernel

Now to insert the hello_world_module.c (To make it ready to convert into a .ko file)

sudo insmod hello_world_module.ko

Verify that you have inserted the module

You can do this by using the dmesg ,which print the kernel log Also you can check the log file whose path is /var/log/kern.log

To remove the module, the comand sudo rmmod MODULE_NAME can be used. To verify that you have removed a module, you can check using the dmesg command or verify the kern.log file

NOTE: Suppose you are getting an error like ‘Operation not permitted’. It is due to the fact we are trying a module which is not signed. In generally modules are signed, which are like proof the module is a valid one. You can either manually sign the module by yourself or you can simply turn off the secure boot to add unsigned modules in your kernel. You can also see the kernel logs that there is a entry which says ‘module verification failed’

References:

  • http://mrbook.org/blog/tutorials/make/
  • https://opensource.com/article/18/8/what-how-makefile
  • https://www.kernel.org/doc/Documentation/kbuild/makefiles.txtm