![Странное поведение pivot_root(".", ".") в пространстве имен монтирования](https://rvso.com/image/168809/%D0%A1%D1%82%D1%80%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5%20%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5%20pivot_root(%22.%22%2C%20%22.%22)%20%D0%B2%20%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D1%81%D1%82%D0%B2%D0%B5%20%D0%B8%D0%BC%D0%B5%D0%BD%20%D0%BC%D0%BE%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F.png)
Я пытаюсь разобраться в контейнерах и наткнулся на трюк, по-видимому, найденный разработчиками LXC, см.этот PR рунк: Вы можете вызвать pivot_root(".", ".")
, который избегает необходимости в каталоге для размещения старого корня. Однако это заставляет пространство имен монтирования вести себя странно:
unshare --user --map-root-user --mount bash -c "
mount --bind containerfs bindmountpoint
cd bindmountpoint
pivot_root . .
# this is fine:
ls -l /
# this is not fine:
ls -l /..
"
Родительский элемент .
, доступ к которому осуществляется через ./..
или /..
или , /proc/<any>/cwd/..
указывает на корень пространства имен корневого монтирования (я еще не пробовал вкладывать)! Он не указывает на родителя containerfs
nor bindmountpoint
, а на самом деле на корень пространства имен корневого/внешнего монтирования.
Аналогично, когда я пробую nsenter --user --preserve-credentials --mount --target=<pid>
, то этот новый процесс помещает свой CWD в корень пространства имен корневого монтирования.
Ничего из этого не происходит, когда я pivot_root(".", "oldroot")
. Поведение также исчезает при размонтировании старого корня, либо через файловый дескриптор, umount -l /
либо umount -l /proc/1/cwd
.
Я также пробовал эту последовательность системных вызовов из пользовательской программы на языке C, поскольку документация pivot_root
только дает гарантии относительно текущего процесса (поэтому я делаю все в одном процессе). Поведение такое же, как и в многопроцессных шагах с использованием инструментов CLI, показанных выше.
Протестировано на ядре 5.3.
Что происходит, когда я бегу pivot_root(".", ".")
?
решение1
pivot_root(new_root, put_old)
перемещает старый корневой каталог вызывающего процесса (который должен быть корнем монтирования) на put_old
и помещает new_root
на его место. Затем он устанавливает текущий каталог и корень каждого процесса, который был установлен в старый корневой каталог, на new_root
.
Итак, после того, как pivot_root(".", ".")
новый корневой каталог смонтировал старый корневой каталог поверх себя.
Всякий раз, когда ..
в противном случае он разрешался бы в каталог, в котором смонтирован другой каталог, он фактически разрешался бы в каталог, смонтированный наверху. Это соответствует историческому поведению Unix и Linux, где ..
, за исключением корневого каталога файловой системы, не было специальной обработки в обходе пути и было реализовано записью каталога, сохраненной на диске.
Это не экранирование пространства имен монтирования.
решение2
Похоже на настоящую ошибку...
Проверьте последнюю версию ядра вашего дистрибутива и сообщите о ней со всеми подробностями (приложите свою тестовую программу!).