diff --git a/man2/ioctl_ns.2 b/man2/ioctl_ns.2 new file mode 100644 index 000000000..6307fcf3a --- /dev/null +++ b/man2/ioctl_ns.2 @@ -0,0 +1,291 @@ +.\" Copyright (c) 2017 by Michael Kerrisk +.\" +.\" %%%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 2017-01-09 "Linux" "Linux Programmer's Manual" +.SH NAME +ioctl_ns \- ioctl() operations for Linux namespaces +.SH DESCRIPTION +.\" ============================================================ +.\" +.SS Discovering namespace relationships +Since Linux 4.9, +.\" commit bcac25a58bfc6bd79191ac5d7afb49bea96da8c9 +.\" commit 6786741dbf99e44fb0c0ed85a37582b8a26f1c3b +.\" commit a7306ed8d94af729ecef8b6e37506a1c6fc14788 +.\" commit 6ad92bf63e45f97e306da48cd1cbce6e4fef1e5d +two +.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: + + new_fd = ioctl(fd, request); + +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 +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 +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. + +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. +.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. + +Trying to get the parent of the initial user namespace fails, +since it has no parent: + +.nf +.in +4n +$ \fB./ns_show /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 the new UTS namespace is associated with the new user namespace: + +.nf +.in +4n +$ \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] +.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_show /proc/23235/ns/user p\fP +Device/Inode of parent namespace is: [0,3] / 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 +$ \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 +.in +.fi +.SS Program source +\& +.nf +/* ns_show.c + + Licensed under the GNU General Public License v2 or later. +*/ +#include +#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("Device/Inode of owning user namespace is: " + "[%lx,%lx] / %ld\\n", + (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\\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("Device/Inode of parent namespace is: [%lx,%lx] / %ld\\n", + (long) major(sb.st_dev), (long) minor(sb.st_dev), + (long) sb.st_ino); + + close(parent_fd); + } + + exit(EXIT_SUCCESS); +} +.fi +.SH SEE ALSO +.BR fstat (2), +.BR ioctl (2), +.BR proc (5), +.BR namespaces (7)