LXDのシステムコールインターセプション機能を試す(失敗編)
このエントリ、ほぼやりかけのことを忘れないための自分用メモです。あまり役に立つことは書いてません(オチがないし)。まあこのブログ全体がそうですが…
みなさん LXD 使ってますか? 私は便利にお仕事で使っています。Plamo LInux 上で CentOS を使うために :-)
もうだいぶ前のリリースになりますが、LXD 3.13 の新機能の中に
- システムコールインターセプションのサポートの初期実装
というものがあります。
これは Linux カーネルだと 5.0 に対応する機能の初期実装がなされています。kernelnewbies の 5.0 の "9. Security" の項の最初 にあるのがそれだと思います。
つまりseccompの機能ですね。このあたりに解説が、
seccomp でシステムコールをトラップして、ユーザースペースに処理を委ね、その返事を見て処理を進めるかどうか決める、みたいな感じでしょうか。
LXD 3.13のアナウンスに「LXD 3.13 を 5.0 以上のカーネル、最新の libseccomp、liblxc と組み合わせると、ユーザー空間でシステムコールをインターセプトして仲介できるようになりました」とあるように、libseccomp は現在リリースされていない機能を含んだ master branch のものを使う必要があるし、LXC は先日リリースされている 4.0.0 が必要になります。
LXD は現在 3.23 で、カーネルも 5.5 になっており、この seccomp の機能を使ってできることは増えているようですが、とりあえずこの 3.13 で実装されたあたりを試してみました。
- Plamo Linux 7.1
- kernel 5.5
- libseccomp はリポジトリの master ブランチを(2020-03-30時点のもの)
- LXC 4.0.0(試行錯誤で 2020-03-30 時点の master の状態でも試してます)
- LXD 3.23
対応の libseccomp を入れた状態で LXC のビルドを行う必要がありました。configure
時に機能の有無を確認するからです。特にこの機能を行うためにシステム共通で行うような LXC/LXD の設定はありません。
LXD で適当なコンテナを作成します。
$ lxc launch ubuntu:18.04 c1
c1 を作成中
c1 を起動中
karma@discovery:~$ lxc shell c1
mesg: ttyname failed: No such device
LXD はデフォルトで非特権コンテナです。一応確認しておきます。
root@c1:~# cat /proc/self/uid_map 0 100000 65537
コンテナの root は uid:100000 のユーザーにマッピングされています。ここで、
root@c1:~# mknod test c 5 1 mknod: test: Operation not permitted
当たり前ですが、UID:1000000 の一般ユーザー権限ではこのような mknod
の実行は許可されません。
ここで、先に紹介した機能を使うようにコンテナの設定を行います。
$ lxc config set c1 security.syscalls.intercept.mknod true $ lxc config show c1 | grep syscalls security.syscalls.intercept.mknod: "true"
設定されました。コンテナを再起動します。
$ lxc restart c1
再起動はします。ところが…、
$ sudo tail -f /var/log/lxd/c1/lxc.log lxc c1 20200330121030.523 ERROR cgfsng - (path to lxc src)/src/lxc/cgroups/cgfsng.c:mkdir_eexist_on_last:1142 - File exists - Failed to create directory "/sys/fs/cgroup/cpuset//lxc.monitor.c1" lxc c1 20200330121030.524 ERROR cgfsng - (path to lxc src)/src/lxc/cgroups/cgfsng.c:mkdir_eexist_on_last:1142 - File exists - Failed to create directory "/sys/fs/cgroup/cpuset//lxc.payload.c1" lxc c1 20200330121030.615 ERROR seccomp - (path to lxc src)/src/lxc/seccomp.c:seccomp_notify_handler:1359 - Invalid argument - Failed to read seccomp notification lxc c1 20200330121030.616 ERROR seccomp - (path to lxc src)/src/lxc/seccomp.c:seccomp_notify_handler:1359 - Invalid argument - Failed to read seccomp notification lxc c1 20200330121030.616 ERROR seccomp - (path to lxc src)/src/lxc/seccomp.c:seccomp_notify_handler:1359 - Invalid argument - Failed to read seccomp notification : (以下同じエラー)
(最初の 2 行は置いといて)このようなエラーが大量に出て、一瞬で GB 単位のログに肥大化します。ここでコンテナ内で mknod
やってもエラーにはなりません。しかし当たり前ですがこのエラーのためにコンテナはだんまりです。Invalid argument
ですって (-_-;)
$ lxc shell c1 root@c1:~# mknod test c 5 1 (このままだんまり)
コンテナも強制終了する必要があります。
LXC の seccomp.c の 1359 行目は
1357 » ret = seccomp_notify_receive(fd, req); 1358 » if (ret) { 1359 » » SYSERROR("Failed to read seccomp notification"); 1360 » » goto out; 1361 » }
こんな感じですね。seccomp_notify_receive()
関数がエラーを返してるようです。とりあえずすぐには手に負えない感じなので :-p
LXD が生成する lxc 設定ファイル(lxc.conf
)を見てみましょう。それっぽいところだけ抜き出します。
$ sudo cat /var/log/lxd/c1/lxc.conf lxc.hook.pre-start = /proc/368/exe callhook /var/lib/lxd 28 start lxc.hook.stop = /usr/bin/lxd callhook /var/lib/lxd 28 stopns lxc.hook.post-stop = /usr/bin/lxd callhook /var/lib/lxd 28 stop lxc.seccomp.profile = /var/lib/lxd/security/seccomp/c1 lxc.seccomp.notify.proxy = unix:/var/lib/lxd/seccomp.socket
コンテナ起動、終了時に何か処理してますね。何やってるのかは…知りません。また調べよう。読み込んでる seccomp プロファイルを見ると、
$ sudo cat /var/lib/lxd/security/seccomp/c1 2 blacklist reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 38 open_by_handle_at errno 38 init_module errno 38 finit_module errno 38 delete_module errno 38 seccomp errno 22 [1,2146435072,SCMP_CMP_MASKED_EQ,2146435072] seccomp errno 22 [1,8,SCMP_CMP_MASKED_EQ,8] mknod notify [1,8192,SCMP_CMP_MASKED_EQ,61440] mknod notify [1,24576,SCMP_CMP_MASKED_EQ,61440] mknodat notify [2,8192,SCMP_CMP_MASKED_EQ,61440] mknodat notify [2,24576,SCMP_CMP_MASKED_EQ,61440]
最後の方で mknod
、mknodat
を実行した時の処理が書かれていますね。この意味は…わかりません。また調べよう。誰か知ってたら教えてw
でもなんかそれっぽい設定で mknod
なんかが呼ばれた時によしなに処理する設定がなされてる風ですね、知らんけど。
Ubuntu 20.04 LTS はこのあたり使えるようにして出てくるのかしら? (いまのところそのようなパッチが適用されてる感じではなさそうだが…)
成功編を書く日は来るのか…
(追記) なんか不審なログが lxd.log に…
=2020-03-30T21:42:08+0900 lvl=dbug msg="Handling mknod syscall" audit_architecture=3221225534 container=c1 project=default seccomp_notify_flags=0 seccomp_notify_id=11827333229505280862 syscall_args="&{cMode:8192 cDev:0 cPid:13025 path:/run/systemd/inaccessible/chr}" syscall_number=133
何この /run/systemd/inaccessible/chr
って…。誰だこのパスを設定してるのは…