linux kernel library で遊ぶ

AsiaBSDCon 2018 で linux rumpkernel についての発表があったらしく気になっていた。

www.slideshare.net

当日は参加していないのでわからないが、linux kernel をライブラリとして使ってユーザーランドでネットワークの実装を簡単に行いたいという文脈なのだろうか。

プロジェクトのサイトは https://lkl.github.io/ だが非常に簡素、というか情報がないので、 直接リポジトリを見たほうが良い。

https://github.com/lkl/linux

README の FAQ に UML (user mode linux) との違いが書いてあるが、UML はフルのカーネルがユーザーランドで動いているが、 lkl はあくまで自分のコードとリンクして kernel の関数を呼び出すということが主眼になっている。

tools/lkl の中にいくつかサンプル的なコードが散らばっているので見てみるとだいたい使い方はわかる。 hijack ライブラリを使うと LD_PRELOAD を使って libc の syscall を置き換えて lkl の syscall を使わせることができる。 すべての syscall を置き換えているわけでは無いので何が使えるかはコードを見る必要がある。 また lkl で置き換えていない syscall はホスト側が使われるようだ。

lkl 自体は arch の一種として実装されているようだ。 UML も同様だったし linux kernel はこのあたりよく抽象化されている。

実際に lkl をつかって procfs をマウントし内部のファイルを出力するサンプルを書いてみた。 https://github.com/toshipp/play-with-lkl/blob/master/cat_proc.c

lkl の初期化に lkl_start_kernel を呼び出して、lkl のシステムコールを使うには lkl_sys_* を呼び出せば良い。 lkl_start_kernel の引数の lkl_host_ops は lkl が使うホストシステム側のシステムコールなどを保持する構造体で、 posix では以下で実装されている。

https://github.com/lkl/linux/blob/master/tools/lkl/lib/posix-host.c

この構造体を書き換えてやれば posix 以外でも動くだろう。 実際に windows 用のコードもある。

さて、lkl は NOMMU として実装されているが、NOMMU でも vfork はサポートできる。 ただし lkl は vfork を未実装にしているので試しに有効にして使ってみた。

https://github.com/toshipp/play-with-lkl/blob/master/patch/vfork.patch https://github.com/toshipp/play-with-lkl/blob/master/vfork.c

残念ながらこれを起動すると segv で落ちてしまう。

% ./vfork                                                                                                                                                                                          (git)-[master]
[    0.000000] Linux version 4.15.0+ (toshi@toshi-note) (gcc version 7.3.1 20180312 (GCC)) #2 Sat Apr 14 20:25:56 JST 2018
[    0.000000] bootmem address range: 0x7f776f396000 - 0x7f776fd95000
[    0.000000] Built 1 zonelists, mobility grouping off.  Total pages: 2524
...
[    1.380143] Btrfs loaded, crc32c=crc32c-generic
[    1.380235] Warning: unable to open an initial console.
[    1.380261] This architecture does not have kernel memory protection.
zsh: segmentation fault (core dumped)  ./vfork

core を見てみると vfork から最終的に呼び出される copy_thread で使う関数ポインタが NULL になっているようだ。 https://github.com/lkl/linux/blob/master/arch/lkl/kernel/threads.c#L179

もしかするとなんとかできるのかもしれないが、よく考えると vfork なんて使わなくても、 lkl 呼び出し側のコードで pthread_create などを使えば良いだけだと気づいたので深追いはしていない。