xref: /linux/tools/testing/selftests/namespaces/file_handle_test.c (revision 18b19abc3709b109676ffd1f48dcd332c2e477d4)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <grp.h>
6 #include <limits.h>
7 #include <sched.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/mount.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16 #include <linux/unistd.h>
17 #include "../kselftest_harness.h"
18 
19 #ifndef FD_NSFS_ROOT
20 #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */
21 #endif
22 
TEST(nsfs_net_handle)23 TEST(nsfs_net_handle)
24 {
25 	struct file_handle *handle;
26 	int mount_id;
27 	int ret;
28 	int fd;
29 	int ns_fd;
30 	struct stat st1, st2;
31 
32 	/* Drop to unprivileged uid/gid */
33 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
34 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
35 
36 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
37 	ASSERT_NE(handle, NULL);
38 
39 	/* Open a namespace file descriptor */
40 	ns_fd = open("/proc/self/ns/net", O_RDONLY);
41 	ASSERT_GE(ns_fd, 0);
42 
43 	/* Get handle for the namespace */
44 	handle->handle_bytes = MAX_HANDLE_SZ;
45 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
46 	if (ret < 0 && errno == EOPNOTSUPP) {
47 		SKIP(free(handle); close(ns_fd);
48 		     return, "nsfs doesn't support file handles");
49 	}
50 	ASSERT_EQ(ret, 0);
51 	ASSERT_GT(handle->handle_bytes, 0);
52 
53 	/* Try to open using FD_NSFS_ROOT as unprivileged user */
54 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
55 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
56 		SKIP(free(handle); close(ns_fd);
57 		     return,
58 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
59 	}
60 	if (fd < 0 && errno == EPERM) {
61 		SKIP(free(handle); close(ns_fd);
62 		     return,
63 			   "Permission denied for unprivileged user (expected)");
64 	}
65 	ASSERT_GE(fd, 0);
66 
67 	/* Verify we opened the correct namespace */
68 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
69 	ASSERT_EQ(fstat(fd, &st2), 0);
70 	ASSERT_EQ(st1.st_ino, st2.st_ino);
71 	ASSERT_EQ(st1.st_dev, st2.st_dev);
72 
73 	close(fd);
74 	close(ns_fd);
75 	free(handle);
76 }
77 
TEST(nsfs_uts_handle)78 TEST(nsfs_uts_handle)
79 {
80 	struct file_handle *handle;
81 	int mount_id;
82 	int ret;
83 	int fd;
84 	int ns_fd;
85 	struct stat st1, st2;
86 
87 	/* Drop to unprivileged uid/gid */
88 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
89 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
90 
91 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
92 	ASSERT_NE(handle, NULL);
93 
94 	/* Open UTS namespace file descriptor */
95 	ns_fd = open("/proc/self/ns/uts", O_RDONLY);
96 	ASSERT_GE(ns_fd, 0);
97 
98 	/* Get handle for the namespace */
99 	handle->handle_bytes = MAX_HANDLE_SZ;
100 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
101 	if (ret < 0 && errno == EOPNOTSUPP) {
102 		SKIP(free(handle); close(ns_fd);
103 		     return, "nsfs doesn't support file handles");
104 	}
105 	ASSERT_EQ(ret, 0);
106 	ASSERT_GT(handle->handle_bytes, 0);
107 
108 	/* Try to open using FD_NSFS_ROOT */
109 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
110 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
111 		SKIP(free(handle); close(ns_fd);
112 		     return,
113 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
114 	}
115 	ASSERT_GE(fd, 0);
116 
117 	/* Verify we opened the correct namespace */
118 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
119 	ASSERT_EQ(fstat(fd, &st2), 0);
120 	ASSERT_EQ(st1.st_ino, st2.st_ino);
121 	ASSERT_EQ(st1.st_dev, st2.st_dev);
122 
123 	close(fd);
124 	close(ns_fd);
125 	free(handle);
126 }
127 
TEST(nsfs_ipc_handle)128 TEST(nsfs_ipc_handle)
129 {
130 	struct file_handle *handle;
131 	int mount_id;
132 	int ret;
133 	int fd;
134 	int ns_fd;
135 	struct stat st1, st2;
136 
137 	/* Drop to unprivileged uid/gid */
138 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
139 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
140 
141 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
142 	ASSERT_NE(handle, NULL);
143 
144 	/* Open IPC namespace file descriptor */
145 	ns_fd = open("/proc/self/ns/ipc", O_RDONLY);
146 	ASSERT_GE(ns_fd, 0);
147 
148 	/* Get handle for the namespace */
149 	handle->handle_bytes = MAX_HANDLE_SZ;
150 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
151 	if (ret < 0 && errno == EOPNOTSUPP) {
152 		SKIP(free(handle); close(ns_fd);
153 		     return, "nsfs doesn't support file handles");
154 	}
155 	ASSERT_EQ(ret, 0);
156 	ASSERT_GT(handle->handle_bytes, 0);
157 
158 	/* Try to open using FD_NSFS_ROOT */
159 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
160 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
161 		SKIP(free(handle); close(ns_fd);
162 		     return,
163 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
164 	}
165 	ASSERT_GE(fd, 0);
166 
167 	/* Verify we opened the correct namespace */
168 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
169 	ASSERT_EQ(fstat(fd, &st2), 0);
170 	ASSERT_EQ(st1.st_ino, st2.st_ino);
171 	ASSERT_EQ(st1.st_dev, st2.st_dev);
172 
173 	close(fd);
174 	close(ns_fd);
175 	free(handle);
176 }
177 
TEST(nsfs_pid_handle)178 TEST(nsfs_pid_handle)
179 {
180 	struct file_handle *handle;
181 	int mount_id;
182 	int ret;
183 	int fd;
184 	int ns_fd;
185 	struct stat st1, st2;
186 
187 	/* Drop to unprivileged uid/gid */
188 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
189 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
190 
191 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
192 	ASSERT_NE(handle, NULL);
193 
194 	/* Open PID namespace file descriptor */
195 	ns_fd = open("/proc/self/ns/pid", O_RDONLY);
196 	ASSERT_GE(ns_fd, 0);
197 
198 	/* Get handle for the namespace */
199 	handle->handle_bytes = MAX_HANDLE_SZ;
200 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
201 	if (ret < 0 && errno == EOPNOTSUPP) {
202 		SKIP(free(handle); close(ns_fd);
203 		     return, "nsfs doesn't support file handles");
204 	}
205 	ASSERT_EQ(ret, 0);
206 	ASSERT_GT(handle->handle_bytes, 0);
207 
208 	/* Try to open using FD_NSFS_ROOT */
209 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
210 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
211 		SKIP(free(handle); close(ns_fd);
212 		     return,
213 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
214 	}
215 	ASSERT_GE(fd, 0);
216 
217 	/* Verify we opened the correct namespace */
218 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
219 	ASSERT_EQ(fstat(fd, &st2), 0);
220 	ASSERT_EQ(st1.st_ino, st2.st_ino);
221 	ASSERT_EQ(st1.st_dev, st2.st_dev);
222 
223 	close(fd);
224 	close(ns_fd);
225 	free(handle);
226 }
227 
TEST(nsfs_mnt_handle)228 TEST(nsfs_mnt_handle)
229 {
230 	struct file_handle *handle;
231 	int mount_id;
232 	int ret;
233 	int fd;
234 	int ns_fd;
235 	struct stat st1, st2;
236 
237 	/* Drop to unprivileged uid/gid */
238 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
239 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
240 
241 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
242 	ASSERT_NE(handle, NULL);
243 
244 	/* Open mount namespace file descriptor */
245 	ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
246 	ASSERT_GE(ns_fd, 0);
247 
248 	/* Get handle for the namespace */
249 	handle->handle_bytes = MAX_HANDLE_SZ;
250 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
251 	if (ret < 0 && errno == EOPNOTSUPP) {
252 		SKIP(free(handle); close(ns_fd);
253 		     return, "nsfs doesn't support file handles");
254 	}
255 	ASSERT_EQ(ret, 0);
256 	ASSERT_GT(handle->handle_bytes, 0);
257 
258 	/* Try to open using FD_NSFS_ROOT */
259 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
260 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
261 		SKIP(free(handle); close(ns_fd);
262 		     return,
263 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
264 	}
265 	ASSERT_GE(fd, 0);
266 
267 	/* Verify we opened the correct namespace */
268 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
269 	ASSERT_EQ(fstat(fd, &st2), 0);
270 	ASSERT_EQ(st1.st_ino, st2.st_ino);
271 	ASSERT_EQ(st1.st_dev, st2.st_dev);
272 
273 	close(fd);
274 	close(ns_fd);
275 	free(handle);
276 }
277 
TEST(nsfs_user_handle)278 TEST(nsfs_user_handle)
279 {
280 	struct file_handle *handle;
281 	int mount_id;
282 	int ret;
283 	int fd;
284 	int ns_fd;
285 	struct stat st1, st2;
286 
287 	/* Drop to unprivileged uid/gid */
288 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
289 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
290 
291 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
292 	ASSERT_NE(handle, NULL);
293 
294 	/* Open user namespace file descriptor */
295 	ns_fd = open("/proc/self/ns/user", O_RDONLY);
296 	ASSERT_GE(ns_fd, 0);
297 
298 	/* Get handle for the namespace */
299 	handle->handle_bytes = MAX_HANDLE_SZ;
300 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
301 	if (ret < 0 && errno == EOPNOTSUPP) {
302 		SKIP(free(handle); close(ns_fd);
303 		     return, "nsfs doesn't support file handles");
304 	}
305 	ASSERT_EQ(ret, 0);
306 	ASSERT_GT(handle->handle_bytes, 0);
307 
308 	/* Try to open using FD_NSFS_ROOT */
309 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
310 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
311 		SKIP(free(handle); close(ns_fd);
312 		     return,
313 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
314 	}
315 	ASSERT_GE(fd, 0);
316 
317 	/* Verify we opened the correct namespace */
318 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
319 	ASSERT_EQ(fstat(fd, &st2), 0);
320 	ASSERT_EQ(st1.st_ino, st2.st_ino);
321 	ASSERT_EQ(st1.st_dev, st2.st_dev);
322 
323 	close(fd);
324 	close(ns_fd);
325 	free(handle);
326 }
327 
TEST(nsfs_cgroup_handle)328 TEST(nsfs_cgroup_handle)
329 {
330 	struct file_handle *handle;
331 	int mount_id;
332 	int ret;
333 	int fd;
334 	int ns_fd;
335 	struct stat st1, st2;
336 
337 	/* Drop to unprivileged uid/gid */
338 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
339 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
340 
341 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
342 	ASSERT_NE(handle, NULL);
343 
344 	/* Open cgroup namespace file descriptor */
345 	ns_fd = open("/proc/self/ns/cgroup", O_RDONLY);
346 	if (ns_fd < 0) {
347 		SKIP(free(handle); return, "cgroup namespace not available");
348 	}
349 
350 	/* Get handle for the namespace */
351 	handle->handle_bytes = MAX_HANDLE_SZ;
352 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
353 	if (ret < 0 && errno == EOPNOTSUPP) {
354 		SKIP(free(handle); close(ns_fd);
355 		     return, "nsfs doesn't support file handles");
356 	}
357 	ASSERT_EQ(ret, 0);
358 	ASSERT_GT(handle->handle_bytes, 0);
359 
360 	/* Try to open using FD_NSFS_ROOT */
361 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
362 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
363 		SKIP(free(handle); close(ns_fd);
364 		     return,
365 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
366 	}
367 	ASSERT_GE(fd, 0);
368 
369 	/* Verify we opened the correct namespace */
370 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
371 	ASSERT_EQ(fstat(fd, &st2), 0);
372 	ASSERT_EQ(st1.st_ino, st2.st_ino);
373 	ASSERT_EQ(st1.st_dev, st2.st_dev);
374 
375 	close(fd);
376 	close(ns_fd);
377 	free(handle);
378 }
379 
TEST(nsfs_time_handle)380 TEST(nsfs_time_handle)
381 {
382 	struct file_handle *handle;
383 	int mount_id;
384 	int ret;
385 	int fd;
386 	int ns_fd;
387 	struct stat st1, st2;
388 
389 	/* Drop to unprivileged uid/gid */
390 	ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */
391 	ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */
392 
393 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
394 	ASSERT_NE(handle, NULL);
395 
396 	/* Open time namespace file descriptor */
397 	ns_fd = open("/proc/self/ns/time", O_RDONLY);
398 	if (ns_fd < 0) {
399 		SKIP(free(handle); return, "time namespace not available");
400 	}
401 
402 	/* Get handle for the namespace */
403 	handle->handle_bytes = MAX_HANDLE_SZ;
404 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
405 	if (ret < 0 && errno == EOPNOTSUPP) {
406 		SKIP(free(handle); close(ns_fd);
407 		     return, "nsfs doesn't support file handles");
408 	}
409 	ASSERT_EQ(ret, 0);
410 	ASSERT_GT(handle->handle_bytes, 0);
411 
412 	/* Try to open using FD_NSFS_ROOT */
413 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
414 	if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) {
415 		SKIP(free(handle); close(ns_fd);
416 		     return,
417 			   "open_by_handle_at with FD_NSFS_ROOT not supported");
418 	}
419 	ASSERT_GE(fd, 0);
420 
421 	/* Verify we opened the correct namespace */
422 	ASSERT_EQ(fstat(ns_fd, &st1), 0);
423 	ASSERT_EQ(fstat(fd, &st2), 0);
424 	ASSERT_EQ(st1.st_ino, st2.st_ino);
425 	ASSERT_EQ(st1.st_dev, st2.st_dev);
426 
427 	close(fd);
428 	close(ns_fd);
429 	free(handle);
430 }
431 
TEST(nsfs_user_net_namespace_isolation)432 TEST(nsfs_user_net_namespace_isolation)
433 {
434 	struct file_handle *handle;
435 	int mount_id;
436 	int ret;
437 	int fd;
438 	int ns_fd;
439 	pid_t pid;
440 	int status;
441 	int pipefd[2];
442 	char result;
443 
444 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
445 	ASSERT_NE(handle, NULL);
446 
447 	/* Create pipe for communication */
448 	ASSERT_EQ(pipe(pipefd), 0);
449 
450 	/* Get handle for current network namespace */
451 	ns_fd = open("/proc/self/ns/net", O_RDONLY);
452 	ASSERT_GE(ns_fd, 0);
453 
454 	handle->handle_bytes = MAX_HANDLE_SZ;
455 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
456 	if (ret < 0 && errno == EOPNOTSUPP) {
457 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
458 		     close(pipefd[1]);
459 		     return, "nsfs doesn't support file handles");
460 	}
461 	ASSERT_EQ(ret, 0);
462 	close(ns_fd);
463 
464 	pid = fork();
465 	ASSERT_GE(pid, 0);
466 
467 	if (pid == 0) {
468 		/* Child process */
469 		close(pipefd[0]);
470 
471 		/* First create new user namespace to drop privileges */
472 		ret = unshare(CLONE_NEWUSER);
473 		if (ret < 0) {
474 			write(pipefd[1], "U",
475 			      1); /* Unable to create user namespace */
476 			close(pipefd[1]);
477 			exit(0);
478 		}
479 
480 		/* Write uid/gid mappings to maintain some capabilities */
481 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
482 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
483 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
484 
485 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
486 			write(pipefd[1], "M", 1); /* Unable to set mappings */
487 			close(pipefd[1]);
488 			exit(0);
489 		}
490 
491 		/* Disable setgroups to allow gid mapping */
492 		write(setgroups_fd, "deny", 4);
493 		close(setgroups_fd);
494 
495 		/* Map current uid/gid to root in the new namespace */
496 		char mapping[64];
497 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
498 		write(uid_map_fd, mapping, strlen(mapping));
499 		close(uid_map_fd);
500 
501 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
502 		write(gid_map_fd, mapping, strlen(mapping));
503 		close(gid_map_fd);
504 
505 		/* Now create new network namespace */
506 		ret = unshare(CLONE_NEWNET);
507 		if (ret < 0) {
508 			write(pipefd[1], "N",
509 			      1); /* Unable to create network namespace */
510 			close(pipefd[1]);
511 			exit(0);
512 		}
513 
514 		/* Try to open parent's network namespace handle from new user+net namespace */
515 		fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
516 
517 		if (fd >= 0) {
518 			/* Should NOT succeed - we're in a different user namespace */
519 			write(pipefd[1], "S", 1); /* Unexpected success */
520 			close(fd);
521 		} else if (errno == ESTALE) {
522 			/* Expected: Stale file handle */
523 			write(pipefd[1], "P", 1);
524 		} else {
525 			/* Other error */
526 			write(pipefd[1], "F", 1);
527 		}
528 
529 		close(pipefd[1]);
530 		exit(0);
531 	}
532 
533 	/* Parent process */
534 	close(pipefd[1]);
535 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
536 
537 	waitpid(pid, &status, 0);
538 	ASSERT_TRUE(WIFEXITED(status));
539 	ASSERT_EQ(WEXITSTATUS(status), 0);
540 
541 	if (result == 'U') {
542 		SKIP(free(handle); close(pipefd[0]);
543 		     return, "Cannot create new user namespace");
544 	}
545 	if (result == 'M') {
546 		SKIP(free(handle); close(pipefd[0]);
547 		     return, "Cannot set uid/gid mappings");
548 	}
549 	if (result == 'N') {
550 		SKIP(free(handle); close(pipefd[0]);
551 		     return, "Cannot create new network namespace");
552 	}
553 
554 	/* Should fail with permission denied since we're in a different user namespace */
555 	ASSERT_EQ(result, 'P');
556 
557 	close(pipefd[0]);
558 	free(handle);
559 }
560 
TEST(nsfs_user_uts_namespace_isolation)561 TEST(nsfs_user_uts_namespace_isolation)
562 {
563 	struct file_handle *handle;
564 	int mount_id;
565 	int ret;
566 	int fd;
567 	int ns_fd;
568 	pid_t pid;
569 	int status;
570 	int pipefd[2];
571 	char result;
572 
573 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
574 	ASSERT_NE(handle, NULL);
575 
576 	/* Create pipe for communication */
577 	ASSERT_EQ(pipe(pipefd), 0);
578 
579 	/* Get handle for current UTS namespace */
580 	ns_fd = open("/proc/self/ns/uts", O_RDONLY);
581 	ASSERT_GE(ns_fd, 0);
582 
583 	handle->handle_bytes = MAX_HANDLE_SZ;
584 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
585 	if (ret < 0 && errno == EOPNOTSUPP) {
586 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
587 		     close(pipefd[1]);
588 		     return, "nsfs doesn't support file handles");
589 	}
590 	ASSERT_EQ(ret, 0);
591 	close(ns_fd);
592 
593 	pid = fork();
594 	ASSERT_GE(pid, 0);
595 
596 	if (pid == 0) {
597 		/* Child process */
598 		close(pipefd[0]);
599 
600 		/* First create new user namespace to drop privileges */
601 		ret = unshare(CLONE_NEWUSER);
602 		if (ret < 0) {
603 			write(pipefd[1], "U",
604 			      1); /* Unable to create user namespace */
605 			close(pipefd[1]);
606 			exit(0);
607 		}
608 
609 		/* Write uid/gid mappings to maintain some capabilities */
610 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
611 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
612 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
613 
614 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
615 			write(pipefd[1], "M", 1); /* Unable to set mappings */
616 			close(pipefd[1]);
617 			exit(0);
618 		}
619 
620 		/* Disable setgroups to allow gid mapping */
621 		write(setgroups_fd, "deny", 4);
622 		close(setgroups_fd);
623 
624 		/* Map current uid/gid to root in the new namespace */
625 		char mapping[64];
626 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
627 		write(uid_map_fd, mapping, strlen(mapping));
628 		close(uid_map_fd);
629 
630 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
631 		write(gid_map_fd, mapping, strlen(mapping));
632 		close(gid_map_fd);
633 
634 		/* Now create new UTS namespace */
635 		ret = unshare(CLONE_NEWUTS);
636 		if (ret < 0) {
637 			write(pipefd[1], "N",
638 			      1); /* Unable to create UTS namespace */
639 			close(pipefd[1]);
640 			exit(0);
641 		}
642 
643 		/* Try to open parent's UTS namespace handle from new user+uts namespace */
644 		fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
645 
646 		if (fd >= 0) {
647 			/* Should NOT succeed - we're in a different user namespace */
648 			write(pipefd[1], "S", 1); /* Unexpected success */
649 			close(fd);
650 		} else if (errno == ESTALE) {
651 			/* Expected: Stale file handle */
652 			write(pipefd[1], "P", 1);
653 		} else {
654 			/* Other error */
655 			write(pipefd[1], "F", 1);
656 		}
657 
658 		close(pipefd[1]);
659 		exit(0);
660 	}
661 
662 	/* Parent process */
663 	close(pipefd[1]);
664 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
665 
666 	waitpid(pid, &status, 0);
667 	ASSERT_TRUE(WIFEXITED(status));
668 	ASSERT_EQ(WEXITSTATUS(status), 0);
669 
670 	if (result == 'U') {
671 		SKIP(free(handle); close(pipefd[0]);
672 		     return, "Cannot create new user namespace");
673 	}
674 	if (result == 'M') {
675 		SKIP(free(handle); close(pipefd[0]);
676 		     return, "Cannot set uid/gid mappings");
677 	}
678 	if (result == 'N') {
679 		SKIP(free(handle); close(pipefd[0]);
680 		     return, "Cannot create new UTS namespace");
681 	}
682 
683 	/* Should fail with ESTALE since we're in a different user namespace */
684 	ASSERT_EQ(result, 'P');
685 
686 	close(pipefd[0]);
687 	free(handle);
688 }
689 
TEST(nsfs_user_ipc_namespace_isolation)690 TEST(nsfs_user_ipc_namespace_isolation)
691 {
692 	struct file_handle *handle;
693 	int mount_id;
694 	int ret;
695 	int fd;
696 	int ns_fd;
697 	pid_t pid;
698 	int status;
699 	int pipefd[2];
700 	char result;
701 
702 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
703 	ASSERT_NE(handle, NULL);
704 
705 	/* Create pipe for communication */
706 	ASSERT_EQ(pipe(pipefd), 0);
707 
708 	/* Get handle for current IPC namespace */
709 	ns_fd = open("/proc/self/ns/ipc", O_RDONLY);
710 	ASSERT_GE(ns_fd, 0);
711 
712 	handle->handle_bytes = MAX_HANDLE_SZ;
713 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
714 	if (ret < 0 && errno == EOPNOTSUPP) {
715 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
716 		     close(pipefd[1]);
717 		     return, "nsfs doesn't support file handles");
718 	}
719 	ASSERT_EQ(ret, 0);
720 	close(ns_fd);
721 
722 	pid = fork();
723 	ASSERT_GE(pid, 0);
724 
725 	if (pid == 0) {
726 		/* Child process */
727 		close(pipefd[0]);
728 
729 		/* First create new user namespace to drop privileges */
730 		ret = unshare(CLONE_NEWUSER);
731 		if (ret < 0) {
732 			write(pipefd[1], "U",
733 			      1); /* Unable to create user namespace */
734 			close(pipefd[1]);
735 			exit(0);
736 		}
737 
738 		/* Write uid/gid mappings to maintain some capabilities */
739 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
740 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
741 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
742 
743 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
744 			write(pipefd[1], "M", 1); /* Unable to set mappings */
745 			close(pipefd[1]);
746 			exit(0);
747 		}
748 
749 		/* Disable setgroups to allow gid mapping */
750 		write(setgroups_fd, "deny", 4);
751 		close(setgroups_fd);
752 
753 		/* Map current uid/gid to root in the new namespace */
754 		char mapping[64];
755 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
756 		write(uid_map_fd, mapping, strlen(mapping));
757 		close(uid_map_fd);
758 
759 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
760 		write(gid_map_fd, mapping, strlen(mapping));
761 		close(gid_map_fd);
762 
763 		/* Now create new IPC namespace */
764 		ret = unshare(CLONE_NEWIPC);
765 		if (ret < 0) {
766 			write(pipefd[1], "N",
767 			      1); /* Unable to create IPC namespace */
768 			close(pipefd[1]);
769 			exit(0);
770 		}
771 
772 		/* Try to open parent's IPC namespace handle from new user+ipc namespace */
773 		fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
774 
775 		if (fd >= 0) {
776 			/* Should NOT succeed - we're in a different user namespace */
777 			write(pipefd[1], "S", 1); /* Unexpected success */
778 			close(fd);
779 		} else if (errno == ESTALE) {
780 			/* Expected: Stale file handle */
781 			write(pipefd[1], "P", 1);
782 		} else {
783 			/* Other error */
784 			write(pipefd[1], "F", 1);
785 		}
786 
787 		close(pipefd[1]);
788 		exit(0);
789 	}
790 
791 	/* Parent process */
792 	close(pipefd[1]);
793 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
794 
795 	waitpid(pid, &status, 0);
796 	ASSERT_TRUE(WIFEXITED(status));
797 	ASSERT_EQ(WEXITSTATUS(status), 0);
798 
799 	if (result == 'U') {
800 		SKIP(free(handle); close(pipefd[0]);
801 		     return, "Cannot create new user namespace");
802 	}
803 	if (result == 'M') {
804 		SKIP(free(handle); close(pipefd[0]);
805 		     return, "Cannot set uid/gid mappings");
806 	}
807 	if (result == 'N') {
808 		SKIP(free(handle); close(pipefd[0]);
809 		     return, "Cannot create new IPC namespace");
810 	}
811 
812 	/* Should fail with ESTALE since we're in a different user namespace */
813 	ASSERT_EQ(result, 'P');
814 
815 	close(pipefd[0]);
816 	free(handle);
817 }
818 
TEST(nsfs_user_mnt_namespace_isolation)819 TEST(nsfs_user_mnt_namespace_isolation)
820 {
821 	struct file_handle *handle;
822 	int mount_id;
823 	int ret;
824 	int fd;
825 	int ns_fd;
826 	pid_t pid;
827 	int status;
828 	int pipefd[2];
829 	char result;
830 
831 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
832 	ASSERT_NE(handle, NULL);
833 
834 	/* Create pipe for communication */
835 	ASSERT_EQ(pipe(pipefd), 0);
836 
837 	/* Get handle for current mount namespace */
838 	ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
839 	ASSERT_GE(ns_fd, 0);
840 
841 	handle->handle_bytes = MAX_HANDLE_SZ;
842 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
843 	if (ret < 0 && errno == EOPNOTSUPP) {
844 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
845 		     close(pipefd[1]);
846 		     return, "nsfs doesn't support file handles");
847 	}
848 	ASSERT_EQ(ret, 0);
849 	close(ns_fd);
850 
851 	pid = fork();
852 	ASSERT_GE(pid, 0);
853 
854 	if (pid == 0) {
855 		/* Child process */
856 		close(pipefd[0]);
857 
858 		/* First create new user namespace to drop privileges */
859 		ret = unshare(CLONE_NEWUSER);
860 		if (ret < 0) {
861 			write(pipefd[1], "U",
862 			      1); /* Unable to create user namespace */
863 			close(pipefd[1]);
864 			exit(0);
865 		}
866 
867 		/* Write uid/gid mappings to maintain some capabilities */
868 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
869 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
870 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
871 
872 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
873 			write(pipefd[1], "M", 1); /* Unable to set mappings */
874 			close(pipefd[1]);
875 			exit(0);
876 		}
877 
878 		/* Disable setgroups to allow gid mapping */
879 		write(setgroups_fd, "deny", 4);
880 		close(setgroups_fd);
881 
882 		/* Map current uid/gid to root in the new namespace */
883 		char mapping[64];
884 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
885 		write(uid_map_fd, mapping, strlen(mapping));
886 		close(uid_map_fd);
887 
888 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
889 		write(gid_map_fd, mapping, strlen(mapping));
890 		close(gid_map_fd);
891 
892 		/* Now create new mount namespace */
893 		ret = unshare(CLONE_NEWNS);
894 		if (ret < 0) {
895 			write(pipefd[1], "N",
896 			      1); /* Unable to create mount namespace */
897 			close(pipefd[1]);
898 			exit(0);
899 		}
900 
901 		/* Try to open parent's mount namespace handle from new user+mnt namespace */
902 		fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
903 
904 		if (fd >= 0) {
905 			/* Should NOT succeed - we're in a different user namespace */
906 			write(pipefd[1], "S", 1); /* Unexpected success */
907 			close(fd);
908 		} else if (errno == ESTALE) {
909 			/* Expected: Stale file handle */
910 			write(pipefd[1], "P", 1);
911 		} else {
912 			/* Other error */
913 			write(pipefd[1], "F", 1);
914 		}
915 
916 		close(pipefd[1]);
917 		exit(0);
918 	}
919 
920 	/* Parent process */
921 	close(pipefd[1]);
922 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
923 
924 	waitpid(pid, &status, 0);
925 	ASSERT_TRUE(WIFEXITED(status));
926 	ASSERT_EQ(WEXITSTATUS(status), 0);
927 
928 	if (result == 'U') {
929 		SKIP(free(handle); close(pipefd[0]);
930 		     return, "Cannot create new user namespace");
931 	}
932 	if (result == 'M') {
933 		SKIP(free(handle); close(pipefd[0]);
934 		     return, "Cannot set uid/gid mappings");
935 	}
936 	if (result == 'N') {
937 		SKIP(free(handle); close(pipefd[0]);
938 		     return, "Cannot create new mount namespace");
939 	}
940 
941 	/* Should fail with ESTALE since we're in a different user namespace */
942 	ASSERT_EQ(result, 'P');
943 
944 	close(pipefd[0]);
945 	free(handle);
946 }
947 
TEST(nsfs_user_cgroup_namespace_isolation)948 TEST(nsfs_user_cgroup_namespace_isolation)
949 {
950 	struct file_handle *handle;
951 	int mount_id;
952 	int ret;
953 	int fd;
954 	int ns_fd;
955 	pid_t pid;
956 	int status;
957 	int pipefd[2];
958 	char result;
959 
960 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
961 	ASSERT_NE(handle, NULL);
962 
963 	/* Create pipe for communication */
964 	ASSERT_EQ(pipe(pipefd), 0);
965 
966 	/* Get handle for current cgroup namespace */
967 	ns_fd = open("/proc/self/ns/cgroup", O_RDONLY);
968 	if (ns_fd < 0) {
969 		SKIP(free(handle); close(pipefd[0]); close(pipefd[1]);
970 		     return, "cgroup namespace not available");
971 	}
972 
973 	handle->handle_bytes = MAX_HANDLE_SZ;
974 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
975 	if (ret < 0 && errno == EOPNOTSUPP) {
976 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
977 		     close(pipefd[1]);
978 		     return, "nsfs doesn't support file handles");
979 	}
980 	ASSERT_EQ(ret, 0);
981 	close(ns_fd);
982 
983 	pid = fork();
984 	ASSERT_GE(pid, 0);
985 
986 	if (pid == 0) {
987 		/* Child process */
988 		close(pipefd[0]);
989 
990 		/* First create new user namespace to drop privileges */
991 		ret = unshare(CLONE_NEWUSER);
992 		if (ret < 0) {
993 			write(pipefd[1], "U",
994 			      1); /* Unable to create user namespace */
995 			close(pipefd[1]);
996 			exit(0);
997 		}
998 
999 		/* Write uid/gid mappings to maintain some capabilities */
1000 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
1001 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
1002 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
1003 
1004 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
1005 			write(pipefd[1], "M", 1); /* Unable to set mappings */
1006 			close(pipefd[1]);
1007 			exit(0);
1008 		}
1009 
1010 		/* Disable setgroups to allow gid mapping */
1011 		write(setgroups_fd, "deny", 4);
1012 		close(setgroups_fd);
1013 
1014 		/* Map current uid/gid to root in the new namespace */
1015 		char mapping[64];
1016 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
1017 		write(uid_map_fd, mapping, strlen(mapping));
1018 		close(uid_map_fd);
1019 
1020 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
1021 		write(gid_map_fd, mapping, strlen(mapping));
1022 		close(gid_map_fd);
1023 
1024 		/* Now create new cgroup namespace */
1025 		ret = unshare(CLONE_NEWCGROUP);
1026 		if (ret < 0) {
1027 			write(pipefd[1], "N",
1028 			      1); /* Unable to create cgroup namespace */
1029 			close(pipefd[1]);
1030 			exit(0);
1031 		}
1032 
1033 		/* Try to open parent's cgroup namespace handle from new user+cgroup namespace */
1034 		fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
1035 
1036 		if (fd >= 0) {
1037 			/* Should NOT succeed - we're in a different user namespace */
1038 			write(pipefd[1], "S", 1); /* Unexpected success */
1039 			close(fd);
1040 		} else if (errno == ESTALE) {
1041 			/* Expected: Stale file handle */
1042 			write(pipefd[1], "P", 1);
1043 		} else {
1044 			/* Other error */
1045 			write(pipefd[1], "F", 1);
1046 		}
1047 
1048 		close(pipefd[1]);
1049 		exit(0);
1050 	}
1051 
1052 	/* Parent process */
1053 	close(pipefd[1]);
1054 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
1055 
1056 	waitpid(pid, &status, 0);
1057 	ASSERT_TRUE(WIFEXITED(status));
1058 	ASSERT_EQ(WEXITSTATUS(status), 0);
1059 
1060 	if (result == 'U') {
1061 		SKIP(free(handle); close(pipefd[0]);
1062 		     return, "Cannot create new user namespace");
1063 	}
1064 	if (result == 'M') {
1065 		SKIP(free(handle); close(pipefd[0]);
1066 		     return, "Cannot set uid/gid mappings");
1067 	}
1068 	if (result == 'N') {
1069 		SKIP(free(handle); close(pipefd[0]);
1070 		     return, "Cannot create new cgroup namespace");
1071 	}
1072 
1073 	/* Should fail with ESTALE since we're in a different user namespace */
1074 	ASSERT_EQ(result, 'P');
1075 
1076 	close(pipefd[0]);
1077 	free(handle);
1078 }
1079 
TEST(nsfs_user_pid_namespace_isolation)1080 TEST(nsfs_user_pid_namespace_isolation)
1081 {
1082 	struct file_handle *handle;
1083 	int mount_id;
1084 	int ret;
1085 	int fd;
1086 	int ns_fd;
1087 	pid_t pid;
1088 	int status;
1089 	int pipefd[2];
1090 	char result;
1091 
1092 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
1093 	ASSERT_NE(handle, NULL);
1094 
1095 	/* Create pipe for communication */
1096 	ASSERT_EQ(pipe(pipefd), 0);
1097 
1098 	/* Get handle for current PID namespace */
1099 	ns_fd = open("/proc/self/ns/pid", O_RDONLY);
1100 	ASSERT_GE(ns_fd, 0);
1101 
1102 	handle->handle_bytes = MAX_HANDLE_SZ;
1103 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
1104 	if (ret < 0 && errno == EOPNOTSUPP) {
1105 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
1106 		     close(pipefd[1]);
1107 		     return, "nsfs doesn't support file handles");
1108 	}
1109 	ASSERT_EQ(ret, 0);
1110 	close(ns_fd);
1111 
1112 	pid = fork();
1113 	ASSERT_GE(pid, 0);
1114 
1115 	if (pid == 0) {
1116 		/* Child process */
1117 		close(pipefd[0]);
1118 
1119 		/* First create new user namespace to drop privileges */
1120 		ret = unshare(CLONE_NEWUSER);
1121 		if (ret < 0) {
1122 			write(pipefd[1], "U",
1123 			      1); /* Unable to create user namespace */
1124 			close(pipefd[1]);
1125 			exit(0);
1126 		}
1127 
1128 		/* Write uid/gid mappings to maintain some capabilities */
1129 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
1130 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
1131 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
1132 
1133 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
1134 			write(pipefd[1], "M", 1); /* Unable to set mappings */
1135 			close(pipefd[1]);
1136 			exit(0);
1137 		}
1138 
1139 		/* Disable setgroups to allow gid mapping */
1140 		write(setgroups_fd, "deny", 4);
1141 		close(setgroups_fd);
1142 
1143 		/* Map current uid/gid to root in the new namespace */
1144 		char mapping[64];
1145 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
1146 		write(uid_map_fd, mapping, strlen(mapping));
1147 		close(uid_map_fd);
1148 
1149 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
1150 		write(gid_map_fd, mapping, strlen(mapping));
1151 		close(gid_map_fd);
1152 
1153 		/* Now create new PID namespace - requires fork to take effect */
1154 		ret = unshare(CLONE_NEWPID);
1155 		if (ret < 0) {
1156 			write(pipefd[1], "N",
1157 			      1); /* Unable to create PID namespace */
1158 			close(pipefd[1]);
1159 			exit(0);
1160 		}
1161 
1162 		/* Fork again for PID namespace to take effect */
1163 		pid_t child_pid = fork();
1164 		if (child_pid < 0) {
1165 			write(pipefd[1], "N",
1166 			      1); /* Unable to fork in PID namespace */
1167 			close(pipefd[1]);
1168 			exit(0);
1169 		}
1170 
1171 		if (child_pid == 0) {
1172 			/* Grandchild in new PID namespace */
1173 			/* Try to open parent's PID namespace handle from new user+pid namespace */
1174 			fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
1175 
1176 			if (fd >= 0) {
1177 				/* Should NOT succeed - we're in a different user namespace */
1178 				write(pipefd[1], "S",
1179 				      1); /* Unexpected success */
1180 				close(fd);
1181 			} else if (errno == ESTALE) {
1182 				/* Expected: Stale file handle */
1183 				write(pipefd[1], "P", 1);
1184 			} else {
1185 				/* Other error */
1186 				write(pipefd[1], "F", 1);
1187 			}
1188 
1189 			close(pipefd[1]);
1190 			exit(0);
1191 		}
1192 
1193 		/* Wait for grandchild */
1194 		waitpid(child_pid, NULL, 0);
1195 		exit(0);
1196 	}
1197 
1198 	/* Parent process */
1199 	close(pipefd[1]);
1200 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
1201 
1202 	waitpid(pid, &status, 0);
1203 	ASSERT_TRUE(WIFEXITED(status));
1204 	ASSERT_EQ(WEXITSTATUS(status), 0);
1205 
1206 	if (result == 'U') {
1207 		SKIP(free(handle); close(pipefd[0]);
1208 		     return, "Cannot create new user namespace");
1209 	}
1210 	if (result == 'M') {
1211 		SKIP(free(handle); close(pipefd[0]);
1212 		     return, "Cannot set uid/gid mappings");
1213 	}
1214 	if (result == 'N') {
1215 		SKIP(free(handle); close(pipefd[0]);
1216 		     return, "Cannot create new PID namespace");
1217 	}
1218 
1219 	/* Should fail with ESTALE since we're in a different user namespace */
1220 	ASSERT_EQ(result, 'P');
1221 
1222 	close(pipefd[0]);
1223 	free(handle);
1224 }
1225 
TEST(nsfs_user_time_namespace_isolation)1226 TEST(nsfs_user_time_namespace_isolation)
1227 {
1228 	struct file_handle *handle;
1229 	int mount_id;
1230 	int ret;
1231 	int fd;
1232 	int ns_fd;
1233 	pid_t pid;
1234 	int status;
1235 	int pipefd[2];
1236 	char result;
1237 
1238 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
1239 	ASSERT_NE(handle, NULL);
1240 
1241 	/* Create pipe for communication */
1242 	ASSERT_EQ(pipe(pipefd), 0);
1243 
1244 	/* Get handle for current time namespace */
1245 	ns_fd = open("/proc/self/ns/time", O_RDONLY);
1246 	if (ns_fd < 0) {
1247 		SKIP(free(handle); close(pipefd[0]); close(pipefd[1]);
1248 		     return, "time namespace not available");
1249 	}
1250 
1251 	handle->handle_bytes = MAX_HANDLE_SZ;
1252 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
1253 	if (ret < 0 && errno == EOPNOTSUPP) {
1254 		SKIP(free(handle); close(ns_fd); close(pipefd[0]);
1255 		     close(pipefd[1]);
1256 		     return, "nsfs doesn't support file handles");
1257 	}
1258 	ASSERT_EQ(ret, 0);
1259 	close(ns_fd);
1260 
1261 	pid = fork();
1262 	ASSERT_GE(pid, 0);
1263 
1264 	if (pid == 0) {
1265 		/* Child process */
1266 		close(pipefd[0]);
1267 
1268 		/* First create new user namespace to drop privileges */
1269 		ret = unshare(CLONE_NEWUSER);
1270 		if (ret < 0) {
1271 			write(pipefd[1], "U",
1272 			      1); /* Unable to create user namespace */
1273 			close(pipefd[1]);
1274 			exit(0);
1275 		}
1276 
1277 		/* Write uid/gid mappings to maintain some capabilities */
1278 		int uid_map_fd = open("/proc/self/uid_map", O_WRONLY);
1279 		int gid_map_fd = open("/proc/self/gid_map", O_WRONLY);
1280 		int setgroups_fd = open("/proc/self/setgroups", O_WRONLY);
1281 
1282 		if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) {
1283 			write(pipefd[1], "M", 1); /* Unable to set mappings */
1284 			close(pipefd[1]);
1285 			exit(0);
1286 		}
1287 
1288 		/* Disable setgroups to allow gid mapping */
1289 		write(setgroups_fd, "deny", 4);
1290 		close(setgroups_fd);
1291 
1292 		/* Map current uid/gid to root in the new namespace */
1293 		char mapping[64];
1294 		snprintf(mapping, sizeof(mapping), "0 %d 1", getuid());
1295 		write(uid_map_fd, mapping, strlen(mapping));
1296 		close(uid_map_fd);
1297 
1298 		snprintf(mapping, sizeof(mapping), "0 %d 1", getgid());
1299 		write(gid_map_fd, mapping, strlen(mapping));
1300 		close(gid_map_fd);
1301 
1302 		/* Now create new time namespace - requires fork to take effect */
1303 		ret = unshare(CLONE_NEWTIME);
1304 		if (ret < 0) {
1305 			write(pipefd[1], "N",
1306 			      1); /* Unable to create time namespace */
1307 			close(pipefd[1]);
1308 			exit(0);
1309 		}
1310 
1311 		/* Fork again for time namespace to take effect */
1312 		pid_t child_pid = fork();
1313 		if (child_pid < 0) {
1314 			write(pipefd[1], "N",
1315 			      1); /* Unable to fork in time namespace */
1316 			close(pipefd[1]);
1317 			exit(0);
1318 		}
1319 
1320 		if (child_pid == 0) {
1321 			/* Grandchild in new time namespace */
1322 			/* Try to open parent's time namespace handle from new user+time namespace */
1323 			fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
1324 
1325 			if (fd >= 0) {
1326 				/* Should NOT succeed - we're in a different user namespace */
1327 				write(pipefd[1], "S",
1328 				      1); /* Unexpected success */
1329 				close(fd);
1330 			} else if (errno == ESTALE) {
1331 				/* Expected: Stale file handle */
1332 				write(pipefd[1], "P", 1);
1333 			} else {
1334 				/* Other error */
1335 				write(pipefd[1], "F", 1);
1336 			}
1337 
1338 			close(pipefd[1]);
1339 			exit(0);
1340 		}
1341 
1342 		/* Wait for grandchild */
1343 		waitpid(child_pid, NULL, 0);
1344 		exit(0);
1345 	}
1346 
1347 	/* Parent process */
1348 	close(pipefd[1]);
1349 	ASSERT_EQ(read(pipefd[0], &result, 1), 1);
1350 
1351 	waitpid(pid, &status, 0);
1352 	ASSERT_TRUE(WIFEXITED(status));
1353 	ASSERT_EQ(WEXITSTATUS(status), 0);
1354 
1355 	if (result == 'U') {
1356 		SKIP(free(handle); close(pipefd[0]);
1357 		     return, "Cannot create new user namespace");
1358 	}
1359 	if (result == 'M') {
1360 		SKIP(free(handle); close(pipefd[0]);
1361 		     return, "Cannot set uid/gid mappings");
1362 	}
1363 	if (result == 'N') {
1364 		SKIP(free(handle); close(pipefd[0]);
1365 		     return, "Cannot create new time namespace");
1366 	}
1367 
1368 	/* Should fail with ESTALE since we're in a different user namespace */
1369 	ASSERT_EQ(result, 'P');
1370 
1371 	close(pipefd[0]);
1372 	free(handle);
1373 }
1374 
TEST(nsfs_open_flags)1375 TEST(nsfs_open_flags)
1376 {
1377 	struct file_handle *handle;
1378 	int mount_id;
1379 	int ret;
1380 	int fd;
1381 	int ns_fd;
1382 
1383 	handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ);
1384 	ASSERT_NE(handle, NULL);
1385 
1386 	/* Open a namespace file descriptor */
1387 	ns_fd = open("/proc/self/ns/net", O_RDONLY);
1388 	ASSERT_GE(ns_fd, 0);
1389 
1390 	/* Get handle for the namespace */
1391 	handle->handle_bytes = MAX_HANDLE_SZ;
1392 	ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH);
1393 	if (ret < 0 && errno == EOPNOTSUPP) {
1394 		SKIP(free(handle); close(ns_fd);
1395 		     return, "nsfs doesn't support file handles");
1396 	}
1397 	ASSERT_EQ(ret, 0);
1398 	ASSERT_GT(handle->handle_bytes, 0);
1399 
1400 	/* Test invalid flags that should fail */
1401 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_WRONLY);
1402 	ASSERT_LT(fd, 0);
1403 	ASSERT_EQ(errno, EPERM);
1404 
1405 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDWR);
1406 	ASSERT_LT(fd, 0);
1407 	ASSERT_EQ(errno, EPERM);
1408 
1409 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TRUNC);
1410 	ASSERT_LT(fd, 0);
1411 	ASSERT_EQ(errno, EPERM);
1412 
1413 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECT);
1414 	ASSERT_LT(fd, 0);
1415 	ASSERT_EQ(errno, EINVAL);
1416 
1417 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TMPFILE);
1418 	ASSERT_LT(fd, 0);
1419 	ASSERT_EQ(errno, EINVAL);
1420 
1421 	fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECTORY);
1422 	ASSERT_LT(fd, 0);
1423 	ASSERT_EQ(errno, ENOTDIR);
1424 
1425 	close(ns_fd);
1426 	free(handle);
1427 }
1428 
1429 TEST_HARNESS_MAIN
1430