Что делает chroot
Системный вызов chroot(path) (с прав root) меняет «apparent /» текущего
процесса на path. Все последующие пути с / резолвятся относительно
него. Процесс и все его потомки не видят то что выше.
Реальная ФС: Внутри chroot /srv/jail:
/ /
├── etc/ ├── etc/
├── usr/ ├── usr/
├── srv/ └── bin/
│ └── jail/ ←── chroot
│ ├── etc/
│ ├── usr/
│ └── bin/
└── home/
Используется для:
- Изоляции демонов (исторически BIND, vsftpd, sshd ChrootDirectory).
- Сборки пакетов в чистом окружении (debootstrap, mock, pbuilder).
- Системного восстановления - boot с live-USB →
chroot /mnt/sysroot, чтобы починить grub/fstab «изнутри» сломанной системы.
Что chroot НЕ делает (важные ограничения)
Linux-документация и история показали: chroot - это / rebind, а не
security-граница. Он не изолирует:
- Сетевой стек (виден тот же сетевой namespace, тот же netfilter)
- PID-пространство (
ps -efснаружи видит процессы chroot'а) - IPC, signals, ptrace (можно прицепиться к процессу хоста с такими же правами)
- Kernel exploits и
/devустройства - Сам chroot - root внутри jail имеет известный escape:
int fd = open("/", O_RDONLY); // fd на ВНЕШНИЙ кореньchroot("/tmp/anything"); // сменить chrootfchdir(fd); // перейти в старый /
chroot("."); // зафиксировать// теперь видим всю ФС
Поэтому для real изоляции нужны namespaces (mount/pid/net/user)
- capabilities + seccomp + cgroups. То что в сумме даёт Docker/Podman.
Когда chroot всё ещё уместен:
- Внутри уже изолированного контейнера - для дополнительного слоя.
- Для не-root процессов (после chroot уронить privileges через
setuid). - Для бытового - пересобрать пакет в чистом окружении.
Как создать рабочий chroot вручную
Минимальный chroot для запуска bash + ls:
ROOT=/tmp/jail
mkdir -p $ROOT/{bin,lib,lib64}# 1) бинари
cp /bin/bash /bin/ls $ROOT/bin/
# 2) их библиотеки - через ldd
ldd /bin/bash
# linux-vdso.so.1
# libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
# /lib64/ld-linux-x86-64.so.2
for bin in /bin/bash /bin/ls; do
ldd $bin | awk '/=>/{print $3}; /^\s*\//{print $1}' | while read lib; domkdir -p $ROOT$(dirname $lib)
cp $lib $ROOT$lib
done
done
# 3) запустить
sudo chroot $ROOT /bin/bash
Такой минимальный jail не имеет /etc/passwd, /proc, /dev - ls -l
покажет UID числами, многие команды упадут.
/proc, /dev, /sys внутри chroot
Большинство демонов требуют доступ к /dev/null, /proc/self, иногда /sys.
Их нельзя просто скопировать - это виртуальные ФС ядра. Решение -
bind-mount из хоста:
sudo mount --bind /proc $ROOT/proc
sudo mount --bind /sys $ROOT/sys
sudo mount --bind /dev $ROOT/dev
sudo mount --bind /dev/pts $ROOT/dev/pts
sudo mount --bind /run $ROOT/run
sudo chroot $ROOT /bin/bash
Это стандартный паттерн для системного rescue.
Использование на практике
sshd ChrootDirectory (sftp-only пользователи)
В /etc/ssh/sshd_config:
Match Group sftpusers
ChrootDirectory /srv/sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
Требования к каталогу: владелец root:root, права 0755 (нельзя дать
юзеру write на сам chroot-root, иначе sshd откажется). Внутри уже можно
создать поддиректории с правами юзера.
debootstrap - установка Debian в каталог
sudo apt install debootstrap
sudo debootstrap stable /srv/sid http://deb.debian.org/debian
sudo mount --bind /proc /srv/sid/proc
sudo chroot /srv/sid /bin/bash
apt update # внутри chroot
Используется чтобы собрать пакет в эталонном окружении или подготовить rootfs для контейнера.
Восстановление сломанной системы
Загрузка с live-USB:
# после монтирования root-ФС больной системы
sudo mount /dev/sda2 /mnt
sudo mount /dev/sda1 /mnt/boot # если /boot отдельно
for fs in proc sys dev dev/pts run; do sudo mount --bind /$fs /mnt/$fs; done
sudo chroot /mnt
# теперь живём «внутри» сломанной системы:
grub-install /dev/sda
update-initramfs -u
passwd # сбросить root-пароль
exit
chroot vs pivot_root
chroot- меняет видимый/, старый корень всё ещё «существует» где-то.pivot_root- буквально меняет местами старый и новый корни, старый можно потом размонтировать. Используется при init контейнера/initramfs.
Для системы внутри контейнера (containerd, runc) - всегда pivot_root. Для одноразового запуска - chroot.
Дебаг - почему не запускается
sudo chroot /srv/jail /bin/bash
▸bash: error while loading shared libraries: libtinfo.so.6: cannot open
Не хватает библиотек. Найти что нужно:
ldd /srv/jail/bin/bash | awk '/not found/' # после chroot - не работает
# вместо этого - снаружи
chroot /srv/jail ldd /bin/bash 2>&1 # упадёт если нет ldd
Альтернатива - strace -e openat чтобы увидеть какие файлы пытаются
открыться:
sudo strace -f -e openat chroot /srv/jail /bin/bash 2>&1 | grep ENOENT