xref: /linux/tools/testing/selftests/filesystems/fsmount_ns/fsmount_ns_test.c (revision 7a0e692a0381254b2f77c54dec100cd3325a6fdf)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026 Christian Brauner <brauner@kernel.org>
4  *
5  * Test for FSMOUNT_NAMESPACE flag.
6  *
7  * Test that fsmount() with FSMOUNT_NAMESPACE creates a new mount
8  * namespace containing the specified mount.
9  */
10 #define _GNU_SOURCE
11 
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <linux/nsfs.h>
16 #include <sched.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/ioctl.h>
21 #include <sys/mount.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 #include "../wrappers.h"
27 #include "../statmount/statmount.h"
28 #include "../utils.h"
29 #include "../../kselftest_harness.h"
30 
31 #ifndef FSMOUNT_NAMESPACE
32 #define FSMOUNT_NAMESPACE	0x00000002
33 #endif
34 
35 #ifndef FSMOUNT_CLOEXEC
36 #define FSMOUNT_CLOEXEC		0x00000001
37 #endif
38 
39 #ifndef FSCONFIG_CMD_CREATE
40 #define FSCONFIG_CMD_CREATE	6
41 #endif
42 
43 static int get_mnt_ns_id(int fd, uint64_t *mnt_ns_id)
44 {
45 	if (ioctl(fd, NS_GET_MNTNS_ID, mnt_ns_id) < 0)
46 		return -errno;
47 	return 0;
48 }
49 
50 static int get_mnt_ns_id_from_path(const char *path, uint64_t *mnt_ns_id)
51 {
52 	int fd, ret;
53 
54 	fd = open(path, O_RDONLY);
55 	if (fd < 0)
56 		return -errno;
57 
58 	ret = get_mnt_ns_id(fd, mnt_ns_id);
59 	close(fd);
60 	return ret;
61 }
62 
63 static void log_mount(struct __test_metadata *_metadata, struct statmount *sm)
64 {
65 	const char *fs_type = "";
66 	const char *mnt_root = "";
67 	const char *mnt_point = "";
68 
69 	if (sm->mask & STATMOUNT_FS_TYPE)
70 		fs_type = sm->str + sm->fs_type;
71 	if (sm->mask & STATMOUNT_MNT_ROOT)
72 		mnt_root = sm->str + sm->mnt_root;
73 	if (sm->mask & STATMOUNT_MNT_POINT)
74 		mnt_point = sm->str + sm->mnt_point;
75 
76 	TH_LOG("  mnt_id: %llu, parent_id: %llu, fs_type: %s, root: %s, point: %s",
77 	       (unsigned long long)sm->mnt_id,
78 	       (unsigned long long)sm->mnt_parent_id,
79 	       fs_type, mnt_root, mnt_point);
80 }
81 
82 static void dump_mounts(struct __test_metadata *_metadata, uint64_t mnt_ns_id)
83 {
84 	uint64_t list[256];
85 	ssize_t nr_mounts;
86 
87 	nr_mounts = listmount(LSMT_ROOT, mnt_ns_id, 0, list, 256, 0);
88 	if (nr_mounts < 0) {
89 		TH_LOG("listmount failed: %s", strerror(errno));
90 		return;
91 	}
92 
93 	TH_LOG("Mount namespace %llu contains %zd mount(s):",
94 	       (unsigned long long)mnt_ns_id, nr_mounts);
95 
96 	for (ssize_t i = 0; i < nr_mounts; i++) {
97 		struct statmount *sm;
98 
99 		sm = statmount_alloc(list[i], mnt_ns_id,
100 				     STATMOUNT_MNT_BASIC |
101 				     STATMOUNT_FS_TYPE |
102 				     STATMOUNT_MNT_ROOT |
103 				     STATMOUNT_MNT_POINT, 0);
104 		if (!sm) {
105 			TH_LOG("  [%zd] mnt_id %llu: statmount failed: %s",
106 			       i, (unsigned long long)list[i], strerror(errno));
107 			continue;
108 		}
109 
110 		log_mount(_metadata, sm);
111 		free(sm);
112 	}
113 }
114 
115 static int create_tmpfs_fd(void)
116 {
117 	int fs_fd, ret;
118 
119 	fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
120 	if (fs_fd < 0)
121 		return -errno;
122 
123 	ret = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
124 	if (ret < 0) {
125 		close(fs_fd);
126 		return -errno;
127 	}
128 
129 	return fs_fd;
130 }
131 
132 FIXTURE(fsmount_ns)
133 {
134 	int fd;
135 	int fs_fd;
136 	uint64_t current_ns_id;
137 };
138 
139 FIXTURE_VARIANT(fsmount_ns)
140 {
141 	const char *fstype;
142 	unsigned int flags;
143 	bool expect_success;
144 	bool expect_different_ns;
145 	int min_mounts;
146 };
147 
148 FIXTURE_VARIANT_ADD(fsmount_ns, basic_tmpfs)
149 {
150 	.fstype = "tmpfs",
151 	.flags = FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
152 	.expect_success = true,
153 	.expect_different_ns = true,
154 	.min_mounts = 1,
155 };
156 
157 FIXTURE_VARIANT_ADD(fsmount_ns, cloexec_only)
158 {
159 	.fstype = "tmpfs",
160 	.flags = FSMOUNT_CLOEXEC,
161 	.expect_success = true,
162 	.expect_different_ns = false,
163 	.min_mounts = 1,
164 };
165 
166 FIXTURE_VARIANT_ADD(fsmount_ns, namespace_only)
167 {
168 	.fstype = "tmpfs",
169 	.flags = FSMOUNT_NAMESPACE,
170 	.expect_success = true,
171 	.expect_different_ns = true,
172 	.min_mounts = 1,
173 };
174 
175 FIXTURE_SETUP(fsmount_ns)
176 {
177 	int ret;
178 
179 	self->fd = -1;
180 	self->fs_fd = -1;
181 
182 	/* Check if fsopen syscall is supported */
183 	ret = sys_fsopen("tmpfs", 0);
184 	if (ret == -1 && errno == ENOSYS)
185 		SKIP(return, "fsopen() syscall not supported");
186 	if (ret >= 0)
187 		close(ret);
188 
189 	/* Check if statmount/listmount are supported */
190 	ret = statmount(0, 0, 0, 0, NULL, 0, 0);
191 	if (ret == -1 && errno == ENOSYS)
192 		SKIP(return, "statmount() syscall not supported");
193 
194 	/* Get current mount namespace ID for comparison */
195 	ret = get_mnt_ns_id_from_path("/proc/self/ns/mnt", &self->current_ns_id);
196 	if (ret < 0)
197 		SKIP(return, "Failed to get current mount namespace ID");
198 }
199 
200 FIXTURE_TEARDOWN(fsmount_ns)
201 {
202 	if (self->fd >= 0)
203 		close(self->fd);
204 	if (self->fs_fd >= 0)
205 		close(self->fs_fd);
206 }
207 
208 TEST_F(fsmount_ns, create_namespace)
209 {
210 	uint64_t new_ns_id;
211 	uint64_t list[256];
212 	ssize_t nr_mounts;
213 	int ret;
214 
215 	self->fs_fd = create_tmpfs_fd();
216 	ASSERT_GE(self->fs_fd, 0);
217 
218 	self->fd = sys_fsmount(self->fs_fd, variant->flags, 0);
219 
220 	if (!variant->expect_success) {
221 		ASSERT_LT(self->fd, 0);
222 		return;
223 	}
224 
225 	if (self->fd < 0 && errno == EINVAL)
226 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
227 
228 	ASSERT_GE(self->fd, 0);
229 
230 	if (variant->expect_different_ns) {
231 		/* Verify we can get the namespace ID from the fd */
232 		ret = get_mnt_ns_id(self->fd, &new_ns_id);
233 		ASSERT_EQ(ret, 0);
234 
235 		/* Verify it's a different namespace */
236 		ASSERT_NE(new_ns_id, self->current_ns_id);
237 
238 		/* List mounts in the new namespace */
239 		nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
240 		ASSERT_GE(nr_mounts, 0) {
241 			TH_LOG("%m - listmount failed");
242 		}
243 
244 		/* Verify minimum expected mounts */
245 		ASSERT_GE(nr_mounts, variant->min_mounts);
246 		TH_LOG("Namespace contains %zd mounts", nr_mounts);
247 	}
248 }
249 
250 TEST_F(fsmount_ns, setns_into_namespace)
251 {
252 	uint64_t new_ns_id;
253 	pid_t pid;
254 	int status;
255 	int ret;
256 
257 	/* Only test with FSMOUNT_NAMESPACE flag */
258 	if (!(variant->flags & FSMOUNT_NAMESPACE))
259 		SKIP(return, "setns test only for FSMOUNT_NAMESPACE case");
260 
261 	self->fs_fd = create_tmpfs_fd();
262 	ASSERT_GE(self->fs_fd, 0);
263 
264 	self->fd = sys_fsmount(self->fs_fd, variant->flags, 0);
265 	if (self->fd < 0 && errno == EINVAL)
266 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
267 
268 	ASSERT_GE(self->fd, 0);
269 
270 	/* Get namespace ID and dump all mounts */
271 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
272 	ASSERT_EQ(ret, 0);
273 
274 	dump_mounts(_metadata, new_ns_id);
275 
276 	pid = fork();
277 	ASSERT_GE(pid, 0);
278 
279 	if (pid == 0) {
280 		/* Child: try to enter the namespace */
281 		if (setns(self->fd, CLONE_NEWNS) < 0)
282 			_exit(1);
283 		_exit(0);
284 	}
285 
286 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
287 	ASSERT_TRUE(WIFEXITED(status));
288 	ASSERT_EQ(WEXITSTATUS(status), 0);
289 }
290 
291 TEST_F(fsmount_ns, verify_mount_properties)
292 {
293 	struct statmount sm;
294 	uint64_t new_ns_id;
295 	uint64_t list[256];
296 	ssize_t nr_mounts;
297 	int ret;
298 
299 	/* Only test with basic FSMOUNT_NAMESPACE flags */
300 	if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC))
301 		SKIP(return, "mount properties test only for basic case");
302 
303 	self->fs_fd = create_tmpfs_fd();
304 	ASSERT_GE(self->fs_fd, 0);
305 
306 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
307 	if (self->fd < 0 && errno == EINVAL)
308 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
309 
310 	ASSERT_GE(self->fd, 0);
311 
312 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
313 	ASSERT_EQ(ret, 0);
314 
315 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
316 	ASSERT_GE(nr_mounts, 1);
317 
318 	/* Get info about the root mount */
319 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
320 	ASSERT_EQ(ret, 0);
321 
322 	TH_LOG("Root mount id: %llu, parent: %llu",
323 	       (unsigned long long)sm.mnt_id,
324 	       (unsigned long long)sm.mnt_parent_id);
325 }
326 
327 TEST_F(fsmount_ns, verify_tmpfs_type)
328 {
329 	struct statmount *sm;
330 	uint64_t new_ns_id;
331 	uint64_t list[256];
332 	ssize_t nr_mounts;
333 	const char *fs_type;
334 	int ret;
335 
336 	/* Only test with basic FSMOUNT_NAMESPACE flags */
337 	if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC))
338 		SKIP(return, "fs type test only for basic case");
339 
340 	self->fs_fd = create_tmpfs_fd();
341 	ASSERT_GE(self->fs_fd, 0);
342 
343 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
344 	if (self->fd < 0 && errno == EINVAL)
345 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
346 
347 	ASSERT_GE(self->fd, 0);
348 
349 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
350 	ASSERT_EQ(ret, 0);
351 
352 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
353 	ASSERT_GE(nr_mounts, 1);
354 
355 	sm = statmount_alloc(list[0], new_ns_id, STATMOUNT_FS_TYPE, 0);
356 	ASSERT_NE(sm, NULL);
357 
358 	fs_type = sm->str + sm->fs_type;
359 	ASSERT_STREQ(fs_type, "tmpfs");
360 
361 	free(sm);
362 }
363 
364 FIXTURE(fsmount_ns_caps)
365 {
366 	bool has_caps;
367 };
368 
369 FIXTURE_SETUP(fsmount_ns_caps)
370 {
371 	int ret;
372 
373 	/* Check if fsopen syscall is supported */
374 	ret = sys_fsopen("tmpfs", 0);
375 	if (ret == -1 && errno == ENOSYS)
376 		SKIP(return, "fsopen() syscall not supported");
377 	if (ret >= 0)
378 		close(ret);
379 
380 	self->has_caps = (geteuid() == 0);
381 }
382 
383 FIXTURE_TEARDOWN(fsmount_ns_caps)
384 {
385 }
386 
387 TEST_F(fsmount_ns_caps, requires_cap_sys_admin)
388 {
389 	pid_t pid;
390 	int status;
391 	int fs_fd;
392 
393 	/*
394 	 * Prepare the configured filesystem fd as root before forking.
395 	 * fsopen() requires CAP_SYS_ADMIN in the mount namespace's
396 	 * user_ns, which won't be available after enter_userns().
397 	 */
398 	fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
399 	ASSERT_GE(fs_fd, 0);
400 
401 	ASSERT_EQ(sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
402 
403 	pid = fork();
404 	ASSERT_GE(pid, 0);
405 
406 	if (pid == 0) {
407 		int fd;
408 
409 		/* Child: drop privileges using utils.h helper */
410 		if (enter_userns() != 0)
411 			_exit(2);
412 
413 		/* Drop all caps using utils.h helper */
414 		if (caps_down() == 0)
415 			_exit(3);
416 
417 		fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
418 		close(fs_fd);
419 
420 		if (fd >= 0) {
421 			close(fd);
422 			/* Should have failed without caps */
423 			_exit(1);
424 		}
425 
426 		if (errno == EPERM)
427 			_exit(0);
428 
429 		/* EINVAL means FSMOUNT_NAMESPACE not supported */
430 		if (errno == EINVAL)
431 			_exit(6);
432 
433 		/* Unexpected error */
434 		_exit(7);
435 	}
436 
437 	close(fs_fd);
438 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
439 	ASSERT_TRUE(WIFEXITED(status));
440 
441 	switch (WEXITSTATUS(status)) {
442 	case 0:
443 		/* Expected: EPERM without caps */
444 		break;
445 	case 1:
446 		ASSERT_FALSE(true) TH_LOG("FSMOUNT_NAMESPACE succeeded without caps");
447 		break;
448 	case 2:
449 		SKIP(return, "enter_userns failed");
450 		break;
451 	case 3:
452 		SKIP(return, "caps_down failed");
453 		break;
454 	case 6:
455 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
456 		break;
457 	default:
458 		ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)",
459 					  WEXITSTATUS(status));
460 		break;
461 	}
462 }
463 
464 FIXTURE(fsmount_ns_userns)
465 {
466 	int fd;
467 	int fs_fd;
468 };
469 
470 FIXTURE_SETUP(fsmount_ns_userns)
471 {
472 	int ret;
473 
474 	self->fd = -1;
475 	self->fs_fd = -1;
476 
477 	/* Check if fsopen syscall is supported */
478 	ret = sys_fsopen("tmpfs", 0);
479 	if (ret == -1 && errno == ENOSYS)
480 		SKIP(return, "fsopen() syscall not supported");
481 	if (ret >= 0)
482 		close(ret);
483 
484 	/* Check if statmount/listmount are supported */
485 	ret = statmount(0, 0, 0, 0, NULL, 0, 0);
486 	if (ret == -1 && errno == ENOSYS)
487 		SKIP(return, "statmount() syscall not supported");
488 }
489 
490 FIXTURE_TEARDOWN(fsmount_ns_userns)
491 {
492 	if (self->fd >= 0)
493 		close(self->fd);
494 	if (self->fs_fd >= 0)
495 		close(self->fs_fd);
496 }
497 
498 TEST_F(fsmount_ns_userns, create_in_userns)
499 {
500 	pid_t pid;
501 	int status;
502 
503 	pid = fork();
504 	ASSERT_GE(pid, 0);
505 
506 	if (pid == 0) {
507 		uint64_t new_ns_id;
508 		uint64_t list[256];
509 		ssize_t nr_mounts;
510 		int fs_fd, fd;
511 
512 		/* Create new user namespace (also creates mount namespace) */
513 		if (setup_userns() != 0)
514 			_exit(2);
515 
516 		/* Now we have CAP_SYS_ADMIN in the user namespace */
517 		fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
518 		if (fs_fd < 0)
519 			_exit(3);
520 
521 		if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
522 			close(fs_fd);
523 			_exit(4);
524 		}
525 
526 		fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
527 		close(fs_fd);
528 
529 		if (fd < 0) {
530 			if (errno == EINVAL)
531 				_exit(6); /* FSMOUNT_NAMESPACE not supported */
532 			_exit(1);
533 		}
534 
535 		/* Verify we can get the namespace ID */
536 		if (get_mnt_ns_id(fd, &new_ns_id) != 0)
537 			_exit(7);
538 
539 		/* Verify we can list mounts in the new namespace */
540 		nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
541 		if (nr_mounts < 0)
542 			_exit(8);
543 
544 		/* Should have at least 1 mount (the tmpfs) */
545 		if (nr_mounts < 1)
546 			_exit(9);
547 
548 		close(fd);
549 		_exit(0);
550 	}
551 
552 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
553 	ASSERT_TRUE(WIFEXITED(status));
554 
555 	switch (WEXITSTATUS(status)) {
556 	case 0:
557 		/* Success */
558 		break;
559 	case 1:
560 		ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed in userns");
561 		break;
562 	case 2:
563 		SKIP(return, "setup_userns failed");
564 		break;
565 	case 3:
566 		SKIP(return, "fsopen failed in userns");
567 		break;
568 	case 4:
569 		SKIP(return, "fsconfig CMD_CREATE failed in userns");
570 		break;
571 	case 6:
572 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
573 		break;
574 	case 7:
575 		ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID");
576 		break;
577 	case 8:
578 		ASSERT_FALSE(true) TH_LOG("listmount failed in new namespace");
579 		break;
580 	case 9:
581 		ASSERT_FALSE(true) TH_LOG("New namespace has no mounts");
582 		break;
583 	default:
584 		ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)",
585 					  WEXITSTATUS(status));
586 		break;
587 	}
588 }
589 
590 TEST_F(fsmount_ns_userns, setns_in_userns)
591 {
592 	pid_t pid;
593 	int status;
594 
595 	pid = fork();
596 	ASSERT_GE(pid, 0);
597 
598 	if (pid == 0) {
599 		uint64_t new_ns_id;
600 		int fs_fd, fd;
601 		pid_t inner_pid;
602 		int inner_status;
603 
604 		/* Create new user namespace */
605 		if (setup_userns() != 0)
606 			_exit(2);
607 
608 		fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
609 		if (fs_fd < 0)
610 			_exit(3);
611 
612 		if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
613 			close(fs_fd);
614 			_exit(4);
615 		}
616 
617 		fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
618 		close(fs_fd);
619 
620 		if (fd < 0) {
621 			if (errno == EINVAL)
622 				_exit(6);
623 			_exit(1);
624 		}
625 
626 		if (get_mnt_ns_id(fd, &new_ns_id) != 0)
627 			_exit(7);
628 
629 		/* Fork again to test setns into the new namespace */
630 		inner_pid = fork();
631 		if (inner_pid < 0)
632 			_exit(10);
633 
634 		if (inner_pid == 0) {
635 			/* Inner child: enter the new namespace */
636 			if (setns(fd, CLONE_NEWNS) < 0)
637 				_exit(1);
638 			_exit(0);
639 		}
640 
641 		if (waitpid(inner_pid, &inner_status, 0) != inner_pid)
642 			_exit(11);
643 
644 		if (!WIFEXITED(inner_status) || WEXITSTATUS(inner_status) != 0)
645 			_exit(12);
646 
647 		close(fd);
648 		_exit(0);
649 	}
650 
651 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
652 	ASSERT_TRUE(WIFEXITED(status));
653 
654 	switch (WEXITSTATUS(status)) {
655 	case 0:
656 		/* Success */
657 		break;
658 	case 1:
659 		ASSERT_FALSE(true) TH_LOG("fsmount or setns failed in userns");
660 		break;
661 	case 2:
662 		SKIP(return, "setup_userns failed");
663 		break;
664 	case 3:
665 		SKIP(return, "fsopen failed in userns");
666 		break;
667 	case 4:
668 		SKIP(return, "fsconfig CMD_CREATE failed in userns");
669 		break;
670 	case 6:
671 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
672 		break;
673 	case 7:
674 		ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID");
675 		break;
676 	case 10:
677 		ASSERT_FALSE(true) TH_LOG("Inner fork failed");
678 		break;
679 	case 11:
680 		ASSERT_FALSE(true) TH_LOG("Inner waitpid failed");
681 		break;
682 	case 12:
683 		ASSERT_FALSE(true) TH_LOG("setns into new namespace failed");
684 		break;
685 	default:
686 		ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)",
687 					  WEXITSTATUS(status));
688 		break;
689 	}
690 }
691 
692 TEST_F(fsmount_ns_userns, umount_fails_einval)
693 {
694 	pid_t pid;
695 	int status;
696 
697 	pid = fork();
698 	ASSERT_GE(pid, 0);
699 
700 	if (pid == 0) {
701 		uint64_t new_ns_id;
702 		uint64_t list[256];
703 		ssize_t nr_mounts;
704 		int fs_fd, fd;
705 		ssize_t i;
706 
707 		/* Create new user namespace */
708 		if (setup_userns() != 0)
709 			_exit(2);
710 
711 		fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
712 		if (fs_fd < 0)
713 			_exit(3);
714 
715 		if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
716 			close(fs_fd);
717 			_exit(4);
718 		}
719 
720 		fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
721 		close(fs_fd);
722 
723 		if (fd < 0) {
724 			if (errno == EINVAL)
725 				_exit(6);
726 			_exit(1);
727 		}
728 
729 		if (get_mnt_ns_id(fd, &new_ns_id) != 0)
730 			_exit(7);
731 
732 		/* Get all mounts in the new namespace */
733 		nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE);
734 		if (nr_mounts < 0)
735 			_exit(13);
736 
737 		if (nr_mounts < 1)
738 			_exit(14);
739 
740 		/* Enter the new namespace */
741 		if (setns(fd, CLONE_NEWNS) < 0)
742 			_exit(8);
743 
744 		for (i = 0; i < nr_mounts; i++) {
745 			struct statmount *sm;
746 			const char *mnt_point;
747 
748 			sm = statmount_alloc(list[i], new_ns_id,
749 					     STATMOUNT_MNT_POINT, 0);
750 			if (!sm)
751 				_exit(15);
752 
753 			mnt_point = sm->str + sm->mnt_point;
754 
755 			if (umount2(mnt_point, MNT_DETACH) == 0) {
756 				free(sm);
757 				_exit(9);
758 			}
759 
760 			if (errno != EINVAL) {
761 				/* Wrong error */
762 				free(sm);
763 				_exit(10);
764 			}
765 
766 			free(sm);
767 		}
768 
769 		close(fd);
770 		_exit(0);
771 	}
772 
773 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
774 	ASSERT_TRUE(WIFEXITED(status));
775 
776 	switch (WEXITSTATUS(status)) {
777 	case 0:
778 		break;
779 	case 1:
780 		ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed");
781 		break;
782 	case 2:
783 		SKIP(return, "setup_userns failed");
784 		break;
785 	case 3:
786 		SKIP(return, "fsopen failed in userns");
787 		break;
788 	case 4:
789 		SKIP(return, "fsconfig CMD_CREATE failed in userns");
790 		break;
791 	case 6:
792 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
793 		break;
794 	case 7:
795 		ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID");
796 		break;
797 	case 8:
798 		ASSERT_FALSE(true) TH_LOG("setns into new namespace failed");
799 		break;
800 	case 9:
801 		ASSERT_FALSE(true) TH_LOG("umount succeeded but should have failed with EINVAL");
802 		break;
803 	case 10:
804 		ASSERT_FALSE(true) TH_LOG("umount failed with wrong error (expected EINVAL)");
805 		break;
806 	case 13:
807 		ASSERT_FALSE(true) TH_LOG("listmount failed");
808 		break;
809 	case 14:
810 		ASSERT_FALSE(true) TH_LOG("No mounts in new namespace");
811 		break;
812 	case 15:
813 		ASSERT_FALSE(true) TH_LOG("statmount_alloc failed");
814 		break;
815 	default:
816 		ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)",
817 					  WEXITSTATUS(status));
818 		break;
819 	}
820 }
821 
822 TEST_F(fsmount_ns_userns, umount_succeeds)
823 {
824 	pid_t pid;
825 	int status;
826 
827 	pid = fork();
828 	ASSERT_GE(pid, 0);
829 
830 	if (pid == 0) {
831 		uint64_t new_ns_id;
832 		uint64_t list[256];
833 		ssize_t nr_mounts;
834 		int fs_fd, fd;
835 		ssize_t i;
836 
837 		if (unshare(CLONE_NEWNS))
838 			_exit(1);
839 
840 		if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) != 0)
841 			_exit(1);
842 
843 		fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC);
844 		if (fs_fd < 0)
845 			_exit(3);
846 
847 		if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
848 			close(fs_fd);
849 			_exit(4);
850 		}
851 
852 		fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0);
853 		close(fs_fd);
854 
855 		if (fd < 0) {
856 			if (errno == EINVAL)
857 				_exit(6);
858 			_exit(1);
859 		}
860 
861 		if (get_mnt_ns_id(fd, &new_ns_id) != 0)
862 			_exit(7);
863 
864 		/* Get all mounts in the new namespace */
865 		nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE);
866 		if (nr_mounts < 0)
867 			_exit(13);
868 
869 		if (nr_mounts < 1)
870 			_exit(14);
871 
872 		/* Enter the new namespace */
873 		if (setns(fd, CLONE_NEWNS) < 0)
874 			_exit(8);
875 
876 		for (i = 0; i < nr_mounts; i++) {
877 			struct statmount *sm;
878 			const char *mnt_point;
879 
880 			sm = statmount_alloc(list[i], new_ns_id,
881 					     STATMOUNT_MNT_POINT, 0);
882 			if (!sm)
883 				_exit(15);
884 
885 			mnt_point = sm->str + sm->mnt_point;
886 
887 			if (umount2(mnt_point, MNT_DETACH) != 0) {
888 				free(sm);
889 				_exit(9);
890 			}
891 
892 			free(sm);
893 		}
894 
895 		close(fd);
896 		_exit(0);
897 	}
898 
899 	ASSERT_EQ(waitpid(pid, &status, 0), pid);
900 	ASSERT_TRUE(WIFEXITED(status));
901 
902 	switch (WEXITSTATUS(status)) {
903 	case 0:
904 		break;
905 	case 1:
906 		ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed or unshare failed");
907 		break;
908 	case 3:
909 		SKIP(return, "fsopen failed");
910 		break;
911 	case 4:
912 		SKIP(return, "fsconfig CMD_CREATE failed");
913 		break;
914 	case 6:
915 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
916 		break;
917 	case 7:
918 		ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID");
919 		break;
920 	case 8:
921 		ASSERT_FALSE(true) TH_LOG("setns into new namespace failed");
922 		break;
923 	case 9:
924 		ASSERT_FALSE(true) TH_LOG("umount failed but should have succeeded");
925 		break;
926 	case 13:
927 		ASSERT_FALSE(true) TH_LOG("listmount failed");
928 		break;
929 	case 14:
930 		ASSERT_FALSE(true) TH_LOG("No mounts in new namespace");
931 		break;
932 	case 15:
933 		ASSERT_FALSE(true) TH_LOG("statmount_alloc failed");
934 		break;
935 	default:
936 		ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)",
937 					  WEXITSTATUS(status));
938 		break;
939 	}
940 }
941 
942 FIXTURE(fsmount_ns_mount_attrs)
943 {
944 	int fd;
945 	int fs_fd;
946 };
947 
948 FIXTURE_SETUP(fsmount_ns_mount_attrs)
949 {
950 	int ret;
951 
952 	self->fd = -1;
953 	self->fs_fd = -1;
954 
955 	/* Check if fsopen syscall is supported */
956 	ret = sys_fsopen("tmpfs", 0);
957 	if (ret == -1 && errno == ENOSYS)
958 		SKIP(return, "fsopen() syscall not supported");
959 	if (ret >= 0)
960 		close(ret);
961 
962 	/* Check if statmount/listmount are supported */
963 	ret = statmount(0, 0, 0, 0, NULL, 0, 0);
964 	if (ret == -1 && errno == ENOSYS)
965 		SKIP(return, "statmount() syscall not supported");
966 }
967 
968 FIXTURE_TEARDOWN(fsmount_ns_mount_attrs)
969 {
970 	if (self->fd >= 0)
971 		close(self->fd);
972 	if (self->fs_fd >= 0)
973 		close(self->fs_fd);
974 }
975 
976 TEST_F(fsmount_ns_mount_attrs, readonly)
977 {
978 	struct statmount sm;
979 	uint64_t new_ns_id;
980 	uint64_t list[256];
981 	ssize_t nr_mounts;
982 	int ret;
983 
984 	self->fs_fd = create_tmpfs_fd();
985 	ASSERT_GE(self->fs_fd, 0);
986 
987 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
988 			       MOUNT_ATTR_RDONLY);
989 	if (self->fd < 0 && errno == EINVAL)
990 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
991 
992 	ASSERT_GE(self->fd, 0);
993 
994 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
995 	ASSERT_EQ(ret, 0);
996 
997 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
998 	ASSERT_GE(nr_mounts, 1);
999 
1000 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
1001 	ASSERT_EQ(ret, 0);
1002 
1003 	/* Verify the mount is read-only */
1004 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY);
1005 }
1006 
1007 TEST_F(fsmount_ns_mount_attrs, noexec)
1008 {
1009 	struct statmount sm;
1010 	uint64_t new_ns_id;
1011 	uint64_t list[256];
1012 	ssize_t nr_mounts;
1013 	int ret;
1014 
1015 	self->fs_fd = create_tmpfs_fd();
1016 	ASSERT_GE(self->fs_fd, 0);
1017 
1018 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
1019 			       MOUNT_ATTR_NOEXEC);
1020 	if (self->fd < 0 && errno == EINVAL)
1021 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
1022 
1023 	ASSERT_GE(self->fd, 0);
1024 
1025 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
1026 	ASSERT_EQ(ret, 0);
1027 
1028 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
1029 	ASSERT_GE(nr_mounts, 1);
1030 
1031 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
1032 	ASSERT_EQ(ret, 0);
1033 
1034 	/* Verify the mount is noexec */
1035 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC);
1036 }
1037 
1038 TEST_F(fsmount_ns_mount_attrs, nosuid)
1039 {
1040 	struct statmount sm;
1041 	uint64_t new_ns_id;
1042 	uint64_t list[256];
1043 	ssize_t nr_mounts;
1044 	int ret;
1045 
1046 	self->fs_fd = create_tmpfs_fd();
1047 	ASSERT_GE(self->fs_fd, 0);
1048 
1049 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
1050 			       MOUNT_ATTR_NOSUID);
1051 	if (self->fd < 0 && errno == EINVAL)
1052 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
1053 
1054 	ASSERT_GE(self->fd, 0);
1055 
1056 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
1057 	ASSERT_EQ(ret, 0);
1058 
1059 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
1060 	ASSERT_GE(nr_mounts, 1);
1061 
1062 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
1063 	ASSERT_EQ(ret, 0);
1064 
1065 	/* Verify the mount is nosuid */
1066 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID);
1067 }
1068 
1069 TEST_F(fsmount_ns_mount_attrs, noatime)
1070 {
1071 	struct statmount sm;
1072 	uint64_t new_ns_id;
1073 	uint64_t list[256];
1074 	ssize_t nr_mounts;
1075 	int ret;
1076 
1077 	self->fs_fd = create_tmpfs_fd();
1078 	ASSERT_GE(self->fs_fd, 0);
1079 
1080 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
1081 			       MOUNT_ATTR_NOATIME);
1082 	if (self->fd < 0 && errno == EINVAL)
1083 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
1084 
1085 	ASSERT_GE(self->fd, 0);
1086 
1087 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
1088 	ASSERT_EQ(ret, 0);
1089 
1090 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
1091 	ASSERT_GE(nr_mounts, 1);
1092 
1093 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
1094 	ASSERT_EQ(ret, 0);
1095 
1096 	/* Verify the mount is noatime */
1097 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME);
1098 }
1099 
1100 TEST_F(fsmount_ns_mount_attrs, combined)
1101 {
1102 	struct statmount sm;
1103 	uint64_t new_ns_id;
1104 	uint64_t list[256];
1105 	ssize_t nr_mounts;
1106 	int ret;
1107 
1108 	self->fs_fd = create_tmpfs_fd();
1109 	ASSERT_GE(self->fs_fd, 0);
1110 
1111 	self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC,
1112 			       MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC |
1113 			       MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOATIME);
1114 	if (self->fd < 0 && errno == EINVAL)
1115 		SKIP(return, "FSMOUNT_NAMESPACE not supported");
1116 
1117 	ASSERT_GE(self->fd, 0);
1118 
1119 	ret = get_mnt_ns_id(self->fd, &new_ns_id);
1120 	ASSERT_EQ(ret, 0);
1121 
1122 	nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0);
1123 	ASSERT_GE(nr_mounts, 1);
1124 
1125 	ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0);
1126 	ASSERT_EQ(ret, 0);
1127 
1128 	/* Verify all attributes are set */
1129 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY);
1130 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC);
1131 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID);
1132 	ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME);
1133 }
1134 
1135 TEST_HARNESS_MAIN
1136