| IOCTL_NS(2) | Руководство программиста Linux | IOCTL_NS(2) |
ioctl_ns - операции ioctl() для пространств имён Linux
Следующие операции ioctl(2) позволяют определить порядок отношений между пространствами имён (смотрите user_namespaces(7) и pid_namespaces(7)). Форма вызовов:
new_fd = ioctl(fd, request);
Здесь в каждом случае fd ссылается на файл /proc/[pid]/ns/*. При успешном выполнении обе операции возвращают новый файловый дескриптор.
Новый файловый дескриптор, возвращаемый этими операциями, открывается с флагами O_RDONLY и O_CLOEXEC (close-on-exec; смотрите fcntl(2)).
Применив fstat(2) к возвращаемому файловому дескриптору, можно получить структуру stat, в которой поля st_dev (подлежащее устройство) и st_ino (номер иноды) вместе отождествляют владельческое/родительское пространство имён. Этот номер иноды можно сравнить с номером иноды другого файла /proc/[pid]/ns/{pid,user}, чтобы определить то же ли это владельческое/родительское пространство имён.
Эти операции ioctl(2) могут завершаться со следующими ошибками:
Также, операция NS_GET_PARENT может завершиться со следующей ошибкой:
Использование этих операций смотрите в разделе ПРИМЕРЫ.
Операция NS_GET_NSTYPE (доступна, начиная с Linux 4.11) позволяет определять тип пространства имён, на которое ссылается файловый дескриптор fd:
nstype = ioctl(fd, NS_GET_NSTYPE);
Значение fd ссылается на файл /proc/[pid]/ns/*.
Возвращаемым значением является одно из CLONE_NEW*, которое может указываться clone(2) или unshare(2) для создания пространства имён.
Операция NS_GET_OWNER_UID (доступна, начиная с Linux 4.11) позволяет определять пользовательский ID владельца пространства имён пользователя (т. е., эффективный пользовательский ID процесса, который создал пространство имён пользователя). Формат вызова:
uid_t uid; ioctl(fd, NS_GET_OWNER_UID, &uid);
Значение fd ссылается на файл /proc/[pid]/ns/user.
Возвращаемый пользовательский ID владельца находится в третьем аргументе с типом uid_t.
Данная операция может завершиться со следующей ошибкой:
Любая из этих операций ioctl() может завершаться со следующими ошибками:
Пространства имён и операции, описанные здесь, есть только в Linux.
В примере, показанном ниже, используются описанные выше операции ioctl(2), с помощью которых определяются отношения между пространствами имён. Далее показаны сценарии запуска этой программы.
Попытка определить родителя изначального пространства имён пользователя завершается ошибкой, так как родителя нет:
$ ./ns_show /proc/self/ns/user p Родительское пространство имён находится вне области вашего пространства имён
Создаётся процесс, выполняющий sleep(1), который располагается в новом пространстве имён пользователя и UTS, и показывается, что новое пространство имён UTS связано с новым пространством имён пользователя:
$ unshare -Uu sleep 1000 & [1] 23235 $ ./ns_show /proc/23235/ns/uts u Устройство/инода, владеющая пространством имён пользователя: [0,3] / 4026532448 $ readlink /proc/23235/ns/user user:[4026532448]
Теперь покажем, что родителем нового пространства имён пользователя из предыдущего примера является начальное пространство имён пользователя:
$ readlink /proc/self/ns/user user:[4026531837] $ ./ns_show /proc/23235/ns/user p Устройство/инода родительского пространства имён: [0,3] / 4026531837
Запустим оболочку в новом пространстве имён пользователя и покажем, что внутри оболочки родительское пространство имён пользователя невозможно определить. Также невозможно определить пространство имён UTS (которое связано с изначальным пространством имён пользователя).
$ PS1="sh2$ " unshare -U bash sh2$ ./ns_show /proc/self/ns/user p Родительское пространство имён находится вне области вашего пространства имён sh2$ ./ns_show /proc/self/ns/uts u Владеющее пространство имён пользователя находится вне области вашего пространства имён
/* ns_show.c
Лицензируется под GNU General Public License v2 или новее.
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/sysmacros.h>
#ifndef NS_GET_USERNS
#define NSIO 0xb7
#define NS_GET_USERNS _IO(NSIO, 0x1)
#define NS_GET_PARENT _IO(NSIO, 0x2)
#endif
int
main(int argc, char *argv[])
{
int fd, userns_fd, parent_fd;
struct stat sb;
if (argc < 2) {
fprintf(stderr, "Использование: %s /proc/[pid]/ns/[файл] [p|u]\n",
argv[0]);
fprintf(stderr, "\nПоказывает результат одной или обеих"
"операций NS_GET_USERNS (u) и NS_GET_PARENT (p)\n"
"для заданного /proc/[pid]/ns/[файла]. Если не указано"
"'p' или 'u', то\n"
"используется NS_GET_USERNS.\n");
exit(EXIT_FAILURE);
}
/* получаем файловый дескриптор для файла 'ns', указанного
в argv[1] */
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
/* получаем файловый дескриптор владельческого пространства
имён пользователя и затем показываем номер иноды
этого пространства имён */
if (argc < 3 || strchr(argv[2], 'u')) {
userns_fd = ioctl(fd, NS_GET_USERNS);
if (userns_fd == -1) {
if (errno == EPERM)
printf("Родительское пространство имён находится "
"вне области вашего пространства имён\n");
else
perror("ioctl-NS_GET_USERNS");
exit(EXIT_FAILURE);
}
if (fstat(userns_fd, &sb) == -1) {
perror("fstat-userns");
exit(EXIT_FAILURE);
}
printf("Устройство/инода, владеющая пространством имён пользователя: "
"[%lx,%lx] / %ld\n",
(long) major(sb.st_dev), (long) minor(sb.st_dev),
(long) sb.st_ino);
close(userns_fd);
}
/* получаем файловый дескриптор родительского пространства
имён пользователя и затем показываем номер иноды
этого пространства имён */
if (argc > 2 && strchr(argv[2], 'p')) {
parent_fd = ioctl(fd, NS_GET_PARENT);
if (parent_fd == -1) {
if (errno == EINVAL)
printf("Невозможно получить родительское пространство имён"
"не иерархического пространства имён\n");
else if (errno == EPERM)
printf("Родительское пространство имён находится"
"вне области вашего пространства имён\n");
else
perror("ioctl-NS_GET_PARENT");
exit(EXIT_FAILURE);
}
if (fstat(parent_fd, &sb) == -1) {
perror("fstat-parentns");
exit(EXIT_FAILURE);
}
printf("Устройство/инода родительского пространства имён: [%lx,%lx] / %ld\n",
(long) major(sb.st_dev), (long) minor(sb.st_dev),
(long) sb.st_ino);
close(parent_fd);
}
exit(EXIT_SUCCESS);
}
| 2019-03-06 | Linux |