Пространство имён (Linux)
Пространство имён (от англ. namespaces) — функция ядра Linux, позволяющая изолировать и виртуализировать глобальные системные ресурсы множества процессов. Примеры ресурсов, которые можно виртуализировать: идентификаторы процессов, имена узлов, идентификаторы пользователей, доступ к сетям, межпроцессное взаимодействие и файловые системы. Одной из основных целей поддержки пространств имён (наряду с контрольными группами) является реализация контейнеров — инструмента для виртуализации на уровне операционной системы, обеспечивающего изоляцию групп процессов и связанных с ними ресурсов от других.
История
Идеи, лежащие в основе механизма пространств имён, исходят из ранних операционных систем. В Unix в 1979 году был добавлен системный вызов chroot()
(«смена корня») с целью обеспечить изоляцию части файловой системы и предоставить «площадку для тестирования», отделённую от основной системы[1].
Пространства имён появились в 2002 году в версии ядра 2.4.19[2]. Дополнительные пространства имён были добавлены в 2006 году и продолжали добавляться в последующих выпусках. Достаточная функциональность для полной изоляции и безопасной работы контейнеров была завершена в ядре версии 3.8 с введением пространств имён пользователей[3], а с поддержкой изоляции пространств имён для контрольных групп в версии 4.6 обеспечены максимальные возможности по изоляции:
Пространство имён | Версия ядра | Год |
---|---|---|
Файловая система (Mount) | 2.4.19 | 2002 |
Изоляция имени узла (UTS) | 2.6.19 | 2006 |
ID процессов (PID) | 2.6.24 | 2008 |
Сети (Network) (net) | 2.6.29 | 2009 |
Межпроцессное взаимодействие (IPC) | 2.6.30 | 2009 |
Пользовательские ID (User) | 3.8 | 2013 |
Изоляция контрольных групп | 4.6 | 2016 |
Виды пространства имён
Linux-система при старте инициализирует один экземпляр каждого типа пространства имён, кроме пространства имён файловой системы. После инициализации можно создать или объединить дополнительные пространства имён[4].
Все пространства имён поддерживают вложенность, то есть между ними можно установить связь «родитель — потомок»[5]. Таким образом некоторые пространства наследуют все свойства от своего родительского пространства имён. Однако это верно не для всех пространств.
Функциональные возможности пространства имён одинаковы для всех типов: каждый процесс связан с пространством имён и может видеть или использовать только ресурсы, связанные с этим пространством имён, и, где это применимо, — с его потомками[4]. Таким образом, каждый процесс (или его группа) может иметь уникальное представление о ресурсе. Изолированный ресурс зависит от типа пространства имён, созданного для данной группы процессов.
Файловая система (Mount)
Пространство имён файловой системы — это независимое дерево файловой системы, ассоциированное с определённой группой процессов.
Каждое пространство имён предоставляет уникальный вид файловой системы для всех процессов, принадлежащих этому пространству[2].
При создании новых пространств можно установить флаг для копирования списка точек монтирования из родительского пространства. Однако последующие операции по монтированию и размонтированию в одном пространстве никак не сказываются на других пространствах (в том числе — и на родительском, и на потомке). Но между пространствами можно установить связь «ведущий — ведомый», и тогда все действия, связанные с монтированием, в пространстве ведущего распространяются и на пространства, помеченные как ведомые. Обратные операции, то есть операции в пространстве ведомого, никак не влияют на пространство ведущего. Такая возможность позволяет сразу монтировать новое устройство в несколько пространств имён файловой системы вместо его монтирования в каждом отдельном пространстве[2].
Пространство имён файловой системы было первым типом пространств имён, выполненных в версии Linux 2.4.19[2] в 2002 году.
UTS
Пространство имён UTS (Unix Time Sharing) используется для изоляции двух конкретных элементов системы, относящихся к системному вызову uname()
[6].
Система характеризуется системным вызовом uname(). uname()
возвращает структуру utsname
, состоящую из 6 строк, описывающих текущую систему: sysname[]
, nodename[]
, release[]
, version[]
, machine[]
, domainname[]
. При этом из них только два элемента изменяются во время выполнения, nodename[]
и domainname[]
. nodename[]
это имя хоста системы, а domainname[]
это доменное имя NIS. Пространство имён UTS изолирует эти два системных идентификатора nodename[]
и domainname[]
. В контейнеризации функция пространства имён UTS позволяет каждому контейнеру иметь свое имя хоста и имя домена.
Для существования нескольких экземпляров пространств имён UTS происходит выделение новых экземпляров структуры utsname
в ядре для каждого экземпляра такого пространства и изменение системных вызовов, которые изменяют значения пространства, для поиска подходящего экземпляра структуры utsname
в качестве текущего.
Пространство имён UTS впервые появилось сборке ядра Linux 2.6.19[2].
ID процессов (PID)
Пространство имён PID изолирует пространство ID процессов, это означает, что процессы в различных пространствах могут иметь одинаковые ID[7]. Однако в пространстве имён хоста все процессы имеют уникальные идентификаторы, таким образом необходимо разделять идентификатор внутри определённого пространства и снаружи этого пространства, то есть в хостовой машине.
В новом пространстве имён первый процесс является инициализирующим или init-процессом для этого пространства и имеет PID 1. При завершении init-процесса ядро завершает все процессы, принадлежащие одному пространству через сигнал SIGKILL.
Пространство имён ID процессов впервые появилось в версии ядра 2.6.24. Однако оно было отмечено как «экспериментальное», с тем чтобы предотвратить его широкое развертывание дистрибьюторами, в то время как некоторые остающиеся вопросы решаются[8].
Сети (Network)
Пространство имён для сетей предоставляет изоляцию систем ресурсов, связанных с сетями: сетевое оборудование, стеки протоколов IPv4 и IPv6, таблицы IP-маршрутизации, файрволы, номера портов (сокеты) и другие[9].
Физические сетевые устройства могут принадлежать только одному пространству. При этом каждое пространство имён может иметь одно или несколько виртуальных устройств, и таким образом для обеспечения доступа во внешнюю сеть между физическим и виртуальным устройством из разных пространств создаётся мост. То есть по сути туннель между разными пространствами имён сети.
Когда последний процесс в пространстве завершается, то физическое сетевое устройство возвращается не в родительское пространство, а в пространство хостовой машины.
Впервые появилось в версии ядра 2.6.24. Однако было полностью закончено только в версии 2.6.29[10].
Межпроцессное взаимодействие (IPC)
System V IPC включает в себя семафоры, разделяемую память и очереди сообщений[11]. Каждый ресурс межпроцессного взаимодействия должен иметь свой уникальный идентификатор (ID)[12]. Это позволяет процессам, взаимодействующим между собой, обращаться к общему ресурсу. И для изоляции таких ресурсов было создано пространство имён IPC.
Каждое пространство имён IPC имеет свой собственный набор идентификаторов System V IPC и свою собственную систему очередей сообщений POSIX[9]. Объекты, созданные в этом пространстве имён, видны всем процессам, состоящим в этом пространстве, и не видны всем остальным процессам в других пространствах имён[9].
Новое пространство имён создаётся без каких-либо объектов, вместо копирования объектов от своего родительского пространства. Когда пространство имён IPC разрушается (то есть когда последний процесс, состоящий в этом пространстве, завершается), все IPC-объекты в этом пространстве автоматически уничтожаются.
Пространство имён IPC впервые было представлено в версии ядра 2.6.19[2] для семафоров и разделяемой памяти. В версии 2.6.30[9] также были добавлены очереди сообщений POSIX.
Пользовательские ID (User)
Пространства имён пользователей изолируют ID пользователей и групп, корневой каталог, ключи и capabilities. Идентификаторы пользователя и группы процесса могут отличаться внутри и вне пространства имён пользователей. В частности, процесс может иметь непривилегированное ID пользователя вне пространства имён пользователей, пока в то же время иметь ID root внутри пространства, то есть процесс имеет полные привилегии для операций внутри пространства имён[3].
Пространства имён могу быть вложенными, это означает, что каждое пространство имён пользователя (за исключением инициализирующего пространства) имеет родительское пространство и может иметь ноль или несколько дочерних пространств. Ядро накладывает лимит в 32 вложенных уровня пространств имён пользователей начиная с версии 3.11[13].
Пространство имён пользователей впервые было представлено в версии ядра 3.8[2].
Контрольные группы (Cgroup)
Пространство имён cgroup скрывает, к какой контрольной группе принадлежит процесс. В таком пространстве имён процесс, проверяя, к какой контрольной группе он относится, увидит путь относительно контрольной группы, установленной при создании. Таким образом, процесс считает, что принадлежит к корневой контрольной группе, а полный путь к контрольной группе оказывается скрыт. Пространство имён cgroup было представлено в версии ядра 4.6 в марте 2016[14][15].
Время (Time)
Пространство имён времени позволяет процессам видеть различное системное время подобно тому, как пространство имён UTS изолирует имя хоста. Пространство имён времени было предложено в 2018 и стало доступно в версии ядра 5.6 (март 2020)[16].
Применение в контейнерах
Пространство имён даёт процессам, запущенным в контейнерах, иллюзию, что они имеют свои собственные ресурсы. Основная цель изоляции процессов состоит в предотвращении вмешательства процессов одного контейнера в работу других контейнеров, а также работу хостовой машины. На данный момент существует несколько технологий контейнеризации, основными же являются LXC и Docker. И в основе этих технологиях лежат пространства имён и они имеют одинаковый принцип работы[17][18][19].
Изоляция процессов
Технология контейнеризации обеспечивает изоляцию процессов путём переноса процессов, запущенных в контейнере, в собственное пространство имён и ограничения прав и видимости процессов, запущенных в других контейнерах и на самой хостовой машине. Этот механизм работает при поддержке пространства имён PID, которое изолирует пространство идентификаторов процесса контейнера от пространства хоста. Поскольку пространство имён PID иерархичное, то процесс может видеть только процессы в своём собственном пространстве имён, либо в его «дочернем» пространстве имён. Вследствие этого, после создания и присвоения пространства имён контейнеру, хостовая машина может видеть и взаимодействовать с пространством идентификаторов процесса контейнера, но процесс внутри контейнера не может видеть и что-либо делать с пространством хоста или другого контейнера.
Изоляция файловой системы
Для достижения защищённости контейнеров и хостовой машины от нелегитимных процессов и модификаций с файловой системой необходима изоляция файловых систем.
Технология контейнеризации использует пространство имён файловой системы для изоляции файловой системы, иерархично связанной с другими контейнерами. Это пространство предоставляет процессам каждого контейнера различное представление дерева файловой системы и ограничивает все события монтирования, происходящие внутри контейнера.
Изоляция IPC
Процессы, запущенные в контейнерах, должны быть ограничены так, чтобы они могли взаимодействовать только через определённый набор ресурсов IPC и им было запрещено вмешиваться в работу других контейнеров и хост-машины.
Технология контейнеризации достигает изоляции IPC использованием пространства имён IPС. Процесс в пространстве имён IPC не может писать или читать IPC-ресурсы, принадлежащие другому пространству имён. Технология контейнеризации присваивает свое пространство имён IPC каждому контейнеру, таким образом, не давая процессам в контейнере вмешиваться в другие контейнеры.
Изоляция сетей
Изоляция сети важна для предотвращения сетевых атак, таких как «человек посередине». Контейнеры должны быть настроены таким образом, чтобы они не могли подслушивать или управлять сетевым трафиком других контейнеров или хоста.
Для каждого контейнера технология контейнеризации создаёт независимый сетевой стек при помощи пространства имён сети. Таким образом, каждый контейнер имеет свои собственные IP-адреса, таблицы IP-маршрутизации, сетевые устройства и так далее. Это позволяет контейнерам взаимодействовать друг с другом через свои соответствующие сетевые интерфейсы, что аналогично тому, как они взаимодействуют с внешними хостами.
Изоляция пользователей
Только с появлением пространства имён пользователей стала возможна полная изоляция контейнеров от хостовой машины. Поскольку до появления этого пространства, пользователь имел ID 0 в контейнере, то есть был пользователем root в этом контейнере, и при этом же имел такой же ID внутри хостовой машины, что создавал большую угрозу для всей системы. И только благодаря пространству имён пользователей удалось разделить эти ID, то есть пользователь остается привилегированным внутри контейнера и при этом непривилегированным внутри хостовой машины.
Изоляция UTS
Благодаря пространству имён UTS каждый контейнер может иметь свое собственное доменное имя NIS domainname[]
и имя контейнера nodename[]
. Это является важным фактором для многих приложений, веб-сервисов, журналирования и других возможностей.
Безопасность
Хотя пространство имён IPC покрывает большинство методов межпроцессных взаимодействий, существуют исключения. Таким исключением является Transparent Inter-Process Communication[20] — это сетевой протокол, созданный для взаимодействия приложений в кластерных системах. Использование такого метода взаимодействия нарушает изоляцию IPC между контейнерами.
Список некоторых известных уязвимостей, связанных с пространствами имён:
- CVE-2013-1956[21]: ядро Linux не проверяет наличие каталога chroot, отличающегося от корневого каталога пространства имён. Это уязвимость позволяет локальным пользователям обходить предполагаемые ограничения файловой системы с помощью сконструированного системного вызова.
- CVE-2013-1957[22]: уязвимость позволяет локальным пользователям обходить предназначенное только для чтения свойство файловой системы, используя отдельное пространство имён файловой системы.
- CVE-2013-1959[23]: уязвимость позволяет локальным пользователям получать права, открывая файл в рамках непривилегированного процесса, а затем изменяя файл в рамках привилегированного процесса. Известный экспойт.
- CVE-2013-1858[24]: уязвимость позволяет локальным пользователям получать права путем вызова chroot и использования совместного доступа к каталогу / между родительским процессом и процессом-потомком.
- CVE-2014-5206[25]: уязвимость позволяет локальным пользователям обойти ограничение «только для чтения», и обойти механизмы защиты «песочницы» с помощью команды
mount -o remount
в пространстве имён пользователя.
Примечания
- ↑ jail, section 9. (неопр.) docs.freebsd.org. Дата обращения: 11 декабря 2017. Архивировано 5 января 2017 года.
- ↑ 1 2 3 4 5 6 7 Namespaces in operation, part 1: namespaces overview [LWN.net] (неопр.). lwn.net. Дата обращения: 8 декабря 2017. Архивировано 1 декабря 2017 года.
- ↑ 1 2 User namespaces progress [LWN.net] (неопр.). lwn.net. Дата обращения: 11 декабря 2017. Архивировано 12 декабря 2017 года.
- ↑ 1 2 Advanced Topics - Linux Kernel Networking: Implementation and Theory (2014) (англ.). apprize.info. Дата обращения: 11 декабря 2017. Архивировано 12 декабря 2017 года.
- ↑ Separation Anxiety: A Tutorial for Isolating Your System with Linux Namespaces (неопр.). Toptal Engineering Blog. Дата обращения: 11 декабря 2017.
- ↑ uname(2) - Linux manual page (неопр.). man7.org. Дата обращения: 8 декабря 2017. Архивировано 8 декабря 2017 года.
- ↑ pid_namespaces(7) - Linux manual page (неопр.). man7.org. Дата обращения: 5 декабря 2017. Архивировано 4 декабря 2017 года.
- ↑ PID namespaces in the 2.6.24 kernel [LWN.net] (неопр.). lwn.net. Дата обращения: 8 декабря 2017. Архивировано 8 декабря 2017 года.
- ↑ 1 2 3 4 namespaces(7) - Linux manual page (неопр.). man7.org. Дата обращения: 8 декабря 2017. Архивировано 6 декабря 2017 года.
- ↑ Network namespaces [LWN.net] (неопр.). lwn.net. Дата обращения: 8 декабря 2017. Архивировано 13 июля 2017 года.
- ↑ svipc(7) - Linux manual page (неопр.). man7.org. Дата обращения: 17 декабря 2017. Архивировано 30 декабря 2017 года.
- ↑ Alexey V. Pautov. Энциклопедия программиста Linux. 6 Межпроцессовые коммуникации LINUX (рус.). rus-linux.net. Дата обращения: 17 декабря 2017. Архивировано 23 декабря 2017 года.
- ↑ user_namespaces(7) - Linux manual page (неопр.). man7.org. Дата обращения: 11 декабря 2017. Архивировано 7 декабря 2017 года.
- ↑ Heo, Tejun (2016-03-18). "[GIT PULL] cgroup namespace support for v4.6-rc1". lkml (Mailing list). Архивировано 5 июня 2024. Дата обращения: 5 августа 2024.
- ↑ Torvalds, Linus (2016-03-26). "Linux 4.6-rc1". lkml (Mailing list). Архивировано 5 июня 2024. Дата обращения: 5 августа 2024.
- ↑ It's Finally Time: The Time Namespace Support Has Been Added To The Linux 5.6 Kernel - Phoronix (неопр.). www.phoronix.com. Дата обращения: 30 марта 2020. Архивировано 18 марта 2020 года.
- ↑ Linux Containers - LXC - Introduction (англ.). linuxcontainers.org. Дата обращения: 8 декабря 2017. Архивировано 18 ноября 2017 года.
- ↑ Docker security (англ.). Docker Documentation. Дата обращения: 8 декабря 2017. Архивировано 2 сентября 2017 года.
- ↑ Elena Reshetova, Janne Karhunen, Thomas Nyman, N. Asokan. Security of OS-level virtualization technologies: Technical report // arXiv:1407.4245 [cs]. — 2014-07-16. Архивировано 9 октября 2016 года.
- ↑ TIPC Home Page (неопр.). tipc.sourceforge.net. Дата обращения: 11 декабря 2017. Архивировано 5 мая 2021 года.
- ↑ NVD - CVE-2013-1956 (неопр.). nvd.nist.gov. Дата обращения: 11 декабря 2017. Архивировано 11 декабря 2017 года.
- ↑ CVE-2013-1957 : The clone_mnt function in fs/namespace.c in the Linux kernel before 3.8.6 does not properly restrict changes to the MNT_ (неопр.). www.cvedetails.com. Дата обращения: 11 декабря 2017. Архивировано 11 декабря 2017 года.
- ↑ [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1959 CVE - CVE-2013-1959] (англ.). cve.mitre.org. Дата обращения: 11 декабря 2017. Архивировано 11 декабря 2017 года.
- ↑ NVD - CVE-2013-1858 (неопр.). nvd.nist.gov. Дата обращения: 11 декабря 2017. Архивировано 12 декабря 2017 года.
- ↑ CVE-2014-5206 : The do_remount function in fs/namespace.c in the Linux kernel through 3.16.1 does not maintain the MNT_LOCK_READONLY bit (неопр.). www.cvedetails.com. Дата обращения: 11 декабря 2017. Архивировано 11 декабря 2017 года.
Ссылки
- Namespaces in operation, part 1: namespaces overview
- Network namespaces
- Multiple Instances of the Global Linux Namespaces
- NAMESPACES(7)
- MOUNT_NAMESPACES(7)
- PID_NAMESPACES(7)
- USER_NAMESPACES(7)
- Использование пространств имён команды mount
- Virtual Servers and Checkpoint/Restart in Mainstream Linux
- Understanding and Hardening Linux Containers
- Security of OS-level virtualization technologies