TenForward

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

cgroup v2 の nsdelegate オプション(1)〜 namespace 外へのプロセス移動の禁止

cgroup v2がカーネルに導入された時点では、cgroup v2にはマウントオプションはありませんでした。

しかし、4.13 で nsdelegate というオプションが導入されました。これは現時点でも cgroup v2 唯一のマウントオプションです。

このオプションは初期の namespace でマウントするときにのみ指定できます。それ以外の namespace では無視されます。

cgroup namespace については、私の連載第34回 で説明しました。ここでは、cgroup namespace で cgroup ツリーを独立させた後でも、cgroup namespace 内の /(root)を超えてプロセスを移動できました。

これはある意味コンテナ内のプロセスを、別のコンテナに移動させるという意味になります。

普通にコンテナを起動すると、mount namespace を分離させますので、他のコンテナのファイルシステムは見えないはずです。したがってこのようなコンテナをまたいだプロセスの移動はできないはずです。しかし、何らかの理由で別の cgroup 階層が見えるような場合は移動ができることになります。このような操作は通常は行わないケースがほとんどで、禁止したいケースがほとんどであると思います。

nsdelegate を使うとこれを禁止できます。

試してみましょう。以下は Plamo 7.0(4.14.44 kernel)で試しています(sysvinit バンザイ!)。

namespace をまたいだプロセスの移動

nsdelegate がないとき

オプションを指定せずに cgroup v2 をマウントします。これは、私の連載第34回で説明しています。詳しくはそちらをどうぞ。

# mount -t cgroup2 cgroup2 /sys/fs/cgroup/

test01test02 cgroup を作成します。

# mkdir /sys/fs/cgroup/test0{1,2}

現在のシェルの PID を test01 に登録します。

# echo $$ | tee /sys/fs/cgroup/test01/cgroup.procs 
4213

unshare で cgroup namespace を作成してシェルを起動します。

# unshare --cgroup -- /bin/bash

起動したシェルは親 cgroup と同じ cgroup に属することになるので、namespace 作成時点で親と自身が cgroup の /(root)にいることになります。namespace 作成時点にいる cgroup が namespace 内では root となる、これが cgroup namespace でした。

# echo $$
4284
# cat /proc/4213/cgroup 
0::/
# cat /proc/4284/cgroup 
0::/

親の namespace から見ると /test01 cgroup にいることになっています。ちゃんと namespace として働いているのがわかりますね。

parent namespace # cat /proc/4213/cgroup 
0::/test01
parent namespace # cat /proc/4284/cgroup 
0::/test01

ここでおもむろに現在のシェルの PID を test01 と同じレベルの別階層にある test02 に登録します。

# echo $$ > /sys/fs/cgroup/test02/cgroup.procs

すると /(root)の一つ上の test02 を表す /../test02 という cgroup に属することになっています。/test01 が root になっているので、同じレベルの別階層だとこうなるのはわかりますね。

# cat /proc/$$/cgroup 
0::/../test02

nsdelegate があるとき

nsdelegate 機能を使うには cgroup v2 をマウントする際に nsdelegate オプションを指定します。既に cgroup v2 がマウント済みの場合は -o remount,nsdelegate と指定して再マウントすれば使えるようになります。

# mount -t cgroup2 -o nsdelegate cgroup2 /sys/fs/cgroup/

先ほどと同様に test01test02 cgroup を作りましょう。

# mkdir /sys/fs/cgroup/test0{1,2}

そして、test01 にシェルのプロセスを登録し、所属する cgroup を確認します。

# echo $$ > /sys/fs/cgroup/test01/cgroup.procs 
# unshare --cgroup /bin/bash
# cat /proc/$$/cgroup 
0::/

test01 が root cgroup になりました。ここまではさきほどと同じですね。

ここで先程と同じようにシェルの PID を test02 に移動させてみましょう。

# echo $$ > /sys/fs/cgroup/test02/cgroup.procs 
bash: echo: write error: No such file or directory

エラーになりました。nsdelegate を指定して cgroup v2 をマウントすると、このように namespace の境界(root)をまたいで、別階層の cgroup にプロセスを移動できません(ENOENT が返ります)。

nsdelegate には他にも重要な機能がありますので、次回にでも。