unshareとpivot_rootでルートファイルシステムを入れ替える

PIDのnamespaceを確認する中で、ルートを変更する方法としてchrootを使いました。chrootはchrootするCapability(cap_sys_chroot)を奪わないとchrootの外に出ることができてしまいます。

ここではpivot_root を試してみます。pivot_rootを使うとプロセスのルートファイルシステムを入れ替えることができます。pivot_rootは引数に「新しいルートファイルシステム」と「古いルートファイルシステムのマウント先」を指定するのですが、以下の制約があります。

  • 「新しいルートファイルシステム」と「古いルートファイルシステムのマウント先」は「変更前のルートファイルシステム」と同じマウントポイントにあってはいけない
  • 「古いルートファイルシステムのマウント先」は 「新しいルートファイルシステム」の配下になければならない
  • 他のファイルシステムを 「古いルートファイルシステムのマウント先」 にマウントできない

これらの制約を満たしつつ、ファイルシステムを入れ替えるために以下の操作をします。

  • 1の条件を満たすためにmount --bind $NEW_ROOT $NEW_ROOTでマウントポイントを分離する
  • 2の条件を満たすために「古いルートファイルシステムのマウント先」を$NEW_ROOT/.put_oldにする
  • pivot_root後に「古いルートファイルシステム」を外す

「古いルートファイルシステム」で起動した/bin/shがいなくなってしまったので、「新しいルートファイルシステム」の/bin/shを起動します。コマンドで表すと、以下のようになります。


NEW_ROOT=/root/images
mkdir $NEW_ROOT/.put_old
mkdir $NEW_ROOT/proc
unshare -mpfr /bin/sh -c " \
mount --bind $NEW_ROOT $NEW_ROOT && \
mount -t proc proc $NEW_ROOT/proc && \
pivot_root $NEW_ROOT $NEW_ROOT/.put_old && \
umount -l /.put_old && \
cd / && \
exec /bin/sh
"
"

UTS ホスト名

UTSの分離は特にややこしいことはありません。以下のように操作してみると独自のホスト名を持たせることができます。


unshare -u /bin/bash
hostname # 名前空間を切る前のホスト名がそのまま表示されます
hostname container
hostname # container
exit

hostname # 名前空間内の操作の影響は受けていません

IPC プロセス間通信

System V プロセス間通信オブジェクトとPOSIXメッセージキューが対象になっていています。POSIXメッセージキューを試してみましょう。試すためのPythonのコードは以下を使います。

まず、posix_ipcを入れます。

pip install posix_ipc

送信側です。1秒スリープしながらキューへの送信を続けます。


import posix_ipc as ipc
from time import sleep

mq = ipc.MessageQueue('/testq', ipc.O_CREAT) cnt = 0

while True: print(cnt) mes = mq.send(str(cnt)) sleep(1) cnt+=1

次に受信側です。


import posix_ipc as ipc

mq = ipc.MessageQueue('/testq')

while True: mes = mq.receive() print(mes[0])

screenなどを使って以下を同時に動かしてみましょう。

送信1:namespaceなし。

python3 ./send.py

受信1:namespaceなし。送信側から送られてくる数字が順に表示されます。

python3 ./receive.py

受信2:namespaceを作成。何も表示されません。


unshare --ipc
python3 ./receive.py

POSIXメッセージキューがnamespaceによって分離されていることを確認できました。