1 // SPDX-License-Identifier: GPL-2.0-or-later
2 // Copyright (c) 2024 Christian Brauner <brauner@kernel.org>
3 
4 #define _GNU_SOURCE
5 #include <fcntl.h>
6 #include <linux/auto_dev-ioctl.h>
7 #include <linux/errno.h>
8 #include <sched.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <sys/mount.h>
13 #include <unistd.h>
14 
15 #include "../../kselftest_harness.h"
16 
17 #define MNT_NS_COUNT 11
18 #define MNT_NS_LAST_INDEX 10
19 
20 struct mnt_ns_info {
21 	__u32 size;
22 	__u32 nr_mounts;
23 	__u64 mnt_ns_id;
24 };
25 
26 #define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */
27 
28 /* Get information about namespace. */
29 #define NS_MNT_GET_INFO _IOR(0xb7, 10, struct mnt_ns_info)
30 /* Get next namespace. */
31 #define NS_MNT_GET_NEXT _IOR(0xb7, 11, struct mnt_ns_info)
32 /* Get previous namespace. */
33 #define NS_MNT_GET_PREV _IOR(0xb7, 12, struct mnt_ns_info)
34 
FIXTURE(iterate_mount_namespaces)35 FIXTURE(iterate_mount_namespaces) {
36 	int fd_mnt_ns[MNT_NS_COUNT];
37 	__u64 mnt_ns_id[MNT_NS_COUNT];
38 };
39 
FIXTURE_SETUP(iterate_mount_namespaces)40 FIXTURE_SETUP(iterate_mount_namespaces)
41 {
42 	for (int i = 0; i < MNT_NS_COUNT; i++)
43 		self->fd_mnt_ns[i] = -EBADF;
44 
45 	/*
46 	 * Creating a new user namespace let's us guarantee that we only see
47 	 * mount namespaces that we did actually create.
48 	 */
49 	ASSERT_EQ(unshare(CLONE_NEWUSER), 0);
50 
51 	for (int i = 0; i < MNT_NS_COUNT; i++) {
52 		struct mnt_ns_info info = {};
53 
54 		ASSERT_EQ(unshare(CLONE_NEWNS), 0);
55 		self->fd_mnt_ns[i] = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
56 		ASSERT_GE(self->fd_mnt_ns[i], 0);
57 		ASSERT_EQ(ioctl(self->fd_mnt_ns[i], NS_MNT_GET_INFO, &info), 0);
58 		self->mnt_ns_id[i] = info.mnt_ns_id;
59 	}
60 }
61 
FIXTURE_TEARDOWN(iterate_mount_namespaces)62 FIXTURE_TEARDOWN(iterate_mount_namespaces)
63 {
64 	for (int i = 0; i < MNT_NS_COUNT; i++) {
65 		if (self->fd_mnt_ns[i] < 0)
66 			continue;
67 		ASSERT_EQ(close(self->fd_mnt_ns[i]), 0);
68 	}
69 }
70 
TEST_F(iterate_mount_namespaces,iterate_all_forward)71 TEST_F(iterate_mount_namespaces, iterate_all_forward)
72 {
73 	int fd_mnt_ns_cur, count = 0;
74 
75 	fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[0], F_DUPFD_CLOEXEC);
76 	ASSERT_GE(fd_mnt_ns_cur, 0);
77 
78 	for (;; count++) {
79 		struct mnt_ns_info info = {};
80 		int fd_mnt_ns_next;
81 
82 		fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info);
83 		if (fd_mnt_ns_next < 0 && errno == ENOENT)
84 			break;
85 		ASSERT_GE(fd_mnt_ns_next, 0);
86 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
87 		fd_mnt_ns_cur = fd_mnt_ns_next;
88 	}
89 	ASSERT_EQ(count, MNT_NS_LAST_INDEX);
90 }
91 
TEST_F(iterate_mount_namespaces,iterate_all_backwards)92 TEST_F(iterate_mount_namespaces, iterate_all_backwards)
93 {
94 	int fd_mnt_ns_cur, count = 0;
95 
96 	fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[MNT_NS_LAST_INDEX], F_DUPFD_CLOEXEC);
97 	ASSERT_GE(fd_mnt_ns_cur, 0);
98 
99 	for (;; count++) {
100 		struct mnt_ns_info info = {};
101 		int fd_mnt_ns_prev;
102 
103 		fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info);
104 		if (fd_mnt_ns_prev < 0 && errno == ENOENT)
105 			break;
106 		ASSERT_GE(fd_mnt_ns_prev, 0);
107 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
108 		fd_mnt_ns_cur = fd_mnt_ns_prev;
109 	}
110 	ASSERT_EQ(count, MNT_NS_LAST_INDEX);
111 }
112 
TEST_F(iterate_mount_namespaces,iterate_forward)113 TEST_F(iterate_mount_namespaces, iterate_forward)
114 {
115 	int fd_mnt_ns_cur;
116 
117 	ASSERT_EQ(setns(self->fd_mnt_ns[0], CLONE_NEWNS), 0);
118 
119 	fd_mnt_ns_cur = self->fd_mnt_ns[0];
120 	for (int i = 1; i < MNT_NS_COUNT; i++) {
121 		struct mnt_ns_info info = {};
122 		int fd_mnt_ns_next;
123 
124 		fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info);
125 		ASSERT_GE(fd_mnt_ns_next, 0);
126 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
127 		fd_mnt_ns_cur = fd_mnt_ns_next;
128 		ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
129 	}
130 }
131 
TEST_F(iterate_mount_namespaces,iterate_backward)132 TEST_F(iterate_mount_namespaces, iterate_backward)
133 {
134 	int fd_mnt_ns_cur;
135 
136 	ASSERT_EQ(setns(self->fd_mnt_ns[MNT_NS_LAST_INDEX], CLONE_NEWNS), 0);
137 
138 	fd_mnt_ns_cur = self->fd_mnt_ns[MNT_NS_LAST_INDEX];
139 	for (int i = MNT_NS_LAST_INDEX - 1; i >= 0; i--) {
140 		struct mnt_ns_info info = {};
141 		int fd_mnt_ns_prev;
142 
143 		fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info);
144 		ASSERT_GE(fd_mnt_ns_prev, 0);
145 		ASSERT_EQ(close(fd_mnt_ns_cur), 0);
146 		fd_mnt_ns_cur = fd_mnt_ns_prev;
147 		ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
148 	}
149 }
150 
TEST_F(iterate_mount_namespaces,nfs_valid_ioctl)151 TEST_F(iterate_mount_namespaces, nfs_valid_ioctl)
152 {
153 	ASSERT_NE(ioctl(self->fd_mnt_ns[0], AUTOFS_DEV_IOCTL_OPENMOUNT, NULL), 0);
154 	ASSERT_EQ(errno, ENOTTY);
155 
156 	ASSERT_NE(ioctl(self->fd_mnt_ns[0], AUTOFS_DEV_IOCTL_CLOSEMOUNT, NULL), 0);
157 	ASSERT_EQ(errno, ENOTTY);
158 
159 	ASSERT_NE(ioctl(self->fd_mnt_ns[0], AUTOFS_DEV_IOCTL_READY, NULL), 0);
160 	ASSERT_EQ(errno, ENOTTY);
161 }
162 
163 TEST_HARNESS_MAIN
164