ОБЗОР
#include <sched.h>
int unshare(int flags);
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
unshare():
-
- Начиная с glibc 2.14:
- _GNU_SOURCE
-
До glibc 2.14:
_BSD_SOURCE || _SVID_SOURCE
/* также достаточно _GNU_SOURCE */
ОПИСАНИЕ
Вызов unshare() позволяет процессу (или потоку) отделить части своего контекста выполнения, которые используются совместно с другими процессами (или потоками). Часть контекста выполнения, например пространство имён монтирования, неявно делается общей при создании нового процесса с помощью fork(2) или vfork(2), в то время как другие части, такие как виртуальная память, могут стать общими по явному запросу при создании процесса или потока с помощью clone(2).Основное предназначение unshare() --- позволить процессу контролировать свой общий контекст выполнения без создания нового процесса.
Значение аргумента flags представляет собой битовую маску, в которой указывается какие части контекста выполнения должны перестать быть общими. Значение составляется из нескольких следующих констант (через OR):
- CLONE_FILES
- Обратный эффект флагу CLONE_FILES для clone(2). Отделяет таблицу файловых дескрипторов таким образом, что вызывающий процесс больше не имеет общих файловых дескрипторов с другими процессами.
- CLONE_FS
- Обратный эффект флагу CLONE_FS для clone(2). Отделяет атрибуты файловой системы таким образом, что вызывающий процесс больше не имеет общих атрибутов корневого каталога (chroot(2)), текущего каталога (chdir(2)) и umask (umask(2)) с другими процессами.
- CLONE_NEWIPC (начиная с Linux 2.6.19)
- Этот флаг имеет действие подобное флагу CLONE_NEWIPC для clone(2). Отделяет пространство имён IPC таким образом, что вызывающий процесс будет иметь свою личную копию пространства имён IPC, неиспользуемую другими процессами. Задание данного флага автоматически устанавливает флаг CLONE_SYSVSEM. Для использования CLONE_NEWIPC требуется мандат CAP_SYS_ADMIN.
- CLONE_NEWNET (начиная с Linux 2.6.24)
- Этот флаг имеет действие подобное флагу CLONE_NEWNET для clone(2). Отделяет сетевое пространство имён таким образом, что вызывающий процесс будет иметь свою личную копию сетевого пространства имён, неиспользуемую другими процессами. Для использования CLONE_NEWNET требуется мандат CAP_SYS_ADMIN.
- CLONE_NEWNS
- Этот флаг имеет действие подобное флагу CLONE_NEWNS для clone(2). Отделяет пространство имён монтирования таким образом, что вызывающий процесс будет иметь свою личную копию данного пространства имён, неиспользуемую другими процессами. Задание данного флага автоматически устанавливает флаг CLONE_FS. Для использования CLONE_NEWNS требуется мандат CAP_SYS_ADMIN.
- CLONE_NEWPID (начиная с Linux 3.8)
- Данный флаг позволяет то же что и CLONE_NEWPID у clone(2). Выполняется отключение от пространства имён PID; вызывающий процесс создаёт новое пространство имён PID для своих потомков, которые до этого не были объединены с существующим процессом. Вызывающий процесс не перемещается в новое пространство имён. Первый потомок, созданный вызывающим процессом, будет иметь ID процесса 1 и считаться init(1) в новом пространстве имён. Также флаг CLONE_NEWPID автоматически подразумевает CLONE_THREAD. Для использования CLONE_NEWPID требуется мандат CAP_SYS_ADMIN. Подробней смотрите pid_namespaces(7).
- CLONE_NEWUSER (начиная с Linux 3.8)
- Данный флаг позволяет то же что и CLONE_NEWUSER у clone(2). Выполняется отключение от пользовательского пространства имён; вызывающий процесс перемещается в новое пользовательское пространство имён, которое до этого не был общим для существующего процесса. Как потомок процесса, созданный clone(2) с флагом CLONE_NEWUSER, вызывающий получает полный набор мандатов в новом пользовательском пространстве имён.
-
Для CLONE_NEWUSER требуется, чтобы вызывающий процесс не имел нитей;
указание CLONE_NEWUSER автоматически подразумевает
CLONE_THREAD. Начиная с Linux 3.9, CLONE_NEWUSER также автоматически
подразумевает CLONE_FS. Для CLONE_NEWUSER требуется, чтобы ID
пользователя и группы вызывающего процесса отображались в ID пользователя и
группы в пользовательском пространстве имён вызывающего процесса на момент
вызова.
Дополнительную информацию о пространствах имён пользователя смотрите в user_namespaces(7).
- CLONE_NEWUTS (начиная с Linux 2.6.19)
- Этот флаг имеет действие подобное флагу CLONE_NEWUTS для clone(2). Отделяет пространство имён UTS IPC таким образом, что вызывающий процесс будет иметь свою личную копию пространства имён UTS, неиспользуемую другими процессами. Для использования CLONE_NEWUTS требуется мандат CAP_SYS_ADMIN.
- CLONE_SYSVSEM (начиная с Linux 2.6.26)
- С данным флагом выполняется обратное действие clone(2) с флагом CLONE_SYSVSEM. Выполняется отмена изменения значений семафоров System V (semadj) таким образом, что вызывающий процесс получает новый пустой список semadj, который не является общим ни с одним другим процессом. Если это последний процесс, который ссылается на текущий список semadj процесса, то изменения (adjustments) в этом списке применяются к соответствующим семафорам как описано в semop(2).
Также в flags могут быть указаны флаги CLONE_THREAD, CLONE_SIGHAND и CLONE_VM, если вызывающий состоит из одной нити (т. е., он не делит своё адресное пространство с другим процессом или нитью). Иначе данные флаги не работают (также заметим, что указание CLONE_THREAD автоматически подразумевает CLONE_VM, а указание CLONE_VM автоматически подразумевает CLONE_SIGHAND). Если процесс состоит из нескольких нитей, то использование данных флагов приведёт к ошибке.
Если значение flags равно нулю, то unshare() ничего не делает, то есть в контексте выполнения вызывающего процесса ничего не изменяется.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. При ошибке возвращается -1, а errno присваивается значение ошибки.ОШИБКИ
- EINVAL
- В значении flags установлен недопустимый бит.
- EINVAL
- В flags указан CLONE_THREAD, CLONE_SIGHAND или CLONE_VM, а вызывающий состоит из нескольких нитей.
- ENOMEM
- Не удалось выделить достаточно памяти для копирования части контекста вызывающего, которая должна быть отделена.
- EPERM
- Вызывающий процесс не имеет требуемых привилегий для этой операции.
- EPERM
- Флаг CLONE_NEWUSER указан в flags, но эффективный пользовательский ID или эффективный ID группы вызывающего не отображён в родительское пространство имён (смотрите user_namespaces(7)).
- EPERM (начиная с Linux 3.9)
- В flags был указан флаг CLONE_NEWUSER и вызывающий выполняется в окружении chroot (т. е. корневой каталог вызывающего не совпадает с корневым каталогом пространства имён монтирования, в котором он находится).
- EUSERS (начиная с Linux 3.11)
- Флаг CLONE_NEWUSER указан в flags, и вызов привёл бы к превышению ограничения на количество вложенных пользовательских пространств имён. Смотрите user_namespaces(7).
ВЕРСИИ
Системный вызов unshare() был добавлен в ядро Linux версии 2.6.16.СООТВЕТСТВИЕ СТАНДАРТАМ
Системный вызов unshare() есть только в Linux.ЗАМЕЧАНИЯ
Не все атрибуты процесса, которые могут использоваться совместно при создании нового процесса с помощью clone(2), могут быть отделены с помощью unshare(). В частности, начиная с ядра 3.8 в unshare() не реализована поддержка флагов, которые были имели обратное действие CLONE_SIGHAND, CLONE_THREAD или CLONE_VM. Эти возможности могут быть добавлены позднее, если потребуется.ПРИМЕР
Программа, представленная далее, предоставляет простую реализацию команды unshare(1), которая отключает использование одного или более пространств имён и выполняет команду, переданную в аргументах командной строки. Вот пример использования этой программы; запускается оболочка в новом пространстве имён монтирования и проверяется, что первоначальная оболочка и новая оболочка находятся в разных пространствах имён монтирования:$ readlink /proc/$$/ns/mnt mnt:[4026531840] $ sudo ./unshare -m /bin/bash [sudo] password for cecilia: # readlink /proc/$$/ns/mnt mnt:[4026532325]
Различающийся вывод двух команд readlink(1) показывает, что две оболочки находятся в разных пространствах имён монтирования.
Исходный код программы
/* unshare.c Простая реализация команды unshare(1): отключение от пространств имён и выполнение команды. */ #define _GNU_SOURCE #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> /* Простая функция обработки ошибок: выводит сообщение об ошибке согласно значению в «errno» и завершает вызвавший процесс */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void usage(char *pname) { fprintf(stderr, "Использование: %s [параметры] программа [аргументы…]\n", pname); fprintf(stderr, "Параметры:\n"); fprintf(stderr, " -i отключиться от пространства имён IPC\n"); fprintf(stderr, " -m отключиться от пространства имён монтирования\n"); fprintf(stderr, " -n отключиться от сетевого пространства имён\n"); fprintf(stderr, " -p отключиться от пространства имён PID\n"); fprintf(stderr, " -u отключиться от пространства имён UTS\n"); fprintf(stderr, " -U отключиться от пользовательского пространства имён\n"); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int flags, opt; flags = 0; while ((opt = getopt(argc, argv, "imnpuU")) != -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 'U': flags |= CLONE_NEWUSER; break; default: usage(argv[0]); } } if (optind >= argc) usage(argv[0]); if (unshare(flags) == -1) errExit("unshare"); execvp(argv[optind], &argv[optind]); errExit("execvp"); }