newbieからバイナリアンへ

newbieからバイナリアンへ

コンピュータ初心者からバイナリアンを目指す大学生日記

【LKM 1.0】 環境整備 ~ hello moduleの作成

 

 

 

0: 参考

www.oreilly.co.jp

www.oreilly.com

 




1: イントロ

なんとなくkernel寄りのことがしたくなったため

kernel moduleをお試しで作っていくことにする

今回は環境の整備と最もシンプルなモジュールを作る




2: 環境整備

VirtualBox + vagrantの環境で開発していく

ゲストOSの情報は以下の通り

$ uname -a
Linux niveapc 4.15.0-60-generic #67-Ubuntu SMP Thu Aug 22 16:55:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

 

vagrantの開発環境はなんか手こずったが

scrapboxを見て丁寧にやったら普通に行けたため省略

 

vagrantではinitしてupして初回はboxをDLしてssh接続すればよい

Vagrantファイルの内容は以下の通り

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu1804"
  config.vm.hostname = "niveapcvagrant"
  config.vm.box_check_update = false
  config.vm.provider "virtualbox" do |vb|
    vb.gui = false
    vb.memory = "4096"
    vb.cpus = 3
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] #DNS継承
  end
end




3: hello module

moduleをインストールしたときと消去したときに

メッセージを出力するだけのモジュール

 

#include<linux/module.h>

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("smallkirby");
MODULE_DESCRIPTION("this is hello module");

static __init int hello_init(void)
{
  printk(KERN_ALERT "Hello world");
  return 0;
}

static __exit void hello_exit(void)
{
  printk(KERN_ALERT "Goodbye, kirby.");
  //return 0;
  /* you shouldn't return in this func */
}

module_init(hello_init);
module_exit(hello_exit);

 

モジュールはkernelに直接リンクされるため

kernelのシンボルこそ参照できるものの

基本的にライブラリのシンボルは使えない

この printk() はkernelが提供する出力関数であり

浮動小数が使えないこと以外は基本的にprintfと同じである

 

あとモジュールはカーネル空間で実行されるため

もちろん利用されるstackもカーネルスタックである

よって自動変数はあまり生成せず

動的に確保することが推奨されるようである

 

<追記>

__init宣言は初期化関数であることを明言し

ロード完了後にローダによってメモリが解放される

同様に__exit宣言はクリーンアップ関数であることを明言する

(この宣言はなくても構わないが)クリーンアップ関数が定義されていない場合

カーネルはモジュールの削除を許可しない

 



続いてMakefile

ifeq ($(DEBUG),y)
  DEBFLAGS = -O -g
else
  DEBFLAGS = -O2
endif

#CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)

ifneq ($(KERNELRELEASE),)
obj-m := hello_module.o

else
  
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD)  modules

endif

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

 

カーネルモジュールのビルドは

カーネルビルドシステムのコンテキスト内で行われなければならない

すなわち普通の作業ディレクトリ内でmakeしてはならない

 

上のMakefileでは

・変数$(KERNELRELEASE)が定義されているか確認する

これが定義されているということはカーネルビルドシステムから呼び出されたということである

・そうでなければ -Cカーネルソースツリーに移動してからmakeする

M=で実際のMakefileを指定する

これによってカーネルビルドシステムのコンテキスト内でワークスペースMakefileを実行できる

・これで呼ばれたMakefileはifneq分岐の中に入ってモジュールが作られる

 

なおなぜか最初にhostOSでビルドしてそれをguestOSに移していたが

それではinsmodの際にInvalid module formatエラーが出る

素直にguestOS内でビルドすれば良い

 

<追記>

モジュールのインストールの際にカーネル

カーネルツリーにおけるvermagic.oとモジュールをリンクさせる

このオブジェクトファイルの情報と一致しないモジュールをインストールしようとすると

Invalid module formatエラーになる




4: モジュールのインストール

こうしてmakeするといろいろなファイルができるが

対象となるのはhello_module.koである

ちなみにhello_module.koの情報は以下の通り

 

# modinfo ./hello_module.ko 
filename:       /home/vagrant/shared_data/./hello_module.ko
description:    this is hello module
author:         smallkirby
license:        GPL v2
srcversion:     C618E0E48058A75265AABF3
depends:        
retpoline:      Y
name:           hello_module
vermagic:       4.15.0-60-generic SMP mod_unload 

 

これをインストールする

# insmod ./hello_module.ko 
# lsmod | grep hello
hello_module           16384  0

さてモジュールmessageを見てみると・・・

# dmesg | tail
[ 2522.175195] hello_module: loading out-of-tree module taints kernel.
[ 2522.175620] Hello world
[ 2583.501734] Goodbye, kirby.

ちょっと怒られたけどちゃんとインストールできたね

でもexitする際のメッセージがもう既に表示されちゃってるのはなんでだろうか

 

気になってshutdownしたあとにもう一度試してみると

[    5.903653] 00:00:00.001638 main     5.2.32_Ubuntu r132056 started. Verbose level = 0
[  115.149294] hello_module: loading out-of-tree module taints kernel.

今度はhelloメッセージすら出力されていない




まあおいおいわかってくるかな






5: アウトロ

進振りは無事に失敗した






続く・・・