1ioctl_ns(2) System Calls Manual ioctl_ns(2)
2
3
4
6 ioctl_ns - ioctl() operations for Linux namespaces
7
9 Discovering namespace relationships
10 The following ioctl(2) operations are provided to allow discovery of
11 namespace relationships (see user_namespaces(7) and pid_namespaces(7)).
12 The form of the calls is:
13
14 new_fd = ioctl(fd, request);
15
16 In each case, fd refers to a /proc/pid/ns/* file. Both operations re‐
17 turn a new file descriptor on success.
18
19 NS_GET_USERNS (since Linux 4.9)
20 Returns a file descriptor that refers to the owning user name‐
21 space for the namespace referred to by fd.
22
23 NS_GET_PARENT (since Linux 4.9)
24 Returns a file descriptor that refers to the parent namespace of
25 the namespace referred to by fd. This operation is valid only
26 for hierarchical namespaces (i.e., PID and user namespaces).
27 For user namespaces, NS_GET_PARENT is synonymous with
28 NS_GET_USERNS.
29
30 The new file descriptor returned by these operations is opened with the
31 O_RDONLY and O_CLOEXEC (close-on-exec; see fcntl(2)) flags.
32
33 By applying fstat(2) to the returned file descriptor, one obtains a
34 stat structure whose st_dev (resident device) and st_ino (inode number)
35 fields together identify the owning/parent namespace. This inode num‐
36 ber can be matched with the inode number of another
37 /proc/pid/ns/{pid,user} file to determine whether that is the own‐
38 ing/parent namespace.
39
40 Either of these ioctl(2) operations can fail with the following errors:
41
42 EPERM The requested namespace is outside of the caller's namespace
43 scope. This error can occur if, for example, the owning user
44 namespace is an ancestor of the caller's current user namespace.
45 It can also occur on attempts to obtain the parent of the ini‐
46 tial user or PID namespace.
47
48 ENOTTY The operation is not supported by this kernel version.
49
50 Additionally, the NS_GET_PARENT operation can fail with the following
51 error:
52
53 EINVAL fd refers to a nonhierarchical namespace.
54
55 See the EXAMPLES section for an example of the use of these operations.
56
57 Discovering the namespace type
58 The NS_GET_NSTYPE operation (available since Linux 4.11) can be used to
59 discover the type of namespace referred to by the file descriptor fd:
60
61 nstype = ioctl(fd, NS_GET_NSTYPE);
62
63 fd refers to a /proc/pid/ns/* file.
64
65 The return value is one of the CLONE_NEW* values that can be specified
66 to clone(2) or unshare(2) in order to create a namespace.
67
68 Discovering the owner of a user namespace
69 The NS_GET_OWNER_UID operation (available since Linux 4.11) can be used
70 to discover the owner user ID of a user namespace (i.e., the effective
71 user ID of the process that created the user namespace). The form of
72 the call is:
73
74 uid_t uid;
75 ioctl(fd, NS_GET_OWNER_UID, &uid);
76
77 fd refers to a /proc/pid/ns/user file.
78
79 The owner user ID is returned in the uid_t pointed to by the third ar‐
80 gument.
81
82 This operation can fail with the following error:
83
84 EINVAL fd does not refer to a user namespace.
85
87 Any of the above ioctl() operations can return the following errors:
88
89 ENOTTY fd does not refer to a /proc/pid/ns/* file.
90
92 Linux.
93
95 The example shown below uses the ioctl(2) operations described above to
96 perform simple discovery of namespace relationships. The following
97 shell sessions show various examples of the use of this program.
98
99 Trying to get the parent of the initial user namespace fails, since it
100 has no parent:
101
102 $ ./ns_show /proc/self/ns/user p
103 The parent namespace is outside your namespace scope
104
105 Create a process running sleep(1) that resides in new user and UTS
106 namespaces, and show that the new UTS namespace is associated with the
107 new user namespace:
108
109 $ unshare -Uu sleep 1000 &
110 [1] 23235
111 $ ./ns_show /proc/23235/ns/uts u
112 Device/Inode of owning user namespace is: [0,3] / 4026532448
113 $ readlink /proc/23235/ns/user
114 user:[4026532448]
115
116 Then show that the parent of the new user namespace in the preceding
117 example is the initial user namespace:
118
119 $ readlink /proc/self/ns/user
120 user:[4026531837]
121 $ ./ns_show /proc/23235/ns/user p
122 Device/Inode of parent namespace is: [0,3] / 4026531837
123
124 Start a shell in a new user namespace, and show that from within this
125 shell, the parent user namespace can't be discovered. Similarly, the
126 UTS namespace (which is associated with the initial user namespace)
127 can't be discovered.
128
129 $ PS1="sh2$ " unshare -U bash
130 sh2$ ./ns_show /proc/self/ns/user p
131 The parent namespace is outside your namespace scope
132 sh2$ ./ns_show /proc/self/ns/uts u
133 The owning user namespace is outside your namespace scope
134
135 Program source
136
137 /* ns_show.c
138
139 Licensed under the GNU General Public License v2 or later.
140 */
141 #include <errno.h>
142 #include <fcntl.h>
143 #include <linux/nsfs.h>
144 #include <stdint.h>
145 #include <stdio.h>
146 #include <stdlib.h>
147 #include <string.h>
148 #include <sys/ioctl.h>
149 #include <sys/stat.h>
150 #include <sys/sysmacros.h>
151 #include <unistd.h>
152
153 int
154 main(int argc, char *argv[])
155 {
156 int fd, userns_fd, parent_fd;
157 struct stat sb;
158
159 if (argc < 2) {
160 fprintf(stderr, "Usage: %s /proc/[pid]/ns/[file] [p|u]\n",
161 argv[0]);
162 fprintf(stderr, "\nDisplay the result of one or both "
163 "of NS_GET_USERNS (u) or NS_GET_PARENT (p)\n"
164 "for the specified /proc/[pid]/ns/[file]. If neither "
165 "'p' nor 'u' is specified,\n"
166 "NS_GET_USERNS is the default.\n");
167 exit(EXIT_FAILURE);
168 }
169
170 /* Obtain a file descriptor for the 'ns' file specified
171 in argv[1]. */
172
173 fd = open(argv[1], O_RDONLY);
174 if (fd == -1) {
175 perror("open");
176 exit(EXIT_FAILURE);
177 }
178
179 /* Obtain a file descriptor for the owning user namespace and
180 then obtain and display the inode number of that namespace. */
181
182 if (argc < 3 || strchr(argv[2], 'u')) {
183 userns_fd = ioctl(fd, NS_GET_USERNS);
184
185 if (userns_fd == -1) {
186 if (errno == EPERM)
187 printf("The owning user namespace is outside "
188 "your namespace scope\n");
189 else
190 perror("ioctl-NS_GET_USERNS");
191 exit(EXIT_FAILURE);
192 }
193
194 if (fstat(userns_fd, &sb) == -1) {
195 perror("fstat-userns");
196 exit(EXIT_FAILURE);
197 }
198 printf("Device/Inode of owning user namespace is: "
199 "[%x,%x] / %ju\n",
200 major(sb.st_dev),
201 minor(sb.st_dev),
202 (uintmax_t) sb.st_ino);
203
204 close(userns_fd);
205 }
206
207 /* Obtain a file descriptor for the parent namespace and
208 then obtain and display the inode number of that namespace. */
209
210 if (argc > 2 && strchr(argv[2], 'p')) {
211 parent_fd = ioctl(fd, NS_GET_PARENT);
212
213 if (parent_fd == -1) {
214 if (errno == EINVAL)
215 printf("Can' get parent namespace of a "
216 "nonhierarchical namespace\n");
217 else if (errno == EPERM)
218 printf("The parent namespace is outside "
219 "your namespace scope\n");
220 else
221 perror("ioctl-NS_GET_PARENT");
222 exit(EXIT_FAILURE);
223 }
224
225 if (fstat(parent_fd, &sb) == -1) {
226 perror("fstat-parentns");
227 exit(EXIT_FAILURE);
228 }
229 printf("Device/Inode of parent namespace is: [%x,%x] / %ju\n",
230 major(sb.st_dev),
231 minor(sb.st_dev),
232 (uintmax_t) sb.st_ino);
233
234 close(parent_fd);
235 }
236
237 exit(EXIT_SUCCESS);
238 }
239
241 fstat(2), ioctl(2), proc(5), namespaces(7)
242
243
244
245Linux man-pages 6.04 2023-04-03 ioctl_ns(2)