| .\" Copyright (c) 2017 by Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of this |
| .\" manual under the conditions for verbatim copying, provided that the |
| .\" entire resulting derived work is distributed under the terms of a |
| .\" permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume no |
| .\" responsibility for errors or omissions, or for damages resulting from |
| .\" the use of the information contained herein. The author(s) may not |
| .\" have taken the same level of care in the production of this manual, |
| .\" which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .\" |
| .TH IOCTL_NS 2 2019-03-06 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| ioctl_ns \- ioctl() operations for Linux namespaces |
| .SH DESCRIPTION |
| .\" ============================================================ |
| .\" |
| .SS Discovering namespace relationships |
| The following |
| .BR ioctl (2) |
| operations are provided to allow discovery of namespace relationships (see |
| .BR user_namespaces (7) |
| and |
| .BR pid_namespaces (7)). |
| The form of the calls is: |
| .PP |
| .in +4n |
| .EX |
| new_fd = ioctl(fd, request); |
| .EE |
| .in |
| .PP |
| In each case, |
| .I fd |
| refers to a |
| .IR /proc/[pid]/ns/* |
| file. |
| Both operations return a new file descriptor on success. |
| .TP |
| .BR NS_GET_USERNS " (since Linux 4.9)" |
| .\" commit bcac25a58bfc6bd79191ac5d7afb49bea96da8c9 |
| .\" commit 6786741dbf99e44fb0c0ed85a37582b8a26f1c3b |
| Returns a file descriptor that refers to the owning user namespace |
| for the namespace referred to by |
| .IR fd . |
| .TP |
| .BR NS_GET_PARENT " (since Linux 4.9)" |
| .\" commit a7306ed8d94af729ecef8b6e37506a1c6fc14788 |
| Returns a file descriptor that refers to the parent namespace of |
| the namespace referred to by |
| .IR fd . |
| This operation is valid only for hierarchical namespaces |
| (i.e., PID and user namespaces). |
| For user namespaces, |
| .BR NS_GET_PARENT |
| is synonymous with |
| .BR NS_GET_USERNS . |
| .PP |
| The new file descriptor returned by these operations is opened with the |
| .BR O_RDONLY |
| and |
| .BR O_CLOEXEC |
| (close-on-exec; see |
| .BR fcntl (2)) |
| flags. |
| .PP |
| By applying |
| .BR fstat (2) |
| to the returned file descriptor, one obtains a |
| .I stat |
| structure whose |
| .I st_dev |
| (resident device) and |
| .I st_ino |
| (inode number) fields together identify the owning/parent namespace. |
| This inode number can be matched with the inode number of another |
| .IR /proc/[pid]/ns/{pid,user} |
| file to determine whether that is the owning/parent namespace. |
| .PP |
| Either of these |
| .BR ioctl (2) |
| operations can fail with the following errors: |
| .TP |
| .B EPERM |
| The requested namespace is outside of the caller's namespace scope. |
| This error can occur if, for example, the owning user namespace is an |
| ancestor of the caller's current user namespace. |
| It can also occur on attempts to obtain the parent of the initial |
| user or PID namespace. |
| .TP |
| .B ENOTTY |
| The operation is not supported by this kernel version. |
| .PP |
| Additionally, the |
| .B NS_GET_PARENT |
| operation can fail with the following error: |
| .TP |
| .B EINVAL |
| .I fd |
| refers to a nonhierarchical namespace. |
| .PP |
| See the EXAMPLE section for an example of the use of these operations. |
| .\" ============================================================ |
| .\" |
| .SS Discovering the namespace type |
| The |
| .B NS_GET_NSTYPE |
| .\" commit e5ff5ce6e20ee22511398bb31fb912466cf82a36 |
| operation (available since Linux 4.11) can be used to discover |
| the type of namespace referred to by the file descriptor |
| .IR fd : |
| .PP |
| .in +4n |
| .EX |
| nstype = ioctl(fd, NS_GET_NSTYPE); |
| .EE |
| .in |
| .PP |
| .I fd |
| refers to a |
| .IR /proc/[pid]/ns/* |
| file. |
| .PP |
| The return value is one of the |
| .BR CLONE_NEW* |
| values that can be specified to |
| .BR clone (2) |
| or |
| .BR unshare (2) |
| in order to create a namespace. |
| .\" ============================================================ |
| .\" |
| .SS Discovering the owner of a user namespace |
| The |
| .B NS_GET_OWNER_UID |
| .\" commit 015bb305b8ebe8d601a238ab70ebdc394c7a19ba |
| operation (available since Linux 4.11) can be used to discover |
| the owner user ID of a user namespace (i.e., the effective user ID |
| of the process that created the user namespace). |
| The form of the call is: |
| .PP |
| .in +4n |
| .EX |
| uid_t uid; |
| ioctl(fd, NS_GET_OWNER_UID, &uid); |
| .EE |
| .in |
| .PP |
| .I fd |
| refers to a |
| .IR /proc/[pid]/ns/user |
| file. |
| .PP |
| The owner user ID is returned in the |
| .I uid_t |
| pointed to by the third argument. |
| .PP |
| This operation can fail with the following error: |
| .TP |
| .B EINVAL |
| .I fd |
| does not refer to a user namespace. |
| .SH ERRORS |
| Any of the above |
| .BR ioctl () |
| operations can return the following errors: |
| .TP |
| .B ENOTTY |
| .I fd |
| does not refer to a |
| .I /proc/[pid]/ns/* |
| file. |
| .SH CONFORMING TO |
| Namespaces and the operations described on this page are a Linux-specific. |
| .SH EXAMPLE |
| The example shown below uses the |
| .BR ioctl (2) |
| operations described above to perform simple |
| discovery of namespace relationships. |
| The following shell sessions show various examples of the use |
| of this program. |
| .PP |
| Trying to get the parent of the initial user namespace fails, |
| since it has no parent: |
| .PP |
| .in +4n |
| .EX |
| $ \fB./ns_show /proc/self/ns/user p\fP |
| The parent namespace is outside your namespace scope |
| .EE |
| .in |
| .PP |
| Create a process running |
| .BR sleep (1) |
| that resides in new user and UTS namespaces, |
| and show that the new UTS namespace is associated with the new user namespace: |
| .PP |
| .in +4n |
| .EX |
| $ \fBunshare \-Uu sleep 1000 &\fP |
| [1] 23235 |
| $ \fB./ns_show /proc/23235/ns/uts u\fP |
| Device/Inode of owning user namespace is: [0,3] / 4026532448 |
| $ \fBreadlink /proc/23235/ns/user \fP |
| user:[4026532448] |
| .EE |
| .in |
| .PP |
| Then show that the parent of the new user namespace in the preceding |
| example is the initial user namespace: |
| .PP |
| .in +4n |
| .EX |
| $ \fBreadlink /proc/self/ns/user\fP |
| user:[4026531837] |
| $ \fB./ns_show /proc/23235/ns/user p\fP |
| Device/Inode of parent namespace is: [0,3] / 4026531837 |
| .EE |
| .in |
| .PP |
| Start a shell in a new user namespace, and show that from within |
| this shell, the parent user namespace can't be discovered. |
| Similarly, the UTS namespace |
| (which is associated with the initial user namespace) |
| can't be discovered. |
| .PP |
| .in +4n |
| .EX |
| $ \fBPS1="sh2$ " unshare \-U bash\fP |
| sh2$ \fB./ns_show /proc/self/ns/user p\fP |
| The parent namespace is outside your namespace scope |
| sh2$ \fB./ns_show /proc/self/ns/uts u\fP |
| The owning user namespace is outside your namespace scope |
| .EE |
| .in |
| .SS Program source |
| \& |
| .EX |
| /* ns_show.c |
| |
| Licensed under the GNU General Public License v2 or later. |
| */ |
| #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, "Usage: %s /proc/[pid]/ns/[file] [p|u]\en", |
| argv[0]); |
| fprintf(stderr, "\enDisplay the result of one or both " |
| "of NS_GET_USERNS (u) or NS_GET_PARENT (p)\en" |
| "for the specified /proc/[pid]/ns/[file]. If neither " |
| "\(aqp\(aq nor \(aqu\(aq is specified,\en" |
| "NS_GET_USERNS is the default.\en"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* Obtain a file descriptor for the \(aqns\(aq file specified |
| in argv[1] */ |
| |
| fd = open(argv[1], O_RDONLY); |
| if (fd == \-1) { |
| perror("open"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* Obtain a file descriptor for the owning user namespace and |
| then obtain and display the inode number of that namespace */ |
| |
| if (argc < 3 || strchr(argv[2], \(aqu\(aq)) { |
| userns_fd = ioctl(fd, NS_GET_USERNS); |
| |
| if (userns_fd == \-1) { |
| if (errno == EPERM) |
| printf("The owning user namespace is outside " |
| "your namespace scope\en"); |
| else |
| perror("ioctl\-NS_GET_USERNS"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (fstat(userns_fd, &sb) == \-1) { |
| perror("fstat\-userns"); |
| exit(EXIT_FAILURE); |
| } |
| printf("Device/Inode of owning user namespace is: " |
| "[%lx,%lx] / %ld\en", |
| (long) major(sb.st_dev), (long) minor(sb.st_dev), |
| (long) sb.st_ino); |
| |
| close(userns_fd); |
| } |
| |
| /* Obtain a file descriptor for the parent namespace and |
| then obtain and display the inode number of that namespace */ |
| |
| if (argc > 2 && strchr(argv[2], \(aqp\(aq)) { |
| parent_fd = ioctl(fd, NS_GET_PARENT); |
| |
| if (parent_fd == \-1) { |
| if (errno == EINVAL) |
| printf("Can\(aq get parent namespace of a " |
| "nonhierarchical namespace\en"); |
| else if (errno == EPERM) |
| printf("The parent namespace is outside " |
| "your namespace scope\en"); |
| else |
| perror("ioctl\-NS_GET_PARENT"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (fstat(parent_fd, &sb) == \-1) { |
| perror("fstat\-parentns"); |
| exit(EXIT_FAILURE); |
| } |
| printf("Device/Inode of parent namespace is: [%lx,%lx] / %ld\en", |
| (long) major(sb.st_dev), (long) minor(sb.st_dev), |
| (long) sb.st_ino); |
| |
| close(parent_fd); |
| } |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .SH SEE ALSO |
| .BR fstat (2), |
| .BR ioctl (2), |
| .BR proc (5), |
| .BR namespaces (7) |