[Перевод] Кунг-фу стиля Linux: делиться — это плохо

В детском саду вы узнали о том, что делиться — это хорошо. Но, если речь заходит о компьютерной безопасности, часто оказывается, что не всё так однозначно. Концепция пространств имён (namespaces) появилась в ядре Linux начиная с версии 2.6.24. Это случилось много лет назад, но использование пространств имён не стало массовым явлением, несмотря на то, что существуют инструменты для работы с ними. Разумеется, задумываться о пространствах имён нужно далеко не всегда. Но это одна из тех вещей, которые, если в них возникает необходимость, дают нам просто бесценные возможности. Если описать эти возможности в двух словах, то получится, что пространства имён позволяют предоставить процессу его собственные, приватные ресурсы, и, что важнее, запретить процессу доступ к ресурсам из других пространств имён.

2t6baq9pk4sbtknjknbfj2ucbf8.jpeg

На самом деле мы, работая в Linux, постоянно пользуемся этой концепцией. Каждый запускаемый нами процесс существует в среде, описываемой неким набором пространств имён. Почему я говорю тут о «наборе» пространств имён? Дело в том, что существуют пространства имён, используемые для управления различными ресурсами. Например, можно настроить особое сетевое пространство имён, которое позволит предоставить процессу его собственный набор сетевых ресурсов — таких, например, как таблицы маршрутизации и правила файрвола.

Поговорим о том, как в Linux организована работа с пространствами имён, и о том, что они скрывают.

Все переводы серии


Существуют следующие пространства имён:

  • Пространство имён файловой системы (mount). Сюда относятся ресурсы файловых систем, в частности, описание точек монтирования. Этими описаниями, доступными одному пространству имён файловой системы, можно поделиться с другими пространствами имён. Для того чтобы это сделать, пользователь должен явным образом выразить своё намерение.
  • Пространство имён UTS. Оно отвечает за управление такими вещами, как имя хоста и доменное имя.
  • Пространство имён IPC. Программа, с которой связано собственное пространство имён IPC, будет обладать собственной разделяемой памятью, собственными очередями сообщений, семафорами и другими объектами, отвечающими за межпроцессное взаимодействие.
  • Пространство имён для сетей (network). Процессы, находящиеся в сетевом пространстве имён, будут обладать собственными сетевыми ресурсами, такими, как стеки сетевых протоколов и настройки системных сущностей, имеющих отношение к сетям.
  • Пространство имён PID. Процессы, входящие в состав пространства имён PID, не видят других процессов, находящихся за пределами этого пространства.
  • Пространство имён cgroup. Это — пространство имён, которое даёт виртуализированное представление механизмов, используемых для управления процессором.
  • Пространства имён пользователей (user). Эти пространства имён позволяют изолировать отдельных пользователей, группы пользователей и другие подобные ресурсы.


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

Эксперименты в командной оболочке


Если вы хотите поэкспериментировать с пространствами имён с использованием командной оболочки — можете воспользоваться командой unshare. Её имя может показаться странным, но стоит обратить внимание на то, что она названа именно так из-за того, что новый процесс обычно получает доступ к пространствам имён, которыми делится с ним его родительский процесс. Команда unshare позволяет создавать новые пространства имён.

Одной из ключевых возможностей этой команды (или её странностью) является тот факт, что она по умолчанию запускает программу и при этом создаёт новые пространства имён. Но эту программу она с этими пространствами имён не связывает. Они назначаются дочерним процессам, создаваемым этой программой. При вызове unshare можно воспользоваться опцией --fork. Это приведёт к тому, что то, как она сработает, будет ближе к тому, чего от неё можно было бы ожидать.

Например — откроем новый экземпляр командной оболочки в её собственном частном пространстве:

sudo unshare --pid --fork --mount-proc /bin/bash
ps alx


Если попробовать эту команду, не создавая при этом отдельного пространства имён, и поинтересоваться списком процессов, этот список будет очень длинным. А такой же список, выведенный внутри нового пространства имён, выглядит не таким уж и большим.

F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0       1       0  20   0  10820  4376 -      S    pts/6      0:00 /bin/bash
0     0       9       1  20   0  12048  1168 -      R+   pts/6      0:00 ps alx


Тут стоит немного поразмыслить о том, как работают разные утилиты. Например, ps читает данные из /proc. Поэтому без --mount-proc, она, как обычно, выведет список всех основных процессов (попробуйте это сделать). С ними нельзя будет взаимодействовать, но, так как у нас есть возможность чтения данных из /proc, нам виден их список. Флаг --mount-proc — это сокращённый вариант описания последовательности действий, когда сначала используют --mount (для получения нового пространства имён файловой системы), а затем монтируют файловую систему proc.

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

Если добавить к большей части аргументов (например — это --pid или --mount) имя файла — можно создавать постоянные пространства имён, которые можно расшаривать между различными процессами. Ещё можно использовать виртуальные Ethernet-адаптеры (виртуальные устройства veth) или сетевой мост для того, чтобы давать доступ к сетям из одного пространства имён другим пространствам имён.

Пространства имён файловой системы и другие опции


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

Тут можно отметить одну деталь. Заключается она в том, что, так как пространства имён изолированы, обычный пользователь может иметь квази-права суперпользователя в новых пространствах имён. Сделать это позволяет опция --map-root-user. Она, кроме того, включает опцию, запрещающую пользователям вызов setgroups. Это могло бы позволить им получить повышенные разрешения.

Тут, конечно, ещё много всего. Если у вас установлен пакет util-linux — обратитесь за подробностями к man-странице unshare. Если вы хотите воспользоваться этими возможностями в некоей программе, что, пожалуй, легче себе представить, чем их непосредственное использование, можете обратиться к системному вызову unshare. Подробности об этом можно найти в man 2 unshare. Обратите внимание на то, что при использовании системных вызовов, в вашем распоряжении окажется даже больше власти, чем при применении обычных команд. Например, можно отсоединить файловую систему. Это близко связано с системным вызовом clone, который представляет собой нечто вроде супер-версии fork.

Может, вам покажется интересным то, что все данные пространства имён для процесса выводятся в /proc. Например — попробуйте такую команду:

sudo ls -l /proc/$$/ns/*


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

lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/net -> 'net:[4026531992]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/time -> 'time:[4026531834]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/user -> 'user:[4026531837]'
lrwxrwxrwx 1 alw alw 0 Dec 8 07:29 /proc/2182630/ns/uts -> 'uts:[4026531838]'


Это — один из «линуксизмов», которые иногда выглядят таинственно, но могут оказаться чрезвычайно полезными тогда, когда они кому-то понадобятся. Даже если прямо сейчас вам всё это и не нужно, в этом стоит разобраться. Это, например, может помочь вам решить какую-нибудь вставшую перед вами программистскую проблему. Конечно, вы можете запустить свою программу в её собственной виртуальной машине. Но это будет образец тяжеловесного решения, так как ту же задачу можно решить, проще, пользуясь аккуратными инструментами, позволяющими изолировать от внешнего мира то, что нужно. И сделать это можно не только вручную, но и из shell-скрипта.

Пользуетесь ли вы пространствами имён Linux?

image-loader.svg

© Habrahabr.ru