Start to write a simple Linux kernel Module

Start to write a simple Linux kernel Module

Step 1 Create a folder

Create a suitable folder, this folder will contain the source program and other compiled files.

1
➜  mkdir Mooc && cd Mooc

Step 2 Create the source file

This source file is used for code.

1
➜  touch hello.c

Step 3 Programming

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
static int __init hello_init(void) {
printk("hello, world%n");
return 0;
}
static void __exit hello_exit(void) {
printk("goodbye!%n");
}

MODULE_LICENSE("GPL");

module_init(hello_init);
module_exit(hello_exit);

You may feel that these codes are very strange. They are obviously programs written in C language, but the style and functions used are different. This is because this is a Linux kernel program, of course it is different. Get used to it ~

Step 4 Write the Makefile

1
➜  touch Makefile

Note that the letter M must be capitalized so that the make command will find our Makefile file.

1
2
3
4
5
6
7
8
9
obj-m:=hello.o

CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

For how to write Makefile, please search Google for relevant content.

Step 5 Compile

We have written the source code and the Makefile file, and then we can use the make command to compile.

1
➜ make

If such a message pops up, it means that the compilation is successful:

1
2
3
4
5
6
7
8
make -C /usr/src/linux-headers-5.4.0-48-generic M=/home/ubuntu/Mooc modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-48-generic'
CC [M] /home/ubuntu/Mooc/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/ubuntu/Mooc/hello.mod.o
LD [M] /home/ubuntu/Mooc/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-48-generic'

At this time, we can look at the various files generated after compilation. We need to pay special attention to the .ko file, which is the target of our compilation.

1
➜ ls -a

You can see that many files are generated:

1
2
.   hello.c   .hello.ko.cmd  hello.mod.c     hello.mod.o       hello.o       Makefile       Module.symvers
.. hello.ko hello.mod .hello.mod.cmd .hello.mod.o.cmd .hello.o.cmd modules.order

Step 6 Insert the module

It can only be run after the super permission module is inserted.

1
➜ sudo insmod hello.ko

Let’s take a look at whether the insertion is successful. The lsmod command can view the modules running in the system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Module                  Size  Used by
hello 16384 0
binfmt_misc 24576 1
dm_multipath 32768 0
scsi_dh_rdac 16384 0
scsi_dh_emc 16384 0
scsi_dh_alua 20480 0
intel_rapl_msr 20480 0
intel_rapl_common 24576 1 intel_rapl_msr
isst_if_common 16384 0
nfit 65536 0
rapl 20480 0
input_leds 16384 0
joydev 24576 0
serio_raw 20480 0
mac_hid 16384 0
qemu_fw_cfg 20480 0
...

Clearly, our hello module was inserted successfully!

Step 7 Print system log information

We use the dmesg command to print syslog messages.

1
➜ dmesg

If you see a message, it means that our module is inserted into the kernel and runs successfully!

1
2
3
4
5
6
7
8
9
10
11
12
13
							...
[ 5.545811] audit: type=1400 audit(1672065866.284:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/snapd/snap-confine" pi
d=504 comm="apparmor_parser"
[ 5.545819] audit: type=1400 audit(1672065866.284:9): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/snapd/snap-confine//mo
unt-namespace-capture-helper" pid=504 comm="apparmor_parser"
[ 5.557997] audit: type=1400 audit(1672065866.296:10): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/sbin/tcpdump" pid=506 com
m="apparmor_parser"
[ 5.560334] audit: type=1400 audit(1672065866.300:11): apparmor="STATUS" operation="profile_load" profile="unconfined" name="nvidia_modprobe" pid=507 comm=
"apparmor_parser"
[ 18.146737] rfkill: input handler disabled
[152396.285398] hello: loading out-of-tree module taints kernel.
[152396.285504] hello: module verification failed: signature and/or required key missing - tainting kernel
[152396.285705] hello, world

Step 8 Uninstall the module

After finishing the experiment, we can uninstall and clear this module, and also use the super authority command:

1
➜ sudo rumod hello

Just write the module name. After uninstalling, let’s see if our hello module is still there:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
➜  Mooc lsmod
Module Size Used by
binfmt_misc 24576 1
dm_multipath 32768 0
scsi_dh_rdac 16384 0
scsi_dh_emc 16384 0
scsi_dh_alua 20480 0
intel_rapl_msr 20480 0
intel_rapl_common 24576 1 intel_rapl_msr
isst_if_common 16384 0
nfit 65536 0
rapl 20480 0
input_leds 16384 0
joydev 24576 0
serio_raw 20480 0
mac_hid 16384 0
qemu_fw_cfg 20480 0
sch_fq_codel 20480 2
ip_tables 32768 0
x_tables 40960 1 ip_tables
autofs4 45056 2

Obviously, the hello module was successfully uninstalled.
Let’s look at the system log information again:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[    5.542072] audit: type=1400 audit(1672065866.280:7): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/{,usr/}sbin/dhclient" pid=503
comm="apparmor_parser"
[ 5.545811] audit: type=1400 audit(1672065866.284:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/snapd/snap-confine" pi
d=504 comm="apparmor_parser"
[ 5.545819] audit: type=1400 audit(1672065866.284:9): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/snapd/snap-confine//mo
unt-namespace-capture-helper" pid=504 comm="apparmor_parser"
[ 5.557997] audit: type=1400 audit(1672065866.296:10): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/sbin/tcpdump" pid=506 com
m="apparmor_parser"
[ 5.560334] audit: type=1400 audit(1672065866.300:11): apparmor="STATUS" operation="profile_load" profile="unconfined" name="nvidia_modprobe" pid=507 comm=
"apparmor_parser"
[ 18.146737] rfkill: input handler disabled
[152396.285398] hello: loading out-of-tree module taints kernel.
[152396.285504] hello: module verification failed: signature and/or required key missing - tainting kernel
[152396.285705] hello, world
[153086.332570] goodbye!

As you can see, the system correctly printed goodbye!.

Step 9 Clear the compiled files

1
2
3
4
5
➜  Mooc make clean
make -C /usr/src/linux-headers-5.4.0-48-generic M=/home/ubuntu/Mooc clean
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-48-generic'
CLEAN /home/ubuntu/Mooc/Module.symvers
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-48-generic'

We can see that the files generated in our folder have been cleared:

1
2
➜  Mooc ls -a
. .. hello.c Makefile

This is one small step in Linux kernel programming, and this article is over, thank you for reading.


Start to write a simple Linux kernel Module
http://blog.luliang.online/2022/12/28/Start to write a simple Linux kernel Module/
作者
Luyoung
发布于
2022年12月28日
许可协议