LXDでのseccomp notify機能の実装
それではseccomp notify機能の動きを実際に見ていきましょう。先に書いた通り,
LXCプロジェクトの開発者はカーネルにも積極的にコンテナ関連機能の実装を進めており,
このため,
デバイスファイルの作成
最初にseccomp notify機能がサポートされたのは,mknod
とmknodat
システムコールが使えるようになり,
LXDが依存しているLXCでは3.
LXDでmknod
,mknodat
が使えるようになったと言っても任意のデバイスファイルが作成できるわけではありません。許可されているデバイスは先に紹介した/dev/
や/dev/
などの一部のデバイスだけです。詳細は公式ドキュメント
それでは,
$ snap list lxd Name Version Rev Tracking Publisher Notes lxd 4.8 18520 latest/stable canonical✓ - $ lxc version Client version: 4.8 Server version: 4.8
まずはコンテナを作成します。そしてこのコンテナが一般ユーザで起動していることを確認します。
$ lxc launch ubuntu:20.04 c1 (Ubuntu 20.04コンテナの作成・起動) Creating c1 Starting c1 $ lxc info c1 | grep Pid (コンテナのPIDを確認) Pid: 41463 $ ps aux | grep 41463 1000000 41463 0.0 0.4 104104 8032 ? Ss 15:05 0:00 /sbin/init (UID:1000000の一般ユーザで起動している)
それではコンテナ内に入ってデバイスファイルが作成できるか試してみましょう。
$ lxc shell c1 (コンテナ内に入りシェルを実行) root@c1:~# mknod my-dev c 1 5 (デバイスファイルを作成) mknod: my-dev: Operation not permitted (許可されていない)
失敗しました。デフォルトではデバイスファイルの作成は許可されていませんのでこれは当然の動作です。
それでは,security.
をtrue
に設定します。
$ lxc config set c1 security.syscalls.intercept.mknod=true (seccomp notifyでmknodを許可する) $ lxc config show c1 | grep intercept security.syscalls.intercept.mknod: "true" (trueに設定された)
設定されました。設定を反映させるためにコンテナを再起動し,
$ lxc restart c1 (コンテナ再起動) $ lxc shell c1 root@c1:~# mknod my-dev c 1 5 (実行成功) root@c1:~# ls -l my-dev total 1 crw-r--r-- 1 root root 1, 5 Dec 7 06:05 my-dev (デバイスファイルが作成されている)
無事,/dev/
)/dev/
)。
root@c1:~# mknod my-dev2 c 1 8 (メジャー番号1,マイナー番号8で作成) root@c1:~# ls -l my-dev2 crw-r--r-- 1 root root 1, 8 Dec 7 06:08 my-dev2 (デバイスファイルが作成されている)
問題なく作成できました。
shiftfs
次はファイルシステムのマウントを試してみましょう。その前に,
この機能は正式にカーネルにはマージされておらず,
- ※4)
- カーネル開発方面では"idmapped mounts"などと名付けてパッチが投稿されています。
LXDに限らず,root:root
となっているのではないでしょうか。
しかしユーザ名前空間を使った非特権コンテナの場合,nobody:nogroup
となってしまうなど,
そこで,chown
して所有権を期待する設定にする必要があります。
ここで,
非特権コンテナからファイルシステムをマウントする場合は,
$ lxc info | grep shiftfs shiftfs: "false"
そこで,
$ sudo snap set lxd shiftfs.enable=true (snapのlxdでshiftfsを有効化) $ sudo systemctl reload snap.lxd.daemon (設定を反映させるために再起動) $ lxc info | grep shiftfs shiftfs: "true"
- ※5)
- 詳しくはTrying out shiftfsをご覧ください。
これで準備OKです。shiftfsを有効にする前にコンテナを作成していた場合は,
$ lxc delete --force c1 $ lxc launch ubuntu:20.04 c1 Creating c1 Starting c1
- ※6)
- すでに作成済のコンテナをそのまま使ってshiftfsを有効にする方法もありますが,
わかりやすさのために再作成します。
ファイルシステムのマウント
準備ができましたので,mount
システムコールを実行し,
ここの例では,/dev/
が存在しています。このパーティションはext4でmkfsしています。
$ sudo fdisk -l /dev/sdb | grep sdb1 /dev/sdb1 2048 10485759 10483712 5G 83 Linux
このsdb1
はコンテナ内ではデバイスファイルが存在しないので,/dev/
はコンテナ内でデバイスファイルが作成できませんので,
$ lxc config device add c1 sdb1 unix-block path=/dev/sdb1 (コンテナ内に/dev/sdb1を出現させる) Device sdb1 added to c1 $ lxc restart c1 (設定を反映させるためにコンテナ再起動)
コンテナ内に/dev/
が出現しており,
root@c1:~# ls -l /dev/sdb1 brw-rw---- 1 root root 8, 17 Dec 7 14:54 /dev/sdb1
seccomp notify機能を使ってマウントする前に,
$ lxc shell c1
root@c1:~# mount /dev/sdb1 /mnt
mount: /mnt: permission denied.
(コンテナに対してマウントを許可していないので失敗する)
マウント操作は失敗します。
ここで,
- マウントができる設定
( security.
)syscalls. intercept. mount - マウントしたファイルシステムに対してshiftfsを有効にする設定
( security.
)syscalls. intercept. mount. shift - マウントできるファイルシステムとしてext4を許可する設定
( security.
)syscalls. intercept. mount. allowed
$ lxc config set c1 security.syscalls.intercept.mount true $ lxc config set c1 security.syscalls.intercept.mount.shift true $ lxc config set c1 security.syscalls.intercept.mount.allowed ext4 $ lxc restart c1
コンテナ内のシェルからマウントしてみましょう。
$ lxc shell c1
root@c1:~# mount /dev/sdb1 /mnt (マウント操作が成功する)
root@c1:~# df -h | grep /mnt
/mnt 4.9G 20M 4.6G 1% /mnt
マウント操作が成功し,
ここでは直接ext4をマウントしていますが,security.
)。
まとめ
今回は,
LXDでは,mknod
,mknodat
,mount
システムコール以外にもいくつかのシステムコールを許可する設定が追加されています。
seccomp notify機能を使うことで,
今回の記事を書くに当たって,
参考文献
- Seccomp Notify – New Frontiers in Unprivileged Container Development (Christian Brauner氏のブログ)
- システムコールのインターセプション (LXD公式ドキュメント
(日本語訳)) - Deferring seccomp decisions to user space (lwn.
net) - Making Unprivileged Containers More Useable (Open Source Summit North America資料)
- Seccomp BPF (SECure COMPuting with filters)
(kernel文書)