Commit fa0bad3f28a7c4a192769a128ede584c49a7e12f
Committed by
Greg Kroah-Hartman
1 parent
80d4d8397a
mnt: Update unprivileged remount test
commit 4a44a19b470a886997d6647a77bb3e38dcbfa8c5 upstream. - MNT_NODEV should be irrelevant except when reading back mount flags, no longer specify MNT_NODEV on remount. - Test MNT_NODEV on devpts where it is meaningful even for unprivileged mounts. - Add a test to verify that remount of a prexisting mount with the same flags is allowed and does not change those flags. - Cleanup up the definitions of MS_REC, MS_RELATIME, MS_STRICTATIME that are used when the code is built in an environment without them. - Correct the test error messages when tests fail. There were not 5 tests that tested MS_RELATIME. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 142 additions and 30 deletions Side-by-side Diff
tools/testing/selftests/mount/unprivileged-remount-test.c
... | ... | @@ -6,6 +6,8 @@ |
6 | 6 | #include <sys/types.h> |
7 | 7 | #include <sys/mount.h> |
8 | 8 | #include <sys/wait.h> |
9 | +#include <sys/vfs.h> | |
10 | +#include <sys/statvfs.h> | |
9 | 11 | #include <stdlib.h> |
10 | 12 | #include <unistd.h> |
11 | 13 | #include <fcntl.h> |
12 | 14 | |
13 | 15 | |
... | ... | @@ -32,11 +34,14 @@ |
32 | 34 | # define CLONE_NEWPID 0x20000000 |
33 | 35 | #endif |
34 | 36 | |
37 | +#ifndef MS_REC | |
38 | +# define MS_REC 16384 | |
39 | +#endif | |
35 | 40 | #ifndef MS_RELATIME |
36 | -#define MS_RELATIME (1 << 21) | |
41 | +# define MS_RELATIME (1 << 21) | |
37 | 42 | #endif |
38 | 43 | #ifndef MS_STRICTATIME |
39 | -#define MS_STRICTATIME (1 << 24) | |
44 | +# define MS_STRICTATIME (1 << 24) | |
40 | 45 | #endif |
41 | 46 | |
42 | 47 | static void die(char *fmt, ...) |
... | ... | @@ -87,6 +92,45 @@ |
87 | 92 | } |
88 | 93 | } |
89 | 94 | |
95 | +static int read_mnt_flags(const char *path) | |
96 | +{ | |
97 | + int ret; | |
98 | + struct statvfs stat; | |
99 | + int mnt_flags; | |
100 | + | |
101 | + ret = statvfs(path, &stat); | |
102 | + if (ret != 0) { | |
103 | + die("statvfs of %s failed: %s\n", | |
104 | + path, strerror(errno)); | |
105 | + } | |
106 | + if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | \ | |
107 | + ST_NOEXEC | ST_NOATIME | ST_NODIRATIME | ST_RELATIME | \ | |
108 | + ST_SYNCHRONOUS | ST_MANDLOCK)) { | |
109 | + die("Unrecognized mount flags\n"); | |
110 | + } | |
111 | + mnt_flags = 0; | |
112 | + if (stat.f_flag & ST_RDONLY) | |
113 | + mnt_flags |= MS_RDONLY; | |
114 | + if (stat.f_flag & ST_NOSUID) | |
115 | + mnt_flags |= MS_NOSUID; | |
116 | + if (stat.f_flag & ST_NODEV) | |
117 | + mnt_flags |= MS_NODEV; | |
118 | + if (stat.f_flag & ST_NOEXEC) | |
119 | + mnt_flags |= MS_NOEXEC; | |
120 | + if (stat.f_flag & ST_NOATIME) | |
121 | + mnt_flags |= MS_NOATIME; | |
122 | + if (stat.f_flag & ST_NODIRATIME) | |
123 | + mnt_flags |= MS_NODIRATIME; | |
124 | + if (stat.f_flag & ST_RELATIME) | |
125 | + mnt_flags |= MS_RELATIME; | |
126 | + if (stat.f_flag & ST_SYNCHRONOUS) | |
127 | + mnt_flags |= MS_SYNCHRONOUS; | |
128 | + if (stat.f_flag & ST_MANDLOCK) | |
129 | + mnt_flags |= ST_MANDLOCK; | |
130 | + | |
131 | + return mnt_flags; | |
132 | +} | |
133 | + | |
90 | 134 | static void create_and_enter_userns(void) |
91 | 135 | { |
92 | 136 | uid_t uid; |
... | ... | @@ -118,7 +162,8 @@ |
118 | 162 | } |
119 | 163 | |
120 | 164 | static |
121 | -bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags) | |
165 | +bool test_unpriv_remount(const char *fstype, const char *mount_options, | |
166 | + int mount_flags, int remount_flags, int invalid_flags) | |
122 | 167 | { |
123 | 168 | pid_t child; |
124 | 169 | |
... | ... | @@ -151,9 +196,11 @@ |
151 | 196 | strerror(errno)); |
152 | 197 | } |
153 | 198 | |
154 | - if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) { | |
155 | - die("mount of /tmp failed: %s\n", | |
156 | - strerror(errno)); | |
199 | + if (mount("testing", "/tmp", fstype, mount_flags, mount_options) != 0) { | |
200 | + die("mount of %s with options '%s' on /tmp failed: %s\n", | |
201 | + fstype, | |
202 | + mount_options? mount_options : "", | |
203 | + strerror(errno)); | |
157 | 204 | } |
158 | 205 | |
159 | 206 | create_and_enter_userns(); |
160 | 207 | |
161 | 208 | |
162 | 209 | |
163 | 210 | |
164 | 211 | |
165 | 212 | |
166 | 213 | |
167 | 214 | |
168 | 215 | |
169 | 216 | |
170 | 217 | |
171 | 218 | |
172 | 219 | |
173 | 220 | |
174 | 221 | |
175 | 222 | |
176 | 223 | |
177 | 224 | |
... | ... | @@ -181,62 +228,127 @@ |
181 | 228 | |
182 | 229 | static bool test_unpriv_remount_simple(int mount_flags) |
183 | 230 | { |
184 | - return test_unpriv_remount(mount_flags, mount_flags, 0); | |
231 | + return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags, 0); | |
185 | 232 | } |
186 | 233 | |
187 | 234 | static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags) |
188 | 235 | { |
189 | - return test_unpriv_remount(mount_flags, mount_flags, invalid_flags); | |
236 | + return test_unpriv_remount("ramfs", NULL, mount_flags, mount_flags, | |
237 | + invalid_flags); | |
190 | 238 | } |
191 | 239 | |
240 | +static bool test_priv_mount_unpriv_remount(void) | |
241 | +{ | |
242 | + pid_t child; | |
243 | + int ret; | |
244 | + const char *orig_path = "/dev"; | |
245 | + const char *dest_path = "/tmp"; | |
246 | + int orig_mnt_flags, remount_mnt_flags; | |
247 | + | |
248 | + child = fork(); | |
249 | + if (child == -1) { | |
250 | + die("fork failed: %s\n", | |
251 | + strerror(errno)); | |
252 | + } | |
253 | + if (child != 0) { /* parent */ | |
254 | + pid_t pid; | |
255 | + int status; | |
256 | + pid = waitpid(child, &status, 0); | |
257 | + if (pid == -1) { | |
258 | + die("waitpid failed: %s\n", | |
259 | + strerror(errno)); | |
260 | + } | |
261 | + if (pid != child) { | |
262 | + die("waited for %d got %d\n", | |
263 | + child, pid); | |
264 | + } | |
265 | + if (!WIFEXITED(status)) { | |
266 | + die("child did not terminate cleanly\n"); | |
267 | + } | |
268 | + return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; | |
269 | + } | |
270 | + | |
271 | + orig_mnt_flags = read_mnt_flags(orig_path); | |
272 | + | |
273 | + create_and_enter_userns(); | |
274 | + ret = unshare(CLONE_NEWNS); | |
275 | + if (ret != 0) { | |
276 | + die("unshare(CLONE_NEWNS) failed: %s\n", | |
277 | + strerror(errno)); | |
278 | + } | |
279 | + | |
280 | + ret = mount(orig_path, dest_path, "bind", MS_BIND | MS_REC, NULL); | |
281 | + if (ret != 0) { | |
282 | + die("recursive bind mount of %s onto %s failed: %s\n", | |
283 | + orig_path, dest_path, strerror(errno)); | |
284 | + } | |
285 | + | |
286 | + ret = mount(dest_path, dest_path, "none", | |
287 | + MS_REMOUNT | MS_BIND | orig_mnt_flags , NULL); | |
288 | + if (ret != 0) { | |
289 | + /* system("cat /proc/self/mounts"); */ | |
290 | + die("remount of /tmp failed: %s\n", | |
291 | + strerror(errno)); | |
292 | + } | |
293 | + | |
294 | + remount_mnt_flags = read_mnt_flags(dest_path); | |
295 | + if (orig_mnt_flags != remount_mnt_flags) { | |
296 | + die("Mount flags unexpectedly changed during remount of %s originally mounted on %s\n", | |
297 | + dest_path, orig_path); | |
298 | + } | |
299 | + exit(EXIT_SUCCESS); | |
300 | +} | |
301 | + | |
192 | 302 | int main(int argc, char **argv) |
193 | 303 | { |
194 | - if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) { | |
304 | + if (!test_unpriv_remount_simple(MS_RDONLY)) { | |
195 | 305 | die("MS_RDONLY malfunctions\n"); |
196 | 306 | } |
197 | - if (!test_unpriv_remount_simple(MS_NODEV)) { | |
307 | + if (!test_unpriv_remount("devpts", "newinstance", MS_NODEV, MS_NODEV, 0)) { | |
198 | 308 | die("MS_NODEV malfunctions\n"); |
199 | 309 | } |
200 | - if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) { | |
310 | + if (!test_unpriv_remount_simple(MS_NOSUID)) { | |
201 | 311 | die("MS_NOSUID malfunctions\n"); |
202 | 312 | } |
203 | - if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) { | |
313 | + if (!test_unpriv_remount_simple(MS_NOEXEC)) { | |
204 | 314 | die("MS_NOEXEC malfunctions\n"); |
205 | 315 | } |
206 | - if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV, | |
207 | - MS_NOATIME|MS_NODEV)) | |
316 | + if (!test_unpriv_remount_atime(MS_RELATIME, | |
317 | + MS_NOATIME)) | |
208 | 318 | { |
209 | 319 | die("MS_RELATIME malfunctions\n"); |
210 | 320 | } |
211 | - if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV, | |
212 | - MS_NOATIME|MS_NODEV)) | |
321 | + if (!test_unpriv_remount_atime(MS_STRICTATIME, | |
322 | + MS_NOATIME)) | |
213 | 323 | { |
214 | 324 | die("MS_STRICTATIME malfunctions\n"); |
215 | 325 | } |
216 | - if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV, | |
217 | - MS_STRICTATIME|MS_NODEV)) | |
326 | + if (!test_unpriv_remount_atime(MS_NOATIME, | |
327 | + MS_STRICTATIME)) | |
218 | 328 | { |
219 | - die("MS_RELATIME malfunctions\n"); | |
329 | + die("MS_NOATIME malfunctions\n"); | |
220 | 330 | } |
221 | - if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV, | |
222 | - MS_NOATIME|MS_NODEV)) | |
331 | + if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME, | |
332 | + MS_NOATIME)) | |
223 | 333 | { |
224 | - die("MS_RELATIME malfunctions\n"); | |
334 | + die("MS_RELATIME|MS_NODIRATIME malfunctions\n"); | |
225 | 335 | } |
226 | - if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV, | |
227 | - MS_NOATIME|MS_NODEV)) | |
336 | + if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME, | |
337 | + MS_NOATIME)) | |
228 | 338 | { |
229 | - die("MS_RELATIME malfunctions\n"); | |
339 | + die("MS_STRICTATIME|MS_NODIRATIME malfunctions\n"); | |
230 | 340 | } |
231 | - if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV, | |
232 | - MS_STRICTATIME|MS_NODEV)) | |
341 | + if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME, | |
342 | + MS_STRICTATIME)) | |
233 | 343 | { |
234 | - die("MS_RELATIME malfunctions\n"); | |
344 | + die("MS_NOATIME|MS_DIRATIME malfunctions\n"); | |
235 | 345 | } |
236 | - if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV, | |
237 | - MS_NOATIME|MS_NODEV)) | |
346 | + if (!test_unpriv_remount("ramfs", NULL, MS_STRICTATIME, 0, MS_NOATIME)) | |
238 | 347 | { |
239 | 348 | die("Default atime malfunctions\n"); |
349 | + } | |
350 | + if (!test_priv_mount_unpriv_remount()) { | |
351 | + die("Mount flags unexpectedly changed after remount\n"); | |
240 | 352 | } |
241 | 353 | return EXIT_SUCCESS; |
242 | 354 | } |