Как выполнить chroot с пространствами имен Linux?

14

После прочтения пространств имен Linux у меня сложилось впечатление, что среди множества других функций они являются альтернативой chroot. Например, в этой статье :

Другие применения [пространств имен] включают [...] chroot () - изоляцию стиля процесса от части единой иерархии каталогов.

Однако, когда я клонирую пространство имен монтирования, например, с помощью следующей команды, я все равно вижу все исходное корневое дерево.

unshare --mount -- /bin/bash

Я понимаю, что теперь я могу выполнять дополнительные монтирования в новом пространстве имен, которые не используются совместно с исходным пространством имен, и, таким образом, это обеспечивает изоляцию, но он все еще остается одним и тем же корнем, например /etc, остается одинаковым для обоих пространств имен. Нужно ли еще chrootменять рут или есть альтернатива?

Я ожидал, что этот вопрос даст ответ, но ответ только использует chroot, опять же.

РЕДАКТИРОВАТЬ # 1

Был удаленный комментарий, в котором упоминалось pivot_root. Так как это на самом деле является частью linux/fs/namespace.c, это на самом деле является частью реализации пространств имен. Это говорит о том, что изменение корневого каталога только с помощью unshareи mountневозможно, но пространства имен предоставляют собственную - более умную - версию chroot. Тем не менее, я не понимаю основную идею этого подхода, который делает его принципиально отличным chrootдаже после чтения исходного кода (в смысле, например, безопасности или лучшей изоляции).

РЕДАКТИРОВАТЬ № 2

Это не дубликат этого вопроса . После выполнения всех команд из ответа у меня есть отдельный /tmp/tmp.vyM9IwnKuY (или аналогичный), но корневой каталог все тот же!

koalo
источник
Что касается разницы между pivot_rootи chroot: я взглянул на исходные коды Docker и обнаружил, что если он не выполняется pivot_root, он отступает chroot, т. Е. Эти механизмы считаются, по крайней мере, схожими по функциональности для целей контейнеризации.
Данила Кивер

Ответы:

13

Ввод пространства имен монтирования перед настройкой a chrootпозволяет избежать загромождения пространства имен хоста дополнительными монтированиями, например, для /proc. Вы можете использовать chrootвнутри пространства имен монтирования как приятный и простой взлом.

Я думаю, что у понимания есть свои преимущества pivot_root, но у него есть некоторая кривая обучения. Документация не совсем объясняет все ... хотя есть пример использования man 8 pivot_root(для команды оболочки). man 2 pivot_root(для системного вызова) может быть более понятным, если бы он делал то же самое и включал пример программы на Си.

Как использовать pivot_root

Сразу после входа в пространство имен монтирования вам также потребуется mount --make-rslave /или эквивалентный. В противном случае все ваши изменения монтирования распространяются на монтирования в исходном пространстве имен, включая pivot_root. Вы не хотите этого :).

Если вы использовали unshare --mountкоманду, обратите внимание, что она задокументирована для применения mount --make-rprivateпо умолчанию. AFAICS, это плохое значение по умолчанию, и вы не хотите этого в производственном коде. Например, на этом этапе он не сможет ejectработать на подключенном DVD или USB в пространстве имен хоста. DVD или USB останутся подключенными внутри частного дерева монтирования, и ядро ​​не позволит вам извлечь DVD.

После этого вы можете смонтировать, например, /procкаталог, который вы будете использовать. Так же, как и вы chroot.

В отличие от того, когда вы используете chroot, pivot_rootтребует, чтобы ваша новая корневая файловая система была точкой монтирования. Если это не один уже, вы можете удовлетворить это, просто применяя привязка установки: mount --rbind new_root new_root.

Используйте pivot_root- и затем umountстарую корневую файловую систему, с-l / MNT_DETACH. ( Вам не нужно umount -R, что может занять больше времени. )

Технически, использование, pivot_rootкак правило, должно включать использование chroot; это не «или-или».

Согласно man 2 pivot_root , он определяется только как замена корня пространства имен монтирования. Не определено, на какую физическую директорию указывает корень процесса. Или текущий рабочий каталог ( /proc/self/cwd). Бывает, что так и есть, но это хак для обработки потоков ядра. На странице написано, что это может измениться в будущем.

Обычно вы хотите эту последовательность:

chdir(new_root);            // cd new_root
pivot_root(".", put_old);   // pivot_root . put_old
chroot(".");                // chroot .

Пост chrootв этой последовательности является еще одной тонкой деталью . Хотя смысл pivot_rootсостоит в том, чтобы переставить пространство имен монтирования, кажется, что код ядра находит корневую файловую систему для перемещения, просматривая корень для каждого процесса, который и chrootустанавливает.

Зачем использовать pivot_root

В принципе, имеет смысл использовать pivot_rootдля безопасности и изоляции. Мне нравится думать о теории безопасности на основе возможностей . Вы передаете список необходимых ресурсов, и процесс не может получить доступ к другим ресурсам. В данном случае речь идет о файловых системах, передаваемых в пространство имен монтирования. Эта идея в целом применима к функции Linux "пространств имен", хотя я, вероятно, не очень хорошо ее выражаю.

chrootтолько устанавливает корень процесса, но процесс все еще ссылается на полное пространство имен монтирования. Если процесс сохраняет привилегию для выполнения chroot, он может выполнить обратное копирование пространства имен файловой системы. Как подробно описано вman 2 chroot статье, «суперпользователь может сбежать из« тюрьмы chroot »с помощью ...».

Еще один заставляющий задуматься способ отменить chrootэто nsenter --mount=/proc/self/ns/mnt. Возможно, это более сильный аргумент в пользу принципа. nsenter/ setns()обязательно перезагружает корень процесса из корня пространства имен монтирования ... хотя тот факт, что это работает, когда оба ссылаются на разные физические каталоги, может рассматриваться как ошибка ядра. (Техническое примечание: может быть несколько файловых систем, смонтированных поверх друг друга в корне; setns()используется верхняя, самая последняя из которых смонтирована).

Это иллюстрирует одно преимущество объединения пространства имен монтирования с «пространством имен PID». Находясь внутри пространства имен PID, вы не сможете войти в пространство имен монтирования неограниченного процесса. Это также не позволяет вам войти в корень неограниченного процесса ( /proc/$PID/root). И, конечно же, пространство имен PID также не позволяет вам убивать любой процесс, находящийся вне его :-).

sourcejedi
источник
Это уже очень помогает. Тем не менее, я не уверен, что вы подразумеваете под «верхом в пространстве имен». И есть ли способ изменить это?
Коало
1
@koalo отредактировано :-). ps я не знаю, зачем вам нужен fstab для "make-rslave" / "make-rprivate". системный switch-root.c просто делаетmount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)
sourcejedi
1
@koalo, а затем разработчики ядра Linux использовали «rootfs», когда они назвали четвертую вещь :-P. unix.stackexchange.com/questions/152029/...
sourcejedi
1
Этот и другие ответы @sourcejedi были исключительно полезны, я бы спросил: «pivot_root: не могу размонтировать put_old как занято», но ответ уже был здесь, будьте ленивы, потому что сила не сработаетumount -l ./oldroot
earcam
1
Недавно было обновлено руководство man pivot_root (2) с несколькими пояснениями, и теперь оно содержит пример программы. Вы можете обновить свой ответ, чтобы отразить это? Страница man теперь также объясняет хороший pivot_root(".", ".")трюк, который на самом деле самый простой способ использовать pivot_rootв большинстве случаев (не chrootобязательно).
Филипп Вендлер