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 |