Linux カーネルとお友達になるべく、カーネルモジュールを書いてみました。
カーネルモジュール作成
まずはカーネルモジュールを書く。
以下のサイト様を参考にさせていただきました。
http://taltalp.hatenablog.jp/entry/2016/09/04/182426
http://www.mech.tohoku-gakuin.ac.jp/rde/contents/linux/drivers/module.html
手順
-
yum install kernel-devel
-
vim my_module.c
露骨なアクセス違反プログラムを書いてみる
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/sched.h>
int init_module(){
int i[10];
// アクセス違反を起こす
printk(KERN_INFO "my bad access: address %p : data %d\n", &(i[4096]), i[4096]);
printk(KERN_INFO "my bad access: address %p : data %d\n", &(i[i[4096]]), i[i[4096]]);
printk(KERN_INFO "my module is loaded at %lu\n", jiffies);
return 0;
}
void cleanup_module(){
printk(KERN_INFO "my module is unloaded at %lu\n", jiffies);
}
- vim Makefile
obj-m := my_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
- make all
make コマンドで出力された my_module.ko がカーネルモジュールの実行ファイルである。
モジュールロード
下記コマンドでモジュールをロードする
# insmod my_module.ko
上記自作モジュールをロードしたとき、パニックする場合としない場合がある。
普通のユーザアプリケーションならセグメンテーションフォールトで即刻落ちるプログラムだが、
カーネルにはセグメンテーションはないらしい。
(カーネルがユーザアプリケーションに対してセグメンテーションを与えているのだから当たり前か)
パニックしない場合
ロードできた
# lsmod | grep my_module
my_module 12426 0
dmesg に printk() で出力したメッセージが確認できる
[ 795.109515] my bad access: address ffff880036207d28 : data 17300
[ 795.109550] my bad access: address ffff880036214b78 : data 0
[ 795.109579] my module is loaded at 4295462624
パニックする場合
パニックし kdump により vmcore が吐かれた
vmcore-dmesg 曰く paging 関係でエラーらしい。
:
[ 936.317621] BUG: unable to handle kernel paging request at ffff880264771b28
[ 936.317662] IP: [<ffffffffa05db043>] init_module+0x43/0x90 [my_module]
:
crash で tainted module を見る。
当たり前だが、ちゃんと tainted module として表示される。
crash> mod -t
NAME TAINTS
my_module POE
バックトレースを見る。
do_one_initcall() 中でページフォールトして死んでいることが良くわかる。
crash> bt
PID: 7818 TASK: ffff880064089700 CPU: 0 COMMAND: "insmod"
#0 [ffff88006571f9f0] machine_kexec at ffffffff81051beb
#1 [ffff88006571fa50] crash_kexec at ffffffff810f2542
#2 [ffff88006571fb20] oops_end at ffffffff8163e1a8
#3 [ffff88006571fb48] no_context at ffffffff8162e2b8
#4 [ffff88006571fb98] __bad_area_nosemaphore at ffffffff8162e34e
#5 [ffff88006571fbe0] bad_area_nosemaphore at ffffffff8162e4b8
#6 [ffff88006571fbf0] __do_page_fault at ffffffff81640fce
#7 [ffff88006571fc48] do_page_fault at ffffffff81641113
#8 [ffff88006571fc70] page_fault at ffffffff8163d408
[exception RIP: init_module+67]
RIP: ffffffffa05db043 RSP: ffff88006571fd28 RFLAGS: 00010246
RAX: 000000007fc14780 RBX: ffffffff81951020 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffff88007fc0d6c8 RDI: ffffffffa05dc028
RBP: ffff88006571fd58 R8: 0000000000000086 R9: 0000000000000618
R10: 0000000000000082 R11: 0000000000000000 R12: ffff88007959cd40
R13: ffffffffa05db000 R14: 0000000000000000 R15: ffffffffa05dd000
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#9 [ffff88006571fd60] do_one_initcall at ffffffff810020e8
# 10 [ffff88006571fd90] load_module at ffffffff810ed4ae
# 11 [ffff88006571fee8] sys_finit_module at ffffffff810ede66
# 12 [ffff88006571ff80] system_call_fastpath at ffffffff81645909
RIP: 00007f8576725949 RSP: 00007ffd968eae08 RFLAGS: 00010246
RAX: 0000000000000139 RBX: ffffffff81645909 RCX: 000000000000001f
RDX: 0000000000000000 RSI: 000000000041a13c RDI: 0000000000000003
RBP: 000000000041a13c R8: 0000000000000000 R9: 00007ffd968eb018
R10: 0000000000000003 R11: 0000000000000206 R12: 0000000000000000
R13: 000000000097e130 R14: 0000000000000000 R15: 000000000097f1f0
ORIG_RAX: 0000000000000139 CS: 0033 SS: 002b
page fault 時の動作は以下が詳しい。
https://wiki.bit-hive.com/linuxkernelmemo/pg/%E3%83%9A%E3%83%BC%E3%82%B8%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88
アクセスした仮想メモリアドレスにマッピングする物理メモリが存在しなかった場合に page fault となる。