他人にバグ修正を頼むのはよくないという反省から、このあと森田は OS ツリーのビルド、インストール方法を調べ 手元で OS のコードをいじれるようにしたのだった。ただしその成果を発揮する日は今の所きていない。来なくていいです
サーバサイドのかっこいいバグの話なんかないですか > 和良
よくないまでいうと語弊があるけれど、自分で直したほうが楽ですよね。そうして軽い気持ちで手を出すと大事になったりするんですが…。
というわけで、1行変更するだけのつもりが大事になった話をひとつ。
seccomp
Firecracker では Linux の seccomp という仕組みを使って、Firecracker プロセスが呼び出せるシステムコールについて許可リストをもっている。Firecracker のなかで動くゲストの Linux は様々なシステムコールを自由に発行できるけれど、Firecracker プロセスがホストの Linux に対して呼び出すシステムコールは厳選されている。
実際の許可リストは、src/vmm/src/default_syscalls/filters.rs にある。この仕組みは、本来なら libc やライブラリが隠蔽してくるはずの実装の詳細であるシステムコールを細かく列挙しなくてはいけないので、結構きびしい。
After more digging, looks like the
rt_sigprocmask
is unescapable. It’s also called from__block_all_sigs
, which is in turn called bypthread_exit
. Basicallymusl
took every precaution and blocks signals whenever something signal-unsafe is underway.
Firecracker がスレッドを終了すると、musl libc 経由で pthread_exit が呼ばれて、そこから rt_sigprocmask というシステムコールが呼ばれてしまうので、結果として seccomp 違反で Firecracker が殺されてしまう、という話だった。
スレッドを終了させるのをやめてみよう
rt_sigprocmask なんて別に悪いことできるシステムコールでもないんだし、許可リストに1行足せばいいんじゃないの? と手元でやってみるとちゃんと動く。これでいけるかな、と聞いてみると、Firecracker 側の人から「そもそもスレッドが終了する必要は無いよね」と修正案を提案される。
問題のスレッドは Firecracker が vCPU と 1:1 で割り当てるスレッドなので、Firecracker の実行中に数が減ったりはしない。そもそもの問題は Firecracker のプロセス自体が終了するときにしか発生しないので、スレッド自体は止めておいて、プロセス全体が死ぬのを待てばいい、というわけ。
なんか大事になってきたなあと思いつつ、乗り掛かった船なのでプルリクエストを出してみる。
x86_64 と aarch64 で終了イベントの扱いが違うのを直そう
Firecracker は x86_64 だけではなく aarch64、いわゆる ARM もサポートしている。自分が出したプルリクエストでは Rust の #ifdef
相当の #[cfg(target_arch = ...)]
を使って、x86_64 と aarch64 を書き分けていた。x86_64 では i8042 をエミュレーションする部分から、ファイルディスクリプタを取り出して、それで終了イベントを扱うようになっていたんだけど、i8042 はすなわち “Intel 8042” なので、aarch64 には存在しないのだった。
「エミュレーション部分は無くていいから、終了イベントを扱うためのファイルディスクリプタは、aarch64 にも欲しいよね」という話になったので、それも実装してプルリクエストを出してみる。なぜ私がリファクタリングを…。
ところでスレッドを終了させない変更は…
なんてやっているうちに、もともとの「スレッドをどうやって終了させずにおくか」という問題は進展して、Firecracker 側の人が、別のプルリクエストを出して、無事マージされた。
というわけで、1行変更で終わるはずが、なぜかリファクタリングにまきこまれ、本題のバグは相手に直してもらった話でした。まあ Rust が書けたしバグも直ったのでめでたしめでたし。
じゃあ次は jmuk さんで。