Почему ребенок с пространством имен mount влияет на родительские установки?

Я пытаюсь понять пространства имен Linux, используя сервер Debian jessie, где у меня есть root-доступ.

Рассмотрим этот код:

# /tmp/test.c #define _GNU_SOURCE #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> static char child_stack[1048576]; static int my_child() { system("/bin/bash"); } int main() { pid_t child_pid = clone(my_child, child_stack+1048576, CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); waitpid(child_pid, NULL, 0); return 0; } 

Затем я запускаю эти команды за один сеанс в одном терминале:

 /tmp# id uid=0(root) gid=0(root) groups=0(root),1093867019 /tmp# echo $$ 1804 /tmp# ps -eaf | head UID PID PPID C STIME TTY TIME CMD root 1 0 0 May08 ? 00:00:01 /sbin/init root 2 0 0 May08 ? 00:00:00 [kthreadd] root 3 2 0 May08 ? 00:00:00 [ksoftirqd/0] root 5 2 0 May08 ? 00:00:00 [kworker/0:0H] root 7 2 0 May08 ? 00:00:11 [rcu_sched] root 8 2 0 May08 ? 00:00:00 [rcu_bh] root 9 2 0 May08 ? 00:00:00 [migration/0] root 10 2 0 May08 ? 00:00:00 [watchdog/0] root 11 2 0 May08 ? 00:00:00 [khelper] /tmp# grep /proc /proc/$$/mountinfo 15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw 33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct /tmp# gcc test.c /tmp# ./a.out /tmp# echo $$ 2 /tmp# echo $PPID 1 /tmp# ps -eaf | head UID PID PPID C STIME TTY TIME CMD root 1 0 0 May08 ? 00:00:01 /sbin/init root 2 0 0 May08 ? 00:00:00 [kthreadd] root 3 2 0 May08 ? 00:00:00 [ksoftirqd/0] root 5 2 0 May08 ? 00:00:00 [kworker/0:0H] root 7 2 0 May08 ? 00:00:11 [rcu_sched] root 8 2 0 May08 ? 00:00:00 [rcu_bh] root 9 2 0 May08 ? 00:00:00 [migration/0] root 10 2 0 May08 ? 00:00:00 [watchdog/0] root 11 2 0 May08 ? 00:00:00 [khelper] tmp# grep /proc /proc/$$/mountinfo 15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw 33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=0,timeout=300,minproto=5,maxproto=5,direct /tmp# mount -t proc proc /proc /tmp# grep /proc /proc/$$/mountinfo 92 70 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw 93 92 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=0,timeout=300,minproto=5,maxproto=5,direct 97 92 0:34 / /proc rw,relatime shared:27 - proc proc rw /tmp# ps -eaf UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:31 pts/0 00:00:00 ./a.out root 2 1 0 07:31 pts/0 00:00:00 /bin/bash root 14 2 0 07:31 pts/0 00:00:00 ps -eaf /tmp# exit exit /tmp# echo $$ 1804 /tmp# grep /proc /proc/$$/mountinfo grep: /proc/1804/mountinfo: No such file or directory /tmp# ps -eaf Error, do this: mount -t proc proc /proc /tmp# mount -t proc proc /proc /tmp# grep /proc /proc/$$/mountinfo 15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw 33 15 0:29 / /proc/sys/fs/binfmt_misc rw,relatime shared:20 - autofs systemd-1 rw,fd=22,pgrp=1,timeout=300,minproto=5,maxproto=5,direct 98 15 0:34 / /proc rw,relatime shared:27 - proc proc rw 69 98 0:3 / /proc rw,relatime shared:28 - proc proc rw 

Почему после выхода из дочернего процесса /proc не установлен? Не должны ли какие-либо изменения в монтировании точек, выполняемых дочерним процессом, не влиять на точки монтирования родителя? Кажется, это противоречит ответу Emmet на вопрос https://stackoverflow.com/questions/22889241/linux-understanding-the-mount-namespace-clone-clone-newns-flag .

Когда дочерний процесс создается с clone с флагом CLONE_NEWNS , дочерний процесс получает свое собственное пространство имен монтирования. Операции mount ( mount , umount , mount --bind и т. Д.) В дочернем пространстве имен имеют эффект внутри этого пространства имен, а операции монтирования в родительском пространстве имен имеют эффект только за пределами нового пространства имен.

Кроме того, для общих монстров. Монтирование может быть общим , и в этом случае операции влияют на все пространства имен, в которых используется общий доступ. Типичным вариантом использования для общих монтирования является создание съемных дисков в дочерних пространствах имен, таких как chroots. Существует больше типов отношений (частные монтирования, несвязанные монтировки); для получения дополнительной информации см. документацию ядра .

Вы можете проверить, является ли общий /proc/ PID /mountinfo монтированием, проверяя /proc/ PID /mountinfo : если строка содержит shared: NUMBER то mount является общим, а число является уникальным значением, определяющим набор пространств имен, которыми он делится. Если строка не содержит такого указания, mount является закрытым.

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

Две вещи усложняют ваш сценарий: вы также создаете пространство имен PID, и вы используете /proc как субъект эксперимента, так и как средство наблюдения. Когда ps жалуется, что /proc не монтируется, на самом деле отображается ошибочное сообщение об ошибке – монтируется неправильная процедура ( proc для неправильного пространства имен). Вы можете наблюдать это с помощью ls /proc и cat /proc/1/mountinfo . Я рекомендую делать эксперименты с файловой системой с царапинами, было бы легче понять, что происходит.

 parent # ./a.out
 child # echo $$
 2
 child # ls / proc
 Это proc родителя, с / proc / PID в родительском пространстве имен PID
 child # ps 1
 … в этом
 child # mount -t proc proc / proc
 Теперь / proc в пространстве имен дочерних монстров предназначен для дочернего пространства имен PID
 child # ps 1
 ... a.out
 выход ребенка #
 родитель #

До сих пор неважно, был ли /proc приватным или общим, но теперь он это делает. Если /proc является приватным, то в этот момент мы наблюдаем родительский /proc , который никогда не затрагивался и показывает пространство имен PID. Но если /proc является общим, то команда mount мы выпустили ранее, затронула оба пространства имен, таким образом:

 parent # ls / proc
 acpi asound buddyinfo ...
 parent # ps 1
 Ошибка, сделайте следующее: mount -t proc proc / proc
 На самом деле, / proc монтируется, но это proc для пространства имен PID, которое мы создали ранее, и теперь имеет нулевые запущенные процессы.
 parent # grep -c '/ proc' / proc / mounts
 2
 parent # umount / proc
 Мы размонтировали дочернее пространство имен PID / proc, которое затеняло родительское пространство имен / proc, поэтому «обычный» / proc снова отображается.
 parent # ps 1
 … в этом