TenForward

技術ブログ。はてなダイアリーから移転しました

LXDのシステムコールインターセプション機能を試す(解決編)

3 回シリーズになるとは思ってなかったこのシリーズ、ついに解決編です。

tenforward.hatenablog.com

1 度目の mknod は成功するものの、なぜか続けて mknod を実行すると失敗してしまうという謎のトラブル。ふと、LXC のコミットログを眺めていると seccomp 関連の修正があり、見てみると簡単な修正ですが、コミットログと修正内容を見てピンと来ました。

それがこれです。

github.com

新しいカーネルではバッファーをゼロクリアしておく必要があるとのこと。これだと 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.mknodtrue に設定して同じ操作を試してみましょう。

$ 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 側でその辺りは制御されており、問題のないデバイスのみが作成できます。作成できるデバイスのリストは公式文書にあります。

リストにないデバイスファイルは次のように失敗します。

a1:~# mknod test3 c 5 2
mknod: test3: Operation not permitted

このあたりの機能、もう少し遊んでみるつもりです。