From: Michael Kerrisk Date: Sun, 11 Dec 2016 11:59:04 +0000 (+0100) Subject: namespaces.7: Document the NS_GET_USERNS and NS_GET_PARENT ioctl() operations X-Git-Tag: man-pages-4.09~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6143dbbffdbc5b4f982d93c5fc9214135009549c;p=thirdparty%2Fman-pages.git namespaces.7: Document the NS_GET_USERNS and NS_GET_PARENT ioctl() operations Signed-off-by: Michael Kerrisk --- diff --git a/man7/namespaces.7 b/man7/namespaces.7 index 39ddef238d..47832321a1 100644 --- a/man7/namespaces.7 +++ b/man7/namespaces.7 @@ -323,11 +323,255 @@ and Use of UTS namespaces requires a kernel that is configured with the .B CONFIG_UTS_NS option. +.\" +.\" ============================================================ +.\" +.SS Introspecting namespace relationships +Since Linux 4.9, +.\" commit bcac25a58bfc6bd79191ac5d7afb49bea96da8c9 +.\" commit 6786741dbf99e44fb0c0ed85a37582b8a26f1c3b +.\" commit a7306ed8d94af729ecef8b6e37506a1c6fc14788 +.\" commit 6ad92bf63e45f97e306da48cd1cbce6e4fef1e5d +two +.BR ioctl (2) +operations are provided to allow introspection of namespace relationships +(see +.BR user_namespaces (7) +and +.BR pid_namespaces (7)). +The form of the calls is: + + ioctl(fd, request); + +In each case, +.I fd +refers to a +.IR /proc/[pid]/ns/* +file. +.TP +.BR NS_GET_USERNS +Returns a file descriptor that refers to the owning user namespace +for the namespace referred to by +.IR fd . +.TP +.BR NS_GET_PARENT +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 +In each case, the returned file descriptor is opened with +.BR O_RDONLY +and +.BR O_CLOEXEC +(close-on-exec). +.PP +By applying +.BR fstat (2) +to the returned file descriptor, one obtains a +.I stat +structure whose +.I st_ino +(inode number) field identifies 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. + +Either of these +.BR ioctl (2) +operations can fail with the following error: +.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. +.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. .SH CONFORMING TO Namespaces are a Linux-specific feature. .SH EXAMPLE -See +For one example, .BR user_namespaces (7). + +The example shown below uses the +.BR ioctl (2) +operations described above to perform simple +introspection of namespace relationships. +The following shell sessions show various examples of the use +of this program. + +Trying to get the parent of the initial user namespace fails, +for the reasons explained earlier: + +.nf +.in +4n +$ \fB./ns_introspect /proc/self/ns/user p\fP +The parent namespace is outside your namespace scope +.in +.fi + +Create a process running +.BR sleep (1) +that resides in new user and UTS namespaces, +and show that new UTS namespace is associated with the new user namespace: + +.nf +.in +4n +$ \fBunshare \-Uu sleep 1000 &\fP +[1] 23235 +$ \fB./ns_introspect /proc/23235/ns/uts\fP +Inode number of owning user namespace is: 4026532448 +$ \fBreadlink /proc/23235/ns/user \fP +user:[4026532448] +.in +.fi + +Then show that the parent of the new user namespace in the preceding +example is the initial user namespace: + +.nf +.in +4n +$ \fBreadlink /proc/self/ns/user\fP +user:[4026531837] +$ \fB./ns_introspect /proc/23235/ns/user\fP +Inode number of owning user namespace is: 4026531837 +.in +.fi + +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. + +.nf +.in +4n +$ PS1="sh2$ " unshare \-U bash +sh2$ \fB./ns_introspect /proc/self/ns/user p\fP +The parent namespace is outside your namespace scope +sh2$ \fB./ns_introspect /proc/self/ns/uts u\fP +The owning user namespace is outside your namespace scope +.in +.fi +.SS Program source +\& +.nf +/* ns_introspect.c + + Licensed under GNU General Public License v2 or later +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#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]\\n", + argv[0]); + fprintf(stderr, "\\nDisplay the result of one or both " + "of NS_GET_USERNS (u) or NS_GET_PARENT (p)\\n" + "for the specified /proc/[pid]/ns/[file]. If neither " + "\(aqp\(aq nor \(aqu\(aq is specified,\\n" + "NS_GET_USERNS is the default.\\n"); + 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\\n"); + else + perror("ioctl\-NS_GET_USERNS"); + exit(EXIT_FAILURE); + } + + if (fstat(userns_fd, &sb) == \-1) { + perror("fstat\-userns"); + exit(EXIT_FAILURE); + } + printf("Inode number of owning user namespace is: %ld\\n", + (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\\n"); + else if (errno == EPERM) + printf("The parent namespace is outside " + "your namespace scope\\n"); + else + perror("ioctl\-NS_GET_PARENT"); + exit(EXIT_FAILURE); + } + + if (fstat(parent_fd, &sb) == \-1) { + perror("fstat\-parentns"); + exit(EXIT_FAILURE); + } + printf("Inode number of parent namespace is: %ld\\n", + (long) sb.st_ino); + + close(parent_fd); + } + + exit(EXIT_SUCCESS); +} +.fi .SH SEE ALSO .BR nsenter (1), .BR readlink (1),