chroot 入門 - ルートディレクトリを切り替えて環境を分離する
この記事で解決できること
chrootで プロセスから見えるルートディレクトリを切り替える 仕組みが分かる- 「chroot 環境でコマンドが動かない」を 依存ライブラリの観点で切り分け できる
- live USB / レスキューモードからの システム復旧の型 が身につく
- chroot が セキュリティ境界ではない 理由と、代わりに何を使うべきかが分かる
結論(実務の型)
- chroot は ファイルシステムの見え方を切り替える だけ。プロセス・ネットワークは隔離しない
- 動かす コマンド本体とその共有ライブラリ を新ルート内に揃える必要がある
- システム復旧では
/dev/proc/sysを bind mount で持ち込んでから chroot する - 本物の隔離が必要なら chroot ではなく コンテナ(namespace) を使う
前提(対象環境)
- OS: Ubuntu / Debian 系(RHEL 系もコマンドは同一)
chroot実行には root 権限(CAP_SYS_CHROOT)が必要chrootコマンドは coreutils 同梱(追加インストール不要)
chroot とは何か?
結論: chroot は、あるプロセスとその子プロセスから見える「ルートディレクトリ
/」を指定したディレクトリに付け替えるコマンド。そのプロセスは新ルートの外にあるファイルへアクセスできなくなる。
通常、すべてのプロセスはシステム全体のルート / を起点にファイルを辿る。chroot /mnt/newroot を実行すると、その配下のプロセスにとって /mnt/newroot が新しい / になる。
$ sudo chroot /mnt/newroot
この瞬間、chroot されたシェルから見える /etc/passwd は、実体としては /mnt/newroot/etc/passwd を指す。新ルートの外側(ホスト本来の /home など)は パスとして表現できなくなる。これが「環境を分離する」と表現される所以である。
chroot された環境は慣習的に chroot jail(牢獄) と呼ばれる。プロセスがその「牢獄」の外のファイルツリーを見られないことに由来する。
なぜ chroot を使うのか?
結論: 主な用途はシステム復旧・クリーンなビルド/テスト環境・特定環境への閉じ込めの3つ。「本番とは独立したファイルシステムでコマンドを実行したい」場面で使う。
代表的なユースケースは次のとおり。
| 用途 | 具体例 |
|---|---|
| システム復旧 | 起動しなくなった OS を live USB から chroot して grub 再インストール・パスワード再設定 |
| クリーン環境 | パッケージビルドを汚れていない最小環境で実行(debootstrap で作成した root など) |
| 隔離実行 | 公開 FTP/SFTP をホームディレクトリ配下に閉じ込める(sshd の ChrootDirectory) |
| 検証 | 別ディストリ・別バージョンのユーザーランドを既存カーネル上で動かす |
chroot は カーネルを切り替えない。新ルート内に別バージョンのライブラリやコマンドを置けても、動いているカーネルはホストのものである。
どう chroot を実行するのか?
結論: 構文は
chroot 新ルート [コマンド]。コマンドを省略するとそのユーザーのシェル($SHELLまたは/bin/sh)を対話起動する。実行には root 権限が要る。
基本構文:
$ sudo chroot NEWROOT [COMMAND [ARG...]]
コマンドを省略した場合:
# 新ルート内のシェルを対話起動する $ sudo chroot /mnt/newroot
コマンドを明示する場合:
# 新ルート内の /bin/ls を実行して終了する $ sudo chroot /mnt/newroot /bin/ls -l /
COMMAND に指定するパスは 新ルートから見た絶対パス。chroot /mnt/newroot /bin/bash は /mnt/newroot/bin/bash を実行する。ホスト側のパスではない点に注意。
chroot 環境に必要なものは?
結論: 動かしたいコマンドの実体に加え、それが依存する共有ライブラリ(
.so)を新ルート内に揃える必要がある。揃っていないと「No such file or directory」で失敗する。
最小の落とし穴がこれである。chroot /mnt/newroot /bin/bash を実行しても、/mnt/newroot/bin/bash が存在しなければ当然動かない。さらに bash が依存する共有ライブラリ も新ルート内に必要になる。
依存ライブラリは ldd で確認する。
$ ldd /bin/bash
linux-vdso.so.1 (0x00007fff...)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f...)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)
/lib64/ld-linux-x86-64.so.2 (0x00007f...)
表示された .so ファイルを、新ルート内の 同じパス にコピーすれば bash が動く。手作業での最小 jail 構築例:
$ NEWROOT=/mnt/jail
$ sudo mkdir -p $NEWROOT/{bin,lib,lib64}
$ sudo cp /bin/bash $NEWROOT/bin/
# ldd の出力を見て必要な .so を同じ階層へコピー
$ sudo cp /lib/x86_64-linux-gnu/{libtinfo.so.6,libc.so.6} $NEWROOT/lib/
$ sudo cp /lib64/ld-linux-x86-64.so.2 $NEWROOT/lib64/
$ sudo chroot $NEWROOT /bin/bash実用的な chroot 環境は手作業ではなく debootstrap(Debian/Ubuntu)や dnf --installroot(RHEL 系)で 依存込みの完全なユーザーランドを一括展開 して作るのが普通。手動コピーは仕組みの理解用と捉えるとよい。
システム復旧での chroot 実践
結論: 起動しない OS の修復では、対象ディスクをマウントし、
/dev/proc/sysを bind mount で持ち込んでから chroot する。これでホスト稼働中の OS をあたかも通常起動したかのように操作できる。
live USB やレスキューモードから本来の OS に入って修復する手順。/dev/sda1 をルートパーティションとする。
# 1. 対象のルートパーティションをマウント $ sudo mount /dev/sda1 /mnt # 2. 仮想ファイルシステムを bind mount で持ち込む $ sudo mount --bind /dev /mnt/dev $ sudo mount --bind /proc /mnt/proc $ sudo mount --bind /sys /mnt/sys # 3. chroot で本来の OS に入る $ sudo chroot /mnt # 4. ここからは通常の OS 操作(例: GRUB 再インストール) # grub-install /dev/sda && update-grub
/dev /proc /sys を持ち込まないと、grub-install やパッケージ操作など カーネルやデバイス情報を参照するコマンドが失敗 する。復旧 chroot ではこの bind mount がほぼ必須。
作業後は chroot を抜けてからアンマウント する。順序を間違えると target is busy になる。
# chroot を抜ける # exit $ sudo umount /mnt/sys /mnt/proc /mnt/dev $ sudo umount /mnt
/dev/pts(疑似端末)や /run が必要なケースもある。arch-chroot(Arch Linux 提供だが他環境でも利用可)はこれらの bind mount を自動でやってくれる便利ラッパー。
chroot はセキュリティ境界になるのか?
結論: ならない。chroot はファイルシステムの見え方を変えるだけで、root 権限を持つプロセスは標準的な手法で chroot の外へ脱出できる。隔離目的には namespace ベースのコンテナを使うべき。
chroot を「サンドボックス」と誤解すると危険である。chroot 環境内で root 権限を持つプロセス は、二重 chroot などの古典的テクニックで容易に脱獄(chroot escape)できる。これは設計上の制約であり、バグではない。
chroot が隔離 しない もの:
- プロセス空間(
psで外のプロセスが見え、killできる) - ネットワーク(同じネットワークスタックを共有)
- ユーザー / 権限(chroot 内の root はホストの root と同一)
- カーネル(共有)
信頼できないコードの隔離・マルチテナント分離に chroot を使ってはいけない。本物の隔離が必要なら namespace + cgroup(コンテナ) や 仮想マシン を使う。chroot 内の root を非 root に落とす(capsh --drop 等)のは緩和策にはなるが、それでも完全な境界にはならない。
非特権ユーザー向けの安全な閉じ込めとしては、sshd の ChrootDirectory(SFTP 専用閉じ込め)や、systemd サービスの RootDirectory= + PrivateDevices= などの組み合わせが現実的な選択肢になる。
よくあるエラーと対処
結論: 失敗の大半は「依存ライブラリ不足」「bind mount 漏れ」「root 権限不足」の3つ。エラーメッセージから原因を切り分ける。
chroot: failed to run command '/bin/bash': No such file or directory
bash 本体は存在するのにこのエラーが出る場合、依存する共有ライブラリ(ローダ含む)が新ルート内に無い ことがほとんど。ldd /bin/bash の出力を新ルートへ揃える(依存セクション参照)。
$ sudo chroot /mnt/jail ldd /bin/bash # 解決済みかは外から ldd で確認できないため $ ldd /bin/bash # ホスト側で必要 .so を洗い出す
chroot: cannot change root directory to '/mnt': Operation not permitted
root 権限が不足している。sudo を付ける。コンテナ内などで CAP_SYS_CHROOT が剥奪されている場合も同じエラーになる。
chroot 後に「command not found」が多発する
PATH が新ルート内の構成と合っていない、または必要なコマンド群が未配置。最小環境では ls すら無いことがある。debootstrap 等で完全なユーザーランドを展開する。
umount で target is busy
chroot シェルを抜ける前にアンマウントしようとしている。先に chroot を exit し、その後 /sys /proc /dev /mnt の順でアンマウントする。
コピペ用: 復旧 chroot の安全テンプレ
# 入る sudo mount /dev/sda1 /mnt sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo chroot /mnt # 作業後、chroot を exit してから sudo umount /mnt/sys /mnt/proc /mnt/dev sudo umount /mnt