はじめに
Linuxのカーネルモジュールで Hello World を書く機会があったのでメモ
環境
- Ubuntu22.04
$ uname -a
Linux dev 6.5.0-26-generic #26~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Mar 12 10:22:43 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.4 LTS"
手順
- 開発ツールのインストール
- コーディング(hello.c、Makefile)
- ビルド(make)
- 実行(insmod, rmmod)
- 作成したカーネルモジュールのロード
- 作成したカーネルモジュールのアンロード
開発ツールのインストール
$ sudo apt install build-essential linux-headers-$(uname -r) gcc-12
コーディング(hello.c、Makefile)
エディタで以下の通り作成する
$ cat hello.c
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_INFO
int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
// 0 を返すと、モジュールのロードに成功したことを意味します
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
MODULE_LICENSE("GPL");
$ cat Makefile
obj-m += hello.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
ビルド(make)
$ make
make -C /lib/modules/6.5.0-26-generic/build M=/home/dev/devel/kp modules
make[1]: ディレクトリ '/usr/src/linux-headers-6.5.0-26-generic' に入ります
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
You are using: gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
CC [M] /home/dev/devel/kp/hello.o
MODPOST /home/dev/devel/kp/Module.symvers
CC [M] /home/dev/devel/kp/hello.mod.o
LD [M] /home/dev/devel/kp/hello.ko
BTF [M] /home/dev/devel/kp/hello.ko
Skipping BTF generation for /home/dev/devel/kp/hello.ko due to unavailability of vmlinux
make[1]: ディレクトリ '/usr/src/linux-headers-6.5.0-26-generic' から出ます
p$ ll
合計 352
drwxrwxr-x 2 dev dev 4096 3月 25 23:55 ./
drwxrwxr-x 3 dev dev 4096 3月 25 23:52 ../
-rw-rw-r-- 1 dev dev 173 3月 25 23:55 .Module.symvers.cmd
-rw-rw-r-- 1 dev dev 270 3月 25 23:55 .hello.ko.cmd
-rw-rw-r-- 1 dev dev 150 3月 25 23:55 .hello.mod.cmd
-rw-rw-r-- 1 dev dev 38494 3月 25 23:55 .hello.mod.o.cmd
-rw-rw-r-- 1 dev dev 37332 3月 25 23:55 .hello.o.cmd
-rw-rw-r-- 1 dev dev 122 3月 25 23:55 .modules.order.cmd
-rw-rw-r-- 1 dev dev 156 3月 25 23:53 Makefile
-rw-rw-r-- 1 dev dev 0 3月 25 23:55 Module.symvers
-rw-rw-r-- 1 dev dev 387 3月 25 23:52 hello.c
-rw-rw-r-- 1 dev dev 111400 3月 25 23:55 hello.ko
-rw-rw-r-- 1 dev dev 27 3月 25 23:55 hello.mod
-rw-rw-r-- 1 dev dev 968 3月 25 23:55 hello.mod.c
-rw-rw-r-- 1 dev dev 96304 3月 25 23:55 hello.mod.o
-rw-rw-r-- 1 dev dev 16512 3月 25 23:55 hello.o
-rw-rw-r-- 1 dev dev 27 3月 25 23:55 modules.order
実行(insmod, rmmod)
別のターミナルで journalctl
でカーネルの出力を見ておく
$ journalctl -r
作成したカーネルモジュールのロード
$ sudo insmod hello.ko
作成したカーネルモジュールのアンロード
$ sudo rmmod hello
出力
$ journalctl -r
:
3月 25 23:55:54 dev kernel: Hello world 1.
3月 25 23:56:29 dev kernel: Goodbye world 1.
:
エラーについて
journalctl で出力されたエラーについて、以下の通り。
dev kernel: hello: loading out-of-tree module taints kernel.
loading out-of-tree module taints kernel
このメッセージは、カーネル外部からのモジュールをロードすることによってカーネルが「汚染」されたことを意味する。ここで言う「汚染」とは、そのモジュールがオープンソースではないか、または公式のLinuxカーネルソースツリーの一部ではないことを意味し、カーネルの安定性やセキュリティに潜在的な影響を与える可能性があるという警告。ただし、自分で開発中のモジュールのテストなど、特定の開発目的で行っている場合は問題ない。
dev kernel: hello: module verification failed: signature and/or required key missing - tainting kernel
module verification failed: signature and/or required key missing - tainting kernel
このメッセージは、ロードしようとしたモジュールが署名されていないか、必要な鍵が見つからないことを意味する。多くのLinuxディストリビューションでは、セキュリティのためにカーネルモジュールの署名を要求していて、署名されていないモジュールをロードすると、このような警告が表示される。開発やテスト目的であれば問題ないが、公開されたシステムやセキュリティが重要な環境では、信頼できる署名されたモジュールのみを使用することが推奨される。
さいごに
かんたんでしたね