Как мне узнать, что я работаю в chroot?

47

У меня есть установка Unix, которая должна использоваться как chroot и как автономная система. Если он работает как chroot, я не хочу запускать какие-либо службы (cron, inetd и т. Д.), Потому что они будут конфликтовать с хост-системой или будут избыточными.

Как мне написать скрипт оболочки, который ведет себя по-разному в зависимости от того, работает ли он в chroot? Моя непосредственная потребность в современной системе Linux, с /procмонтированной в chroot, и скрипт запускается как root, но приветствуются и более переносимые ответы. (См. Как мне сказать, что я работаю в chroot, если / proc не смонтирован? Для Linux без /proc.)

В целом, предложения, которые работают для других методов сдерживания, были бы интересны. Практический вопрос заключается в том, должна ли эта система запускать какие-либо службы? (Ответ - нет в chroot и да в полноценных виртуальных машинах; я не знаю о промежуточных случаях, таких как тюрьмы или контейнеры.)

Жиль "ТАК - перестань быть злым"
источник

Ответы:

46

Здесь я проверил, initсовпадает ли корень процесса (PID 1) с корнем текущего процесса. Хотя /proc/1/rootэто всегда ссылка на /(если только она initне является chroot, но это не тот случай, который меня волнует), следование по ней ведет к корневому каталогу «master». Этот метод используется в нескольких сценариях обслуживания в Debian, например, для пропуска запуска udev после установки в chroot.

if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
  echo "We are chrooted!"
else
  echo "Business as usual"
fi

(Кстати, это еще один пример того, почему chrootбесполезно для безопасности, если у корневого процесса есть root-доступ. Процессы без полномочий root не могут читать /proc/1/root, но они могут следовать, /proc/1234/rootесли есть запущенный процесс с PID 1234, работающим так же пользователь.)

Если у вас нет прав доступа root, вы можете посмотреть /proc/1/mountinfoи /proc/$$/mountinfo(кратко описано в документации filesystems/proc.txtядра Linux ). Этот файл доступен для чтения всем и содержит много информации о каждой точке монтирования в представлении процесса файловой системы. Пути в этом файле ограничены тем, что chroot влияет на процесс чтения, если таковой имеется. Если чтение процесса /proc/1/mountinfoпривязано к файловой системе, отличной от глобального корня (при условии, что корень pid 1 является глобальным корнем), тогда запись для не /появляется /proc/1/mountinfo. Если чтение процесса /proc/1/mountinfoявляется изолированным в каталог на глобальной корневой файловой системе, то запись для /появляюсь в /proc/1/mountinfo, но с другим идентификатором монтирование. Кстати, корневое поле ($4) указывает, где находится chroot в основной файловой системе.

[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]

Это чисто решение Linux. Это может быть обобщено на другие варианты Unix с достаточно похожим /proc(у Solaris есть подобное /proc/1/root, я думаю, но нет mountinfo).

Жиль "ТАК - перестань быть злым"
источник
1
Это не будет работать в OpenBSD, потому что он имеет случайные PID ; корневой процесс в основном никогда не PID 1. Теперь вы знаете, почему!
Адам Кац
@AdamKatz "... с несколькими очевидными исключениями, например, init (8)." Так что это?
Муру
@muru: ау, ебет Вы сбили меня. Я не уверен, почему init(8)абсолютно необходимо иметь слот № 1, если нет какой-то жестко запрограммированной природы, которая требует этого (в которой я все еще не уверен, почему ). Конечно, в BSD гораздо более продвинутые тюрьмы, чем просто в chroot, поэтому я даже не уверен, насколько это проблематично.
Адам Кац
4
@AdamKatz Все наоборот: pid 1 играет особую роль (он должен пожинать зомби, и он неуязвим для SIGKILL). Программа init является реализацией этой роли. Причина, по которой мой ответ не работает в OpenBSD, не имеет к этому никакого отношения: причина в том, что в OpenBSD нет ничего похожего на Solaris / Linux /proc. В любом случае, мой ответ не предназначался ни для чего, кроме Linux.
Жиль "ТАК - перестань быть злым"
@ Жиль Я полагал, что OpenBSD так или иначе победит это. Тем не менее, я удивлен, что все эти особые элементы роли не могут быть применены к произвольному PID (без последствий), что я и имел в виду в своем выделенном курсивом «почему» ранее.
Адам Кац
22

Как уже упоминались в портативном способе найти номер индексного дескриптора и обнаружение CHROOT тюрьмы изнутри , вы можете проверить , является ли индексный дескриптором /является 2:

$ ls -di /
2 /

Номер инода, отличный от 2, указывает на то, что видимый корень не является фактическим корнем файловой системы. Это не будет обнаруживать chroot, которые оказались корневыми в точке монтирования или в операционных системах со случайными номерами корневых узлов .

l0b0
источник
На каких файловых системах работает эта эвристика?
Жиль "ТАК - перестань быть злым"
Проверено на ext3 и hfs.
10
Так что я дурачился и думаю, что нашел более надежный метод, который не требует прав root (только для Linux). Я все еще открыт для контрпримеров или более переносимых методов.
Жиль "ТАК - перестань быть злым"
6
Это верно для ext [234], но не для всех файловых систем. Он также только проверяет, что ваш корень является корнем файловой системы, которая не может быть смонтирована как настоящий корень. Другими словами, если вы смонтируете другой раздел в / jail и chroot /jail, тогда он будет выглядеть как настоящий корень этого теста.
psusi
1
@ AdamKatz Видимо нет. Протестировано в openbsd 6.0-stable, номер инода по-прежнему равен 2 для фактического корневого пути, в то время как это случайное число для chroot.
Дмитрий Д.Б.
5

Хотя это явно не так переносимо, как многие другие опции, перечисленные здесь, попробуйте сделать это, если вы используете систему на основе Debian ischroot.

См .: https://manpages.debian.org/jessie/debianutils/ischroot.1.en.html.

Чтобы получить статус в консоли напрямую, используя ischroot:

ischroot;echo $?

Коды выхода:

0 if currently running in a chroot
1 if currently not running in a chroot
2 if the detection is not possible (On GNU/Linux this happens if the script is not run as root).
thom_nic
источник