1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * A synchronous umount first unmounts the shrinkable submounts of the
4 * victim that aren't busy. Every one of them has to be checked right
5 * before it is unmounted: unmounting one can slide a busy mount to where
6 * the propagated copy of the next one is looked up.
7 */
8 #define _GNU_SOURCE
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sched.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <sys/fanotify.h>
17 #include <sys/mount.h>
18 #include <sys/stat.h>
19 #include <sys/statfs.h>
20 #include <sys/vfs.h>
21 #include <linux/magic.h>
22
23 #include "../../kselftest_harness.h"
24
25 #ifndef FAN_REPORT_MNT
26 #define FAN_REPORT_MNT 0x00004000
27 #endif
28 #ifndef FAN_MARK_MNTNS
29 #define FAN_MARK_MNTNS 0x00000110
30 #endif
31 #ifndef FAN_MNT_ATTACH
32 #define FAN_MNT_ATTACH 0x01000000
33 #endif
34 #ifndef FAN_MNT_DETACH
35 #define FAN_MNT_DETACH 0x02000000
36 #endif
37
38 #define DIR_LEN 64
39 #define PATH_LEN 128
40
FIXTURE(shrink_submounts)41 FIXTURE(shrink_submounts) {
42 char base[DIR_LEN];
43 char automount[PATH_LEN];
44 bool mounted;
45 int fan;
46 };
47
48 /*
49 * Shrinkable mounts come from an automount. The tracefs mount below debugfs
50 * is one and bind mounts inherit the flag.
51 */
FIXTURE_SETUP(shrink_submounts)52 FIXTURE_SETUP(shrink_submounts)
53 {
54 struct stat st;
55 char p[PATH_LEN];
56
57 self->mounted = false;
58 self->fan = -1;
59
60 if (geteuid() != 0)
61 SKIP(return, "test requires CAP_SYS_ADMIN");
62
63 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
64 ASSERT_EQ(mount("", "/", NULL, MS_REC | MS_PRIVATE, NULL), 0);
65
66 snprintf(self->base, sizeof(self->base), "/tmp/shrink_submounts.XXXXXX");
67 ASSERT_NE(mkdtemp(self->base), NULL);
68 ASSERT_EQ(mount("tmpfs", self->base, "tmpfs", 0, NULL), 0);
69 self->mounted = true;
70 ASSERT_EQ(mount(NULL, self->base, NULL, MS_PRIVATE, NULL), 0);
71
72 snprintf(p, sizeof(p), "%s/dbg", self->base);
73 ASSERT_EQ(mkdir(p, 0755), 0);
74 if (mount("debugfs", p, "debugfs", 0, NULL)) {
75 umount2(self->base, MNT_DETACH);
76 rmdir(self->base);
77 SKIP(return, "test requires debugfs");
78 }
79 snprintf(self->automount, sizeof(self->automount), "%s/dbg/tracing",
80 self->base);
81 snprintf(p, sizeof(p), "%s/dbg/tracing/.", self->base);
82 if (stat(p, &st)) {
83 umount2(self->base, MNT_DETACH);
84 rmdir(self->base);
85 SKIP(return, "test requires the tracefs automount");
86 }
87 }
88
FIXTURE_TEARDOWN(shrink_submounts)89 FIXTURE_TEARDOWN(shrink_submounts)
90 {
91 if (self->fan >= 0)
92 close(self->fan);
93 chdir("/");
94 if (self->mounted)
95 umount2(self->base, MNT_DETACH);
96 rmdir(self->base);
97 }
98
mounted_tmpfs(const char * path)99 static bool mounted_tmpfs(const char *path)
100 {
101 struct statfs st;
102
103 return !statfs(path, &st) && st.f_type == TMPFS_MAGIC;
104 }
105
106 /*
107 * P is a shared bind mount of the automount, P1 a slave of P that is shared
108 * in turn and P2 its peer. B, another bind mount of the automount, goes on
109 * P/options and propagates copies Bc1 and Bc2 onto P1/options and
110 * P2/options. R, a tmpfs and our working directory, sits on top of Bc2 which
111 * is made private first. P, with B on it, is moved to P1/instances.
112 *
113 * A synchronous umount of P1 unmounts the shrinkable submounts Bc1 and B
114 * first. Unmounting Bc1 takes Bc2 along and slides R to P2/options where
115 * the propagated copy of B is looked up next. R is busy, so B has to stay
116 * and the umount fails with EBUSY.
117 */
TEST_F(shrink_submounts,busy_mount_moved_into_reach)118 TEST_F(shrink_submounts, busy_mount_moved_into_reach)
119 {
120 char p[PATH_LEN], p1[PATH_LEN], p2[PATH_LEN], r[PATH_LEN], cwd[PATH_LEN];
121 int nsfd;
122
123 snprintf(p, sizeof(p), "%s/p", self->base);
124 snprintf(p1, sizeof(p1), "%s/p1", self->base);
125 snprintf(p2, sizeof(p2), "%s/p2", self->base);
126 ASSERT_EQ(mkdir(p, 0755), 0);
127 ASSERT_EQ(mkdir(p1, 0755), 0);
128 ASSERT_EQ(mkdir(p2, 0755), 0);
129
130 /* watch the mount namespace so that the detached mounts get queued */
131 self->fan = fanotify_init(FAN_REPORT_MNT, O_RDONLY);
132 if (self->fan >= 0) {
133 nsfd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
134 ASSERT_GE(nsfd, 0);
135 EXPECT_EQ(fanotify_mark(self->fan, FAN_MARK_ADD | FAN_MARK_MNTNS,
136 FAN_MNT_ATTACH | FAN_MNT_DETACH, nsfd, NULL), 0);
137 close(nsfd);
138 }
139
140 ASSERT_EQ(mount(self->automount, p, NULL, MS_BIND, NULL), 0);
141 ASSERT_EQ(mount(NULL, p, NULL, MS_SHARED, NULL), 0);
142 ASSERT_EQ(mount(p, p1, NULL, MS_BIND, NULL), 0);
143 ASSERT_EQ(mount(NULL, p1, NULL, MS_SLAVE, NULL), 0);
144 ASSERT_EQ(mount(NULL, p1, NULL, MS_SHARED, NULL), 0);
145 ASSERT_EQ(mount(p1, p2, NULL, MS_BIND, NULL), 0);
146
147 /* B on P/options, copies on P1/options and P2/options */
148 snprintf(r, sizeof(r), "%s/p/options", self->base);
149 ASSERT_EQ(mount(self->automount, r, NULL, MS_BIND, NULL), 0);
150
151 /* R on top of Bc2 */
152 snprintf(r, sizeof(r), "%s/p2/options", self->base);
153 ASSERT_EQ(mount(NULL, r, NULL, MS_PRIVATE, NULL), 0);
154 ASSERT_EQ(mount("R", r, "tmpfs", 0, NULL), 0);
155 ASSERT_EQ(chdir(r), 0);
156
157 /* P, with B on it, below the victim */
158 snprintf(cwd, sizeof(cwd), "%s/p1/instances", self->base);
159 ASSERT_EQ(mount(p, cwd, NULL, MS_MOVE, NULL), 0);
160
161 ASSERT_TRUE(mounted_tmpfs(r));
162 ASSERT_EQ(umount2(p1, 0), -1);
163 EXPECT_EQ(errno, EBUSY);
164
165 /* R is still mounted and still our working directory */
166 EXPECT_TRUE(mounted_tmpfs(r));
167 ASSERT_NE(getcwd(cwd, sizeof(cwd)), NULL);
168 EXPECT_STREQ(cwd, r);
169 }
170
171 /*
172 * T is shared and Q, a slave of T, has T moved into it, so Q receives
173 * propagation from its own child. M, another bind mount of the automount, is
174 * on T/options and that is the dentry T sits on in Q. Unmounting M makes T
175 * the propagated victim at that dentry in Q and takes T along. The shrink
176 * walk of V has just unmounted M and continues in the children of T.
177 */
TEST_F(shrink_submounts,parent_goes_with_child)178 TEST_F(shrink_submounts, parent_goes_with_child)
179 {
180 char v[PATH_LEN], t[PATH_LEN], q[PATH_LEN], p[PATH_LEN];
181 struct stat before, after;
182
183 snprintf(v, sizeof(v), "%s/v", self->base);
184 snprintf(t, sizeof(t), "%s/v/t", self->base);
185 snprintf(q, sizeof(q), "%s/v/q", self->base);
186 ASSERT_EQ(mkdir(v, 0755), 0);
187 ASSERT_EQ(mount("V", v, "tmpfs", 0, NULL), 0);
188 ASSERT_EQ(mount(NULL, v, NULL, MS_PRIVATE, NULL), 0);
189 ASSERT_EQ(stat(v, &before), 0);
190 ASSERT_EQ(mkdir(t, 0755), 0);
191 ASSERT_EQ(mkdir(q, 0755), 0);
192
193 /* T shared, M on T/options before anything receives from T */
194 ASSERT_EQ(mount(self->automount, t, NULL, MS_BIND, NULL), 0);
195 ASSERT_EQ(mount(NULL, t, NULL, MS_SHARED, NULL), 0);
196 snprintf(p, sizeof(p), "%s/v/t/options", self->base);
197 ASSERT_EQ(mount(self->automount, p, NULL, MS_BIND, NULL), 0);
198
199 /* Q, a slave of T, and T moved into Q at the dentry M sits on */
200 ASSERT_EQ(mount(t, q, NULL, MS_BIND, NULL), 0);
201 ASSERT_EQ(mount(NULL, q, NULL, MS_SLAVE, NULL), 0);
202 snprintf(p, sizeof(p), "%s/v/q/options", self->base);
203 ASSERT_EQ(mount(t, p, NULL, MS_MOVE, NULL), 0);
204
205 /* M, T and then Q go, V is empty and can be unmounted */
206 ASSERT_EQ(umount2(v, 0), 0);
207 ASSERT_EQ(stat(v, &after), 0);
208 EXPECT_NE(before.st_dev, after.st_dev);
209 }
210
211 TEST_HARNESS_MAIN
212