ИМЯ
unshare -
отделяет
части
процесса
контекста
выполнения
ОБЗОР
#define _GNU_SOURCE
#include <sched.h>
int unshare(int flags);
ОПИСАНИЕ
Вызов 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_NEWCGROUP
(начиная с Linux
4.6)
- Этот флаг
имеет
действие
подобное
флагу CLONE_NEWCGROUP
для clone(2).
Отделяет
пространство
имён cgroup. Для
использования
CLONE_NEWCGROUP
требуется
мандат
CAP_SYS_ADMIN.
- 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.
Дополнительная
информация
доступна в
mount_namespaces(7).
- 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, а
вызывающий
состоит из
нескольких
нитей.
- EINVAL
- Указан
флаг CLONE_NEWIPC в
flags, но ядро
собрано
без
параметров
CONFIG_SYSVIPC и CONFIG_IPC_NS.
- EINVAL
- Указан
флаг CLONE_NEWNET в
flags, но ядро
собрано
без
параметра
CONFIG_NET_NS.
- EINVAL
- Указан
флаг CLONE_NEWPID в
flags, но ядро
собрано
без
параметра
CONFIG_PID_NS.
- EINVAL
- Указан
флаг CLONE_NEWUSER в
flags, но ядро
собрано
без
параметра
CONFIG_USER_NS.
- EINVAL
- Указан
флаг CLONE_NEWUTS в
flags, но ядро
собрано
без
параметра
CONFIG_UTS_NS.
- EINVAL
- Указан
флаг CLONE_NEWPID в
flags, но
процесс
был ранее
вызван unshare() с
флагом CLONE_NEWPID.
- ENOMEM
- Не удалось
выделить
достаточно
памяти для
копирования
части
контекста
вызывающего,
которая
должна
быть
отделена.
- ENOSPC
(начиная с Linux
3.7)
- В флагах
указан CLONE_NEWPID,
но вызов
привёл бы к
превышению
ограничения
на
количество
вложенных
имён PID;
смотрите
pid_namespaces(7).
- ENOSPC
(начиная с Linux
4.9; до этого
EUSERS)
- Флаг CLONE_NEWUSER
указан в flags,
и вызов
привёл бы к
превышению
ограничения
на
количество
вложенных
пользовательских
пространств
имён.
Смотрите
user_namespaces(7).
- В этом
случае в Linux 3.11
по Linux 4.8
возвращалась
ошибка EUSERS.
- ENOSPC
(начиная с Linux
4.9)
- Одним из
значений в
flags
задаётся
создание
нового
пространства
пространства
имён
пользователя,
но это
превысило
бы
ограничение,
определённое
в
соответствующем
файле в
каталоге
/proc/sys/user.
Дополнительную
информацию
смотрите в
namespaces(7).
- EPERM
- Вызывающий
процесс не
имеет
требуемых
привилегий
для этой
операции.
- EPERM
- Флаг CLONE_NEWUSER
указан в flags,
но
эффективный
пользовательский
ID или
эффективный
ID группы
вызывающего
не
отображён
в
родительское
пространство
имён
(смотрите
user_namespaces(7)).
- EPERM
(начиная с Linux
3.9)
- В flags был
указан
флаг CLONE_NEWUSER и
вызывающий
выполняется
в
окружении
chroot (т. е.
корневой
каталог
вызывающего
не
совпадает
с корневым
каталогом
пространства
имён
монтирования,
в котором
он
находится).
- EUSERS (Linux 3.11
по Linux 4.8)
- Флаг CLONE_NEWUSER
указан в flags,
и вызов
привёл бы к
превышению
ограничения
на
количество
вложенных
пользовательских
пространств
имён.
Смотрите
описание
ошибки ENOSPC,
представленное
выше.
ВЕРСИИ
Системный
вызов 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
# 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");
}