3 回シリーズになるとは思ってなかったこのシリーズ、ついに解決編です。
1 度目の mknod
は成功するものの、なぜか続けて mknod
を実行すると失敗してしまうという謎のトラブル。ふと、LXC のコミットログを眺めていると seccomp 関連の修正があり、見てみると簡単な修正ですが、コミットログと修正内容を見てピンと来ました。
それがこれです。
新しいカーネルではバッファーをゼロクリアしておく必要があるとのこと。これだと 1 度実行して成功しても、そのバッファに前のデータが残っていたらエラーになりそう!ということで試すとバッチリ成功しました。
これだけだとなんなので、今回のシステムコールインターセプション機能についてまとめておきましょう。
システムコールインターセプション機能
5.0 kernel で Add seccomp trap to userspace. なる機能が追加されました。解説は次にあります。
これは、本来カーネル側で権限のチェックを行い実行の可否を判断するシステムコールの実行を、seccomp を使ってシステムコールをトラップし、ユーザースペースに処理を委ね、その応答を見て処理を進めるかどうかを決めるというもののようです。
この機能が LXD に入ったのは 3.13 と少し前で、その時のアナウンスには
LXD 3.13 を 5.0 以上のカーネル、最新の libseccomp、liblxc と組み合わせると、ユーザー空間でシステムコールをインターセプトして仲介できるようになりました
とあります。
お試し
そういうわけで、先の失敗編エントリーのころからは少し環境を変えています。
- Plamo Linux 7.1
- kernel 5.6
- libseccomp は 2020-03-30 時点の master branch を取得しビルド
- LXC 4.0.1 + 先のパッチ
- LXD 4.0.0
これで Alpine Linux コンテナを作成しました。
$ lxc launch images:alpine/3.11 a1 a1 を作成中 a1 を起動中 $ lxc shell a1 a1:~# whoami root a1:~# cat /proc/self/uid_map /proc/self/gid_map (非特権コンテナで動作していることを確認) 0 100000 65537 0 100000 65537 a1:~# mknod test c 5 1 mknod: test: Operation not permitted
上のように root ユーザーではありますが、ID のマッピングを見ると、ホスト環境では uid/gid: 100000 の一般ユーザー権限で User Namespace を使って動作していることがわかります。
当然一般ユーザーでは mknod
する権限はありませんので失敗します。
ここで LXD の設定 security.syscalls.intercept.mknod
を true
に設定して同じ操作を試してみましょう。
$ lxc config set a1 security.syscalls.intercept.mknod=true $ lxc config show a1 architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200402_13:00) image.os: Alpine image.release: "3.11" image.serial: "20200402_13:00" image.type: squashfs security.syscalls.intercept.mknod: "true" :(略)
このように設定が true
になりました。コンテナに設定を反映させるために再起動します。
$ lxc restart a1 $ lxc shell a1 a1:~# mknod test c 5 1 a1:~# mknod test2 c 0 0 a1:~# ls -l total 0 crw-rw-rw- 0 root root 5, 1 Apr 10 11:53 test crw-rw-rw- 0 root root 0, 0 Apr 10 11:53 test2
このように、LXC にパッチを適用する前は失敗していた 2 つ目の mknod
も無事成功し、キャラクターデバイスがふたつ作成できました。
ちなみにどんなデバイスでも作成できるわけではありません。LXD 側でその辺りは制御されており、問題のないデバイスのみが作成できます。作成できるデバイスのリストは公式文書にあります。
- システムコールのインターセプション (LXD ドキュメント翻訳プロジェクト)
リストにないデバイスファイルは次のように失敗します。
a1:~# mknod test3 c 5 2 mknod: test3: Operation not permitted
このあたりの機能、もう少し遊んでみるつもりです。