Provided by: manpages-ru_4.19.0-7_all bug

ИМЯ

       user_namespaces - обзор пользовательских пространств имён Linux

ОПИСАНИЕ

       Обзор пространств имён смотрите в namespaces(7).

       Пользовательские  пространства  имён  изолируют  идентификаторы и атрибуты безопасности, в
       частности ID пользователя и ID группы (смотрите credentials(7)), корневой  каталог,  ключи
       (смотрите keyrings(7)) и мандаты (смотрите capabilities(7)). Идентификаторы пользователя и
       группы процесса могут отличаться внутри и снаружи пользовательского пространства  имён.  В
       частности,  процесс может иметь обычный бесправный пользовательский ID снаружи и ID равный
       0 внутри пространства имён; другими  словами,  процесс  имеет  доступ  ко  всем  операциям
       внутри  пользовательского  пространства  имён,  но  не  имеет  доступа к привилегированным
       операциям вне пространства имён.

   Вложенные пространства имён, членство пространств имён
       User namespaces can be nested; that is, each user namespace—except  the  initial  ("root")
       namespace—has  a  parent  user namespace, and can have zero or more child user namespaces.
       The parent user namespace is the user namespace of  the  process  that  creates  the  user
       namespace via a call to unshare(2)  or clone(2)  with the CLONE_NEWUSER flag.

       The  kernel  imposes  (since  Linux  3.11) a limit of 32 nested levels of user namespaces.
       Calls to unshare(2)  or clone(2)  that would cause this limit to be exceeded fail with the
       error EUSERS.

       Каждый процесс является членом только одного пользовательского пространства имён. Процесс,
       созданный с помощью fork(2) или clone(2) без флага CLONE_NEWUSER, является членом того  же
       пользовательского  пространства имён что и его родитель. Однонитевой процесс может перейти
       в другое пользовательское пространство имён с помощью setns(2), если в этом пространстве у
       него  есть  мандат  CAP_SYS_ADMIN; после перехода он получает полный набор мандатов в этом
       пространстве имён.

       Вызов clone(2) или unshare(2) с флагом CLONE_NEWUSER делает новый дочерний (для  clone(2))
       или  вызвавший (для unshare(2)) процесс членом нового пользовательского пространства имён,
       создаваемого вызовом.

       Операцию NS_GET_PARENT ioctl(2) можно  использовать  для  обнаружения  родительской  связи
       между пространствами имён пользователя; смотрите ioctl_ns(2).

   Мандаты
       Дочерний   процесс,  созданный  clone(2)  с  флагом  CLONE_NEWUSER,  запускается  в  новом
       пользовательском  пространстве  имён  с  полным  набором  мандатов.  Аналогично,  процесс,
       создающий  новое пользовательское пространство имён с помощью unshare(2) или переходящий в
       существующее пользовательское пространство имён с помощью setns(2), получает полный  набор
       мандатов   в  этом  пространстве  имён. С другой стороны, этот процесс не имеет мандатов в
       родительском  (в  случае  clone(2))  или  предыдущем  (в  случае  unshare(2)  и  setns(2))
       пользовательском  пространстве имён, даже если новое пространство имён создано или переход
       осуществлялся  суперпользователем  (т.  е.,  процесс  с  ID  пользователя  0  в   корневом
       пространстве имён).

       Заметим,  что  вызов  execve(2)  приводит  к  пересчёту мандатов процесса обычным порядком
       (смотрите capabilities(7)). Следовательно, если ID пользователя процесс не равно 0  внутри
       пространства  имён  или  исполняемый  файл  имеет непустую маску наследования мандатов, то
       процесс теряет все мандаты. Смотрите описание отображения пользовательских и групповых  ID
       далее.

       A  call  to  clone(2)   or  unshare(2)  using the CLONE_NEWUSER flag or a call to setns(2)
       that moves the caller into  another  user  namespace  sets  the  "securebits"  flags  (see
       capabilities(7))  to their default values (all flags disabled) in the child (for clone(2))
       or caller (for unshare(2)  or setns(2)).  Note that  because  the  caller  no  longer  has
       capabilities  in  its original user namespace after a call to setns(2), it is not possible
       for a process  to  reset  its  "securebits"  flags  while  retaining  its  user  namespace
       membership  by  using  a pair of setns(2) calls to move to another user namespace and then
       return to its original user namespace.

       Правила  определения  наличия  мандата  у   процесса   в   определённом   пользовательском
       пространстве имён следующие:

       •  Процесс  имеет  мандат  внутри  пользовательского  пространства  имён, если он является
          членом этого пространства имён и имеет мандат  в  своём  наборе  эффективных  мандатов.
          Процесс   может  получить  мандаты  в  своём  наборе  эффективных  мандатов  различными
          способами. Например, он может запустить программу с битом set-user-ID  или  исполняемый
          файл,  имеющий  мандаты  файла.  Также  процесс  может  получить мандаты при выполнении
          clone(2), unshare(2) или setns(2), как описывалось ранее.

       •  Если процесс имеет мандат в пользовательском пространстве имён, то он также имеет  этот
          мандат во всех дочерних (и позже удалённых потомках) пространствах имён.

       •  При   создании   пользовательского   пространства   имён  ядро  записывает  эффективный
          пользовательский ID создающего процесса как  «владельца»  пространства  имён.  Процесс,
          располагающийся  в родительском пространстве имён пользовательского пространства имён и
          чей эффективный пользовательский ID совпадает с владельцем пространства имён, имеет все
          мандаты в пространстве имён. Предыдущее правило означает, что у процесса также есть все
          мандаты во всех в последствии удалённых потомках пользовательских пространств имён. Для
          обнаружения  идентификатора пользователя-владельца пространства имён можно использовать
          операцию NS_GET_OWNER_UID вызова ioctl(2); смотрите ioctl_ns(2).

   Влияние мандатов внутри пространства имён пользователя
       Наличие  мандата  внутри  пространства  имён  пользователя  разрешает  процессу  выполнять
       операции  (требующие привилегий) с ресурсами, управляемыми только этим пространством имён.
       Иначе говоря, наличие мандата в  пользовательском  пространстве  имён  разрешает  процессу
       выполнять    привилегированные    операции    с   ресурсами,   которые   управляются   (не
       пользовательскими) пространствами имён, принадлежащими (связанными  с)  пространству  имён
       пользователя (смотрите следующий подраздел).

       On the other hand, there are many privileged operations that affect resources that are not
       associated with any namespace type, for example, changing the system (i.e., calendar) time
       (governed  by  CAP_SYS_TIME),  loading  a  kernel module (governed by CAP_SYS_MODULE), and
       creating a device (governed by CAP_MKNOD).  Only a process with privileges in the  initial
       user namespace can perform such operations.

       Наличие   CAP_SYS_ADMIN   внутри   пользовательского   пространства  имён,  принадлежащему
       пространству имён монтирования  процесса,  позволяет  этому  процессу  создавать  привязки
       монтирования и монтировать следующие типы файловых систем:

           •  /proc (начиная с Linux 3.8)
           •  /sys (начиная с Linux 3.8)
           •  devpts (начиная с Linux 3.9)
           •  tmpfs(5)  (начиная с Linux 3.9)
           •  ramfs (начиная с Linux 3.9)
           •  mqueue (начиная с Linux 3.9)
           •  bpf (начиная с Linux 4.4)
           •  overlayfs (начиная с Linux 5.11)

       Наличие   CAP_SYS_ADMIN   внутри   пользовательского   пространства  имён,  принадлежащему
       пространству имён  cgroup  процесса,  позволяет  (начиная  с  Linux  4.6)  этому  процессу
       монтировать  именованные  иерархии  файловой системы cgroup версии 2 и cgroup версии 1 (т.
       е., файловые системы cgroup, монтируемые с параметром "none,name=").

       Наличие  CAP_SYS_ADMIN  внутри   пользовательского   пространства   имён,   принадлежащему
       пространству имён PID процесса, позволяет (начиная с Linux 3.8) этому процессу монтировать
       файловые системы /proc.

       Однако заметим, что  монтирование  блочных  файловых  систем  может  производиться  только
       процессом, имеющим CAP_SYS_ADMIN в начальном пространстве имён пользователя.

   Взаимодействие между пользовательскими и другими типами пространств имён
       Начиная  с  Linux  3.8,  непривилегированные  процессы  могут  создавать  пользовательские
       пространства  имён,  а  для  создания  пространств  имён  других  типов  требуется  мандат
       CAP_SYS_ADMIN в пользовательском пространстве имён вызывающего.

       После  создания  не  пользовательского пространства имён оно принадлежит пользовательскому
       пространству имён, в котором  на  момент  создания  пространства  имён  создающий  процесс
       являлся   членом.   Для   привилегированных   операций   над  ресурсами,  управляемыми  не
       пользовательским   пространством   имён,   от   процесса   требуется   иметь   мандаты   в
       пользовательском  пространстве имён, которому принадлежит не пользовательское пространство
       имён.

       Если вместе  с  флагами  CLONE_NEW*  указан  флаг  CLONE_NEWUSER  в  вызове  clone(2)  или
       unshare(2),  то  пользовательское пространство имён гарантированно создаётся первым, давая
       потомку (clone(2)) или вызывающему (unshare(2))  права  на  остальные  пространства  имён,
       создаваемые вызовом. Даже бесправный вызывающий может задать такую комбинацию флагов.

       При создании нового пространства имён (не пользовательского пространства имён) посредством
       clone(2) или unshare(2), ядро записывает  пользовательское  пространство  имён  создающего
       процесса как владельца нового пространства имён (эту связь нельзя изменить). Когда процесс
       в новом пространстве имён  в  дальнейшем  выполняет  привилегированные  операции,  которые
       работают  с глобальными ресурсами, изолированными пространством имён, выполняется проверка
       прав согласно мандатам процесса в пользовательском пространстве имён, которое ядро связало
       с  новым пространством имён. Например, предположим, что процесс пытается изменить имя узла
       (sethostname(2)) — ресурс, управляемый пространство имён UTS. В этом  случае,  ядро  будет
       искать  пространство  имён  пользователя,  принадлежащее пространству имён UTS процесса, и
       проверять что процесс имеет необходимый мандат (CAP_SYS_ADMIN) в  этом  пространстве  имён
       пользователя.

       Операцию  NS_GET_USERNS  ioctl(2)  можно  использовать  для  обнаружения пространства имён
       пользователя,  которое  владеет   не   пользовательским   пространством   имён;   смотрите
       ioctl_ns(2).

   Отображение идентификаторов пользователей и групп: uid_map и gid_map
       В   новом   созданном   пользовательском   пространстве   имён   отсутствует   отображение
       пользовательских  ID  (ID  групп)  в  родительское  пользовательское  пространство.   Файл
       /proc/pid/uid_map  и  /proc/pid/gid_map  (доступны  начиная  с  Linux  3.5)  предоставляют
       отображения пользовательских и групповых ID внутри пользовательского пространства имён для
       процесса  pid.  Эти  файлы  можно  читать  для  просмотра  отображений  в пользовательском
       пространстве имён и писать (однократно) для определения отображений.

       В следующих параграфах объясняется формат uid_map; gid_map имеет тот же формат, но  каждый
       экземпляр «ID пользователя» заменяется на «ID группы».

       Файл   uid_map   предоставляет   отображение   пользовательских  ID  из  пользовательского
       пространства имён процесса pid в  пользовательское  пространство  имён  процесса,  который
       открыл uid_map (но смотрите уточнение далее). Другими словами, процессы, которые находятся
       в разных пользовательских пространствах имён, возможно будут видеть  разные  значения  при
       чтении  соответствующего файла uid_map, в зависимости от отображений пользовательских ID у
       пользовательских пространств имён читающего процесса.

       Каждая  строка  в  файле  uid_map  определяет  отображение  1-в-1  непрерывного  диапазона
       пользовательских  ID  между  двумя  пользовательскими  пространствами  имён  (при создании
       пользовательского пространства имён этот файл пуст). В каждой строке содержится три  числа
       через  пробел.  Первые два числа определяют начальный пользовательский ID в каждом из двух
       пользовательских пространств имён. Третье число определяет длину отображаемого  диапазона.
       Эти поля рассматриваются так:

       (1)  Начало  диапазона  пользовательских  ID в пользовательском пространстве имён процесса
            pid.

       (2)  Начало диапазона пользовательских ID, на который  отображаются  пользовательские  ID,
            указанные  в  первом  поле.  Интерпретация второго поля зависит от того, находится ли
            процесс, открывший uid_map, и процесс  pid,  в  одном  пользовательском  пространстве
            имён:

            (а)  Если  два  процесса находятся в разных пользовательских пространствах имён: поле
                 два — начало диапазона пользовательских ID в пользовательском пространстве  имён
                 процесса, который открыл uid_map.

            (б)  Если два процесса находятся в одном пользовательском пространстве имён: поле два
                 —  начало  диапазона  пользовательских  ID   в   родительском   пользовательском
                 пространстве  имён  процесса  pid.  Это  позволяет  открывшему  uid_map  (обычно
                 открывают  /proc/self/uid_map)  видеть   отображение   пользовательских   ID   в
                 пользовательском  пространстве  имён  процесса,  создавшего это пользовательское
                 пространство имён.

       (3)  Длина  диапазона  пользовательских   ID,   выполняющего   отображение   между   двумя
            пользовательскими пространствами имён.

       System  calls  that return user IDs (group IDs)—for example, getuid(2), getgid(2), and the
       credential fields in the structure returned by  stat(2)—return  the  user  ID  (group  ID)
       mapped into the caller's user namespace.

       Когда  процесс  обращается  к файлу, его ID пользователя и группы отображаются в начальном
       пользовательском пространстве имён с целью проверки прав доступа  и  назначенного  ID  при
       создании файла. Когда процесс получает ID пользователя и группы файла через stat(2), то ID
       отображаются в обратном направлении, для создания значений,  относительно  отображений  ID
       пользователя и группы процесса.

       Начальное  пользовательское пространство имён не имеет родительского пространства имён, но
       для однородности, для него ядро предоставляет фиктивные файлы отображения ID пользователей
       и  групп.  Посмотрим  на  файл  uid_mapgid_map  тоже  самое) из оболочки в начальном
       пространстве имён:

           $ cat /proc/$$/uid_map
                    0          0 4294967295

       Данное отображение показывает, что диапазон начинающийся с пользовательского ID 0  в  этом
       пространстве  имён,  отображается  в  диапазон,  начинающийся,  с  0,  в  (несуществующее)
       родительское пространство  имён,  и  длина  диапазона  равна  самому  большому  32-битному
       беззнаковому  целому.  Значение  4294967295 (32-битное знаковое значение -1) оставлено без
       отображения. Предназначение: (uid_t) -1 используется в  некоторых  интерфейсах  (например,
       setreuid(2))  для  указания  «отсутствия  ID  пользователя».  Оставление  (uid_t)  -1  без
       отображения и его не использование гарантирует, что при использовании этих интерфейсов  не
       будет проблем).

   Отображение идентификаторов пользователей и групп: запись в uid_map и gid_map
       После создания нового пользовательского пространства имён в файл uid_map один из процессов
       в пространстве  имён  может  выполнить  однократную  запись  для  определения  отображения
       пользовательских ID в новом пользовательском пространстве имён. Повторная попытка записи в
       файл uid_map в пользовательском пространстве имён  завершится  с  ошибкой  EPERM.  Эти  же
       правила применимы к файлам gid_map.

       The lines written to uid_map (gid_map)  must conform to the following validity rules:

       •  В трёх полях должны быть корректные числа и последнее поле должно быть больше 0.

       •  Строки заканчиваются символами новой строки.

       •  Существует  ограничение  на  количество  строк  в  файле.  В  Linux  4.14  и старее оно
          установлено (произвольно) равным пятью строкам. Начиная с Linux 4.14 его значение равно
          340  строкам.  Также,  количество байт, записываемых в файл, должно быть меньше размера
          системной страницы,  и  запись  должна  выполняться  в  начало  файла  (т.  е.,  нельзя
          использовать lseek(2) и pwrite(2) для записи в файл при ненулевом смещении).

       •  Диапазон  пользовательских  ID  (групповых  ID),  указанный  в каждой строке, не должен
          перекрываться с диапазонами в других строках.  В  первой  реализации  (Linux  3.8)  это
          требование  удовлетворялось  простейшим  способом,  который  задавал другое требование:
          значения в полях 1 и 2 следующих одна за одной  строк,  должны  увеличиваться,  что  не
          давало  создавать некоторые корректные отображения. В Linux 3.9 и новее это ограничение
          было снято, и допустим любой набор не перекрывающихся отображений.

       •  В файл должна быть записана, как минимум, одна строка.

       Попытки записи, нарушающие перечисленные выше правила, завершаются с ошибкой EINVAL.

       In order for a process to write to the /proc/pid/uid_map (/proc/pid/gid_map)  file, all of
       the following permission requirements must be met:

       •  Записывающий  процесс  должен  иметь  мандат CAP_SETUID (CAP_SETGID) в пользовательском
          пространстве имён процесса pid.

       •  Записывающий процесс должен находиться в пользовательском  пространстве  имён  процесса
          pid или быть родительским пользовательским пространством имён процесса pid.

       •  Отображаемые   пользовательские   ID   (групповые   ID)  должны  иметь  соответствующее
          отображение в родительском пользовательском пространстве имён.

       •  If updating /proc/pid/uid_map to create a  mapping  that  maps  UID  0  in  the  parent
          namespace, then one of the following must be true:

          (а)  if  writing  process  is  in  the  parent  user  namespace,  then it must have the
               CAP_SETFCAP capability in that user namespace; or

          (б)  if the writing process is in the child  user  namespace,  then  the  process  that
               created  the  user  namespace  must  have  had the CAP_SETFCAP capability when the
               namespace was created.

          This rule has been in place since Linux 5.12.  It eliminates an  earlier  security  bug
          whereby  a  UID  0  process  that  lacks the CAP_SETFCAP capability, which is needed to
          create a binary with namespaced file capabilities (as  described  in  capabilities(7)),
          could nevertheless create such a binary, by the following steps:

          (1)  Create a new user namespace with the identity mapping (i.e., UID 0 in the new user
               namespace maps to UID 0 in the parent namespace), so that UID 0 in both namespaces
               is equivalent to the same root user ID.

          (2)  Since  the  child process has the CAP_SETFCAP capability, it could create a binary
               with namespaced file capabilities that would then be effective in the parent  user
               namespace (because the root user IDs are the same in the two namespaces).

       •  Применимо к одному из двух случаев:

          (а)  Или  записывающий  процесс  имеет  мандат  CAP_SETUID  (CAP_SETGID) в родительском
               пользовательском пространстве имён.

               •  В дальнейшем ограничения не применяются: процесс может создавать отображения  в
                  произвольные пользовательские ID (групповые ID) в родительском пользовательском
                  пространстве имён.

          (б)  Или в противном случае накладываются следующие (все) ограничения:

               •  Данные, записываемые в uid_map (gid_map),  должны  состоять  из  одной  строки,
                  которая отображает эффективный пользовательский ID (групповой ID) записывающего
                  процесса в родительском пользовательском пространстве имён  в  пользовательский
                  ID (групповой ID) в пользовательском пространстве имён.

               •  Записывающий процесс должен иметь мандат тот же эффективный пользовательский ID
                  что и процесс, который создал пользовательское пространство имён.

               •  In the case of gid_map, use of the setgroups(2)   system  call  must  first  be
                  denied  by  writing  "deny"  to the /proc/pid/setgroups file (see below) before
                  writing to gid_map.

       Попытки записи, нарушающие перечисленные выше правила, завершаются с ошибкой EPERM.

   Project ID mappings: projid_map
       Similarly to user and group ID mappings, it is possible to create project ID mappings  for
       a  user  namespace.   (Project  IDs  are  used  for  disk  quotas;  see  setquota(8)   and
       quotactl(2).)

       Project ID mappings are defined by writing to the /proc/pid/projid_map file (present since
       Linux 3.7).

       The  validity rules for writing to the /proc/pid/projid_map file are as for writing to the
       uid_map file; violation of these rules causes write(2)  to fail with the error EINVAL.

       The permission rules for writing to the /proc/pid/projid_map file are as follows:

       •  Записывающий процесс должен находиться в пользовательском  пространстве  имён  процесса
          pid или быть родительским пользовательским пространством имён процесса pid.

       •  The mapped project IDs must in turn have a mapping in the parent user namespace.

       Violation of these rules causes write(2)  to fail with the error EPERM.

   Взаимодействие с системными вызовами, которые изменяют UID или GID процесса.
       В  пользовательском  пространстве  имён,  в  котором не выполнялась запись в файл uid_map,
       системные вызовы, изменяющие ID  пользователя,  будут  завершаться  с  ошибкой.  Подобными
       образом,  если  не  выполнялась  запись в файл gid_map, то системные вызовы, изменяющие ID
       группы, будут завершаться с  ошибкой.  После  записи  в  файл  uid_map  и  gid_map  только
       отображённые значения могут использоваться в системных вызовах, изменяющих ID пользователя
       или группы.

       Для ID пользователя, это относится  к следующим системным вызовам: setuid(2), setfsuid(2),
       setreuid(2)  и  setresuid(2). Для ID группы, это относится  к следующим системным вызовам:
       setgid(2), setfsgid(2), setregid(2), setresgid(2) и setgroups(2).

       Writing "deny" to the /proc/pid/setgroups file before writing  to  /proc/pid/gid_map  will
       permanently   disable   setgroups(2)   in   a   user   namespace   and  allow  writing  to
       /proc/pid/gid_map without having the CAP_SETGID capability in the parent user namespace.

   The /proc/pid/setgroups file
       The /proc/pid/setgroups file  displays  the  string  "allow"  if  processes  in  the  user
       namespace  that  contains the process pid are permitted to employ the setgroups(2)  system
       call; it displays "deny" if setgroups(2)  is not permitted in that user  namespace.   Note
       that  regardless  of  the  value  in  the  /proc/pid/setgroups file (and regardless of the
       process's  capabilities),   calls   to   setgroups(2)    are   also   not   permitted   if
       /proc/pid/gid_map has not yet been set.

       A  privileged  process  (one with the CAP_SYS_ADMIN capability in the namespace) may write
       either of the strings "allow" or "deny" to this file before writing a group ID mapping for
       this user namespace to the file /proc/pid/gid_map.  Writing the string "deny" prevents any
       process in the user namespace from employing setgroups(2).

       Сущность ограничений, описанных в предыдущем  абзаце  в  том,  чтобы  разрешить  запись  в
       /proc/pid/setgroups    только    когда    запрещено   вызывать   setgroups(2),   так   как
       /proc/pid/gid_map  не  настроен.  Это  гарантирует,  что  процесс  не  сможет  перейти  из
       состояния,  в котором setgroups(2) разрешён, в состояние, в котором setgroups(2) запрещён;
       процесс может переходить только из состояния, когда setgroups(2)  запрещён,  в  состояние,
       когда setgroups(2) разрешён.

       The default value of this file in the initial user namespace is "allow".

       Once  /proc/pid/gid_map has been written to (which has the effect of enabling setgroups(2)
       in the user namespace), it is no longer possible  to  disallow  setgroups(2)   by  writing
       "deny" to /proc/pid/setgroups (the write fails with the error EPERM).

       Дочернее  пользовательское пространство имён наследует значение /proc/pid/setgroups своего
       родителя.

       If the setgroups file has the value "deny",  then  the  setgroups(2)   system  call  can't
       subsequently  be  reenabled  (by  writing  "allow"  to  the  file) in this user namespace.
       (Attempts to do so fail with the error EPERM.)  This restriction also propagates  down  to
       all child user namespaces of this user namespace.

       The  /proc/pid/setgroups  file was added in Linux 3.19, but was backported to many earlier
       stable kernel series, because it addresses a security issue.  The  issue  concerned  files
       with  permissions  such as "rwx---rwx".  Such files give fewer permissions to "group" than
       they do to "other".  This means that dropping groups using  setgroups(2)   might  allow  a
       process  file  access  that  it  did  not  formerly  have.   Before  the existence of user
       namespaces this was not  a  concern,  since  only  a  privileged  process  (one  with  the
       CAP_SETGID  capability)  could  call setgroups(2).  However, with the introduction of user
       namespaces, it became possible for an unprivileged process to create a  new  namespace  in
       which  the user had all privileges.  This then allowed formerly unprivileged users to drop
       groups  and  thus  gain  file  access  that   they   did   not   previously   have.    The
       /proc/pid/setgroups  file was added to address this security issue, by denying any pathway
       for an unprivileged process to drop groups with setgroups(2).

   Неотображённые пользовательские и групповые ID
       Есть несколько мест, где в пользовательском пространстве  могут  появиться  неотображённые
       пользовательские  ID  (групповые  ID).  Например,  первый процесс в новом пользовательском
       пространстве имён может вызвать getuid(2) до определения отображения  пользовательских  ID
       для   пространства   имён.  В  большинстве  случаев,  неотображённый  пользовательский  ID
       преобразуется в пользовательский ID (групповой ID) переполнения  (overflow);  значение  по
       умолчанию  для  пользовательского  ID  (группового  ID) переполнения равно 65534. Смотрите
       описание /proc/sys/kernel/overflowuid и /proc/sys/kernel/overflowgid в proc(5).

       Случаи, где неотображённые ID отображаются в таком виде, относятся  к  системным  вызовам,
       которые  возвращают  пользовательские  ID  (getuid(2),  getgid(2)  и  подобные),  мандаты,
       передаваемые через доменный сокет UNIX, мандаты, возвращаемые stat(2), waitid(2) и  System
       V  IPC  «ctl»-операциями  IPC_STAT,  мандаты,  показываемые  в /proc/pid/status и файлах в
       /proc/sysvipc/*, мандаты, возвращаемые в поле si_uid структуры  siginfo_t,  полученной  по
       сигналу  (смотрите  sigaction(2)),  мандаты,  записываемые в файл учёта процесса (смотрите
       acct(5)), и мандаты,  возвращаемые  с  уведомлениями  очереди  сообщений  POSIX  (смотрите
       mq_notify(3)).

       Есть  один  известный  случай,  где  неотображённый  пользовательский  и  групповой  ID не
       преобразуется в соответствующее значение ID переполнения. Если при просмотре файла uid_map
       или gid_map обнаруживается, что для второго поля нет отображения, то поле отображается как
       4294967295 (-1 для беззнакового целого).

   Доступ к файлам
       In order to determine permissions when  an  unprivileged  process  accesses  a  file,  the
       process  credentials (UID, GID) and the file credentials are in effect mapped back to what
       they would be in the initial user namespace and then compared to determine the permissions
       that  the process has on the file.  The same is also true of other objects that employ the
       credentials plus permissions mask accessibility model, such as System V IPC objects.

   Операции с файловыми мандатами
       Некоторые мандаты позволяют процессу обходить различные ограничения, налагаемые  ядром  на
       выполнение  операций  над файлами, принадлежащими другим пользователям или группам. Список
       мандатов: CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER и CAP_FSETID.

       Внутри  пользовательского  пространства  имён  эти  мандаты  позволяют  процессу  обходить
       правила, если процесс имеет соответствующий мандат на файле, подразумевающий что:

       •  процесс   имеет   соответствующий   эффективный   мандат   в  своём  пространстве  имён
          пользователя; и

       •  файловые ID пользователя и группы корректно отображаются в пользовательскомпространстве
          имён.

       Мандат  CAP_FOWNER учитывается по-другому: it allows a process to bypass the corresponding
       rules so long as at least the file's user ID has a mapping in the user namespace  (т.  е.,
       файловый ID группы может не иметь корректного отображения).

   Программы с установленными битами set-user-ID и set-group-ID
       Когда   процесс   внутри   пользовательского   пространства  имён  выполняет  программу  с
       установленным битом set-user-ID (set-group-ID), то эффективный  ID  пользователя  (группы)
       внутри пространства имён изменяется на значение, отображённое для ID пользователя (группы)
       файла. Однако,  если  ID  пользователя  или  группы  файла  не  имеет  отображения  внутри
       пространства  имён,  то  бит  set-user-ID  (set-group-ID) просто игнорируется: выполняется
       новая программа, но эффективный ID пользователя (группы)  остаётся  не  изменённым  (такое
       поведение  зеркально  семантике  выполнения  программы  с  set-user-ID  или  set-group-ID,
       располагающейся в файловой системе, которая была  смонтирована  с  флагом  MS_NOSUID,  как
       описано в mount(2)).

   Разное
       Когда  ID  пользователя и группы процесса передаются через доменный сокет UNIX в процесс в
       другом пользовательском пространстве имён (смотрите описание SCM_CREDENTIALS  в  unix(7)),
       то  они  транслируются  в  соответствующие значения согласно отображению ID пользователя и
       группы принимающего процесса.

СТАНДАРТЫ

       Пространства имён есть только в Linux.

ЗАМЕЧАНИЯ

       За  эти  годы  в  ядро  Linux  добавлено  много  свойств,  которые  были  доступны  только
       привилегированным пользователям, так как их возможности слишком велики, чтобы наделять ими
       приложения с set-user-ID. В целом, становится  безопасно  разрешать  пользователю  root  в
       пользовательском   пространстве   имён   использовать  эти  свойства,  так  как  будучи  в
       пользовательском пространстве имён, он не может получить больше прав,  чем  имеет  root  в
       пользовательском пространстве имён.

   Global root
       The  term "global root" is sometimes used as a shorthand for user ID 0 in the initial user
       namespace.

   Доступность
       Для использования пользовательских пространств имён ядро должно быть собрано с  параметром
       CONFIG_USER_NS. Пользовательские пространства имён требуют поддержки во многих подсистемах
       ядра. Если  в  ядре  задействована  неподдерживаемая  подсистема,  то  включить  поддержку
       пользовательских пространств имён невозможно.

       В  Linux  3.8  самые важные подсистемы поддерживают пользовательские пространства имён, но
       значительное  количество  файловых  систем  не  имеют   инфраструктуры   для   отображения
       пользовательских  и  групповых ID между пользовательскими пространствами имён. В Linux 3.9
       добавлена требуемая поддержка инфраструктуры во многие неподдерживаемые  файловые  системы
       (Plan  9  (9P),  Andrew  File  System  (AFS), Ceph, CIFS, CODA, NFS и OCFS2). В Linux 3.12
       добавлена поддержка в последние основные файловые системы (XFS).

ПРИМЕРЫ

       The program below is designed to allow experimenting with  user  namespaces,  as  well  as
       other types of namespaces.  It creates namespaces as specified by command-line options and
       then executes a command inside those  namespaces.   The  comments  and  usage()   function
       inside the program provide a full explanation of the program.  The following shell session
       demonstrates its use.

       Сначала, посмотрим на окружение выполнения:

           $ uname -rs     # требуется Linux 3.8 или новее
           Linux 3.8.0
           $ id -u         # работа от непривилегированного пользователя
           1000
           $ id -g
           1000

       Теперь запустим новую оболочку в новых пользовательском (-U), монтирования (-m) и PID (-p)
       пространствах  имён  с пользовательским (-M) и групповым ID (-G)  1000, отображающимся в 0
       внутри пользовательского пространства имён:

           $ ./userns_child_exec -p -m -U -M '0 1000 1' -G '0 1000 1' bash

       У оболочки PID равен 1, так как это первый процесс в новом пространстве имён PID:

           bash$ echo $$
           1

       Смонтируем новую файловую систему  /proc  и  просмотрим  все  процессы,  видимые  в  новом
       пространстве  имён  PID;  убедимся,  что  оболочка  не видит ни одного процесса вне своего
       пространства имён PID:

           bash$ mount -t proc proc /proc
           bash$ ps ax
             PID TTY      STAT   TIME COMMAND
               1 pts/3    S      0:00 bash
              22 pts/3    R+     0:00 ps ax

       Внутри пользовательского пространства имён идентификаторы пользователя и  группы  оболочки
       равны 0, и она имеет полный набор разрешённых и эффективных мандатов:

           bash$ cat /proc/$$/status | egrep '^[UG]id'
           Uid: 0    0    0    0
           Gid: 0    0    0    0
           bash$ cat /proc/$$/status | egrep '^Cap(Prm|Inh|Eff)'
           CapInh:   0000000000000000
           CapPrm:   0000001fffffffff
           CapEff:   0000001fffffffff

   Исходный код программы

       /* userns_child_exec.c

          Лицензируется на условиях Универсальной общественной лицензии
          GNU версии 2 и новее

          Создаёт дочерний процесс, который запускает командную оболочку
          в новых пространствах имён; может выполнять отображение UID и GID,
          если они указаны при создании пользовательского пространства имён.
       */
       #define _GNU_SOURCE
       #include <err.h>
       #include <sched.h>
       #include <unistd.h>
       #include <stdint.h>
       #include <stdlib.h>
       #include <sys/wait.h>
       #include <signal.h>
       #include <fcntl.h>
       #include <stdio.h>
       #include <string.h>
       #include <limits.h>
       #include <errno.h>

       struct child_args {
           char **argv;        /* команда, выполняемая потомком с параметрами */
           int    pipe_fd[2];  /* канал для синхронизации родителя и потомка */
       };

       static int verbose;

       static void
       usage(char *pname)
       {
           fprintf(stderr, "Usage: %s [options] cmd [arg...]\n\n", pname);
           fprintf(stderr, "Create a child process that executes a shell "
                   "command in a new user namespace,\n"
                   "and possibly also other new namespace(s).\n\n");
           fprintf(stderr, "Options can be:\n\n");
       #define fpe(str) fprintf(stderr, "    %s", str);
           fpe("-i          New IPC namespace\n");
           fpe("-m          New mount namespace\n");
           fpe("-n          New network namespace\n");
           fpe("-p          New PID namespace\n");
           fpe("-u          New UTS namespace\n");
           fpe("-U          New user namespace\n");
           fpe("-M uid_map  Specify UID map for user namespace\n");
           fpe("-G gid_map  Specify GID map for user namespace\n");
           fpe("-z          Map user's UID and GID to 0 in user namespace\n");
           fpe("            (equivalent to: -M '0 <uid> 1' -G '0 <gid> 1')\n");
           fpe("-v          Display verbose messages\n");
           fpe("\n");
           fpe("If -z, -M, or -G is specified, -U is required.\n");
           fpe("It is not permitted to specify both -z and either -M or -G.\n");
           fpe("\n");
           fpe("Map strings for -M and -G consist of records of the form:\n");
           fpe("\n");
           fpe("    ID-inside-ns   ID-outside-ns   len\n");
           fpe("\n");
           fpe("A map string can contain multiple records, separated"
               " by commas;\n");
           fpe("the commas are replaced by newlines before writing"
               " to map files.\n");

           exit(EXIT_FAILURE);
       }

       /* Update the mapping file 'map_file', with the value provided in
          'mapping', a string that defines a UID or GID mapping. A UID or
          GID mapping consists of one or more newline-delimited records
          of the form:

              ID-внутри-ns    ID-снаружи-ns   длина

          Требовать от пользователя указывать строку с символами новой строки
          в командной строке неприемлемо. Поэтому мы позволим использовать
          для разделения записей запятые и заменим их символами новой строки
          перед записью строки в файл. */

       static void
       update_map(char *mapping, char *map_file)
       {
           int fd;
           size_t map_len;     /* Length of 'mapping' */

           /* Заменяем запятые на символы новой строки в строке отображения. */

           map_len = strlen(mapping);
           for (size_t j = 0; j < map_len; j++)
               if (mapping[j] == ',')
                   mapping[j] = '\n';

           fd = open(map_file, O_RDWR);
           if (fd == -1) {
               fprintf(stderr, "ОШИБКА: open %s: %s\n", map_file,
                       strerror(errno));
               exit(EXIT_FAILURE);
           }

           if (write(fd, mapping, map_len) != map_len) {
               fprintf(stderr, "ОШИБКА: write %s: %s\n", map_file,
                       strerror(errno));
               exit(EXIT_FAILURE);
           }

           close(fd);
       }

       /* Linux 3.19 made a change in the handling of setgroups(2) and the
          'gid_map' file to address a security issue.  The issue allowed
          *unprivileged* users to employ user namespaces in order to drop groups.
          The upshot of the 3.19 changes is that in order to update the
          'gid_maps' file, use of the setgroups() system call in this
          user namespace must first be disabled by writing "deny" to one of
          the /proc/PID/setgroups files for this namespace.  That is the
          purpose of the following function. */

       static void
       proc_setgroups_write(pid_t child_pid, char *str)
       {
           char setgroups_path[PATH_MAX];
           int fd;

           snprintf(setgroups_path, PATH_MAX, "/proc/%jd/setgroups",
                   (intmax_t) child_pid);

           fd = open(setgroups_path, O_RDWR);
           if (fd == -1) {

               /* We may be on a system that doesn't support
                  /proc/PID/setgroups. In that case, the file won't exist,
                  and the system won't impose the restrictions that Linux 3.19
                  added. That's fine: we don't need to do anything in order
                  to permit 'gid_map' to be updated.

                  Однако, если ошибка open() отличается от
                  ENOENT, сообщим об этом пользователю. */

               if (errno != ENOENT)
                   fprintf(stderr, "ERROR: open %s: %s\n", setgroups_path,
                       strerror(errno));
               return;
           }

           if (write(fd, str, strlen(str)) == -1)
               fprintf(stderr, "ОШИБКА: write %s: %s\n", setgroups_path,
                   strerror(errno));

           close(fd);
       }

       static int              /* Начальная функция клонированного потомка */
       childFunc(void *arg)
       {
           struct child_args *args = arg;
           char ch;

           /* Ждём пока родитель обновит отображения UID и GID.
              Смотрите комментарий в main(). Мы ждём конца файла в канале,
              который будет закрыт родительским процессом после обновления
              отображений. */

           close(args->pipe_fd[1]);    /* закрываем наш дескриптор для записи
                                          конца канала для того, чтобы мы
                                          увидели EOF, когда родитель закроет
                                          свой дескриптор */
           if (read(args->pipe_fd[0], &ch, 1) != 0) {
               fprintf(stderr,
                       "Ошибка в потомке: при чтении из канала получен != 0\n");
               exit(EXIT_FAILURE);
           }

           close(args->pipe_fd[0]);

           /* Запускаем командную оболочку. */

           printf("About to exec %s\n", args->argv[0]);
           execvp(args->argv[0], args->argv);
           err(EXIT_FAILURE, "execvp");
       }

       #define STACK_SIZE (1024 * 1024)

       static char child_stack[STACK_SIZE];    /* Space for child's stack */

       int
       main(int argc, char *argv[])
       {
           int flags, opt, map_zero;
           pid_t child_pid;
           struct child_args args;
           char *uid_map, *gid_map;
           const int MAP_BUF_SIZE = 100;
           char map_buf[MAP_BUF_SIZE];
           char map_path[PATH_MAX];

           /* Parse command-line options. The initial '+' character in
              the final getopt() argument prevents GNU-style permutation
              of command-line options. That's useful, since sometimes
              the 'command' to be executed by this program itself
              has command-line options. We don't want getopt() to treat
              those as options to this program. */

           flags = 0;
           verbose = 0;
           gid_map = NULL;
           uid_map = NULL;
           map_zero = 0;
           while ((opt = getopt(argc, argv, "+imnpuUM:G:zv")) != -1) {
               switch (opt) {
               case 'i': flags |= CLONE_NEWIPC;        break;
               case 'm': flags |= CLONE_NEWNS;         break;
               case 'n': flags |= CLONE_NEWNET;        break;
               case 'p': flags |= CLONE_NEWPID;        break;
               case 'u': flags |= CLONE_NEWUTS;        break;
               case 'v': verbose = 1;                  break;
               case 'z': map_zero = 1;                 break;
               case 'M': uid_map = optarg;             break;
               case 'G': gid_map = optarg;             break;
               case 'U': flags |= CLONE_NEWUSER;       break;
               default:  usage(argv[0]);
               }
           }

           /* -M или -G без -U не имеют смысла */

           if (((uid_map != NULL || gid_map != NULL || map_zero) &&
                       !(flags & CLONE_NEWUSER)) ||
                   (map_zero && (uid_map != NULL || gid_map != NULL)))
               usage(argv[0]);

           args.argv = &argv[optind];

           /* We use a pipe to synchronize the parent and child, in order to
              ensure that the parent sets the UID and GID maps before the child
              calls execve(). This ensures that the child maintains its
              capabilities during the execve() in the common case where we
              want to map the child's effective user ID to 0 in the new user
              namespace. Without this synchronization, the child would lose
              its capabilities if it performed an execve() with nonzero
              user IDs (see the capabilities(7) man page for details of the
              transformation of a process's capabilities during execve()). */

           if (pipe(args.pipe_fd) == -1)
               err(EXIT_FAILURE, "pipe");

           /* создаём потомка в новом пространстве имён */

           child_pid = clone(childFunc, child_stack + STACK_SIZE,
                             flags | SIGCHLD, &args);
           if (child_pid == -1)
               err(EXIT_FAILURE, "clone");

           /* предок попадает сюда. */

           if (verbose)
               printf("%s: PID потомка, созданного clone(): %jd\n",
                       argv[0], (intmax_t) child_pid);

           /* обновляем отображения UID и GID в потомке */

           if (uid_map != NULL || map_zero) {
               snprintf(map_path, PATH_MAX, "/proc/%jd/uid_map",
                       (intmax_t) child_pid);
               if (map_zero) {
                   snprintf(map_buf, MAP_BUF_SIZE, "0 %jd 1",
                           (intmax_t) getuid());
                   uid_map = map_buf;
               }
               update_map(uid_map, map_path);
           }

           if (gid_map != NULL || map_zero) {
               proc_setgroups_write(child_pid, "deny");

               snprintf(map_path, PATH_MAX, "/proc/%jd/gid_map",
                       (intmax_t) child_pid);
               if (map_zero) {
                   snprintf(map_buf, MAP_BUF_SIZE, "0 %ld 1",
                           (intmax_t) getgid());
                   gid_map = map_buf;
               }
               update_map(gid_map, map_path);
           }

           /* закрываем конец канала на стороне записи для сообщения потомку
              о том, что мы обновили отображения UID и GID */

           close(args.pipe_fd[1]);

           if (waitpid(child_pid, NULL, 0) == -1)      /* ждём потомка */
               err(EXIT_FAILURE, "waitpid");

           if (verbose)
               printf("%s: завершение\n", argv[0]);

           exit(EXIT_SUCCESS);
       }

СМ. ТАКЖЕ

       newgidmap(1), newuidmap(1), clone(2), ptrace(2), setns(2), unshare(2), proc(5), subgid(5),
       subuid(5),   capabilities(7),   cgroup_namespaces(7),    credentials(7),    namespaces(7),
       pid_namespaces(7)

       Файл             из            дерева            исходного            кода            ядра
       Documentation/admin-guide/namespaces/resource-control.rst.

ПЕРЕВОД

       Русский   перевод   этой    страницы    руководства    был    сделан    Azamat    Hackimov
       <azamat.hackimov@gmail.com>,    Dmitriy    Ovchinnikov    <dmitriyxt5@gmail.com>,   Dmitry
       Bolkhovskikh <d20052005@yandex.ru>, Katrin Kutepova <blackkatelv@gmail.com>,  Yuri  Kozlov
       <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

       Этот  перевод  является  бесплатной  документацией;  прочитайте  Стандартную  общественную
       лицензию GNU версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если  вы  обнаружите  ошибки  в  переводе этой страницы руководства, пожалуйста, отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.