1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <sched.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <pthread.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/mount.h>
11 #include <sys/wait.h>
12 #include <sys/vfs.h>
13 #include <sys/statvfs.h>
14 #include <sys/sysinfo.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <grp.h>
19 #include <stdbool.h>
20 #include <stdarg.h>
21 #include <linux/mount.h>
22
23 #include "../filesystems/wrappers.h"
24 #include "../kselftest_harness.h"
25
26 #ifndef CLONE_NEWNS
27 #define CLONE_NEWNS 0x00020000
28 #endif
29
30 #ifndef CLONE_NEWUSER
31 #define CLONE_NEWUSER 0x10000000
32 #endif
33
34 #ifndef MS_REC
35 #define MS_REC 16384
36 #endif
37
38 #ifndef MS_RELATIME
39 #define MS_RELATIME (1 << 21)
40 #endif
41
42 #ifndef MS_STRICTATIME
43 #define MS_STRICTATIME (1 << 24)
44 #endif
45
46 #ifndef MOUNT_ATTR_RDONLY
47 #define MOUNT_ATTR_RDONLY 0x00000001
48 #endif
49
50 #ifndef MOUNT_ATTR_NOSUID
51 #define MOUNT_ATTR_NOSUID 0x00000002
52 #endif
53
54 #ifndef MOUNT_ATTR_NOEXEC
55 #define MOUNT_ATTR_NOEXEC 0x00000008
56 #endif
57
58 #ifndef MOUNT_ATTR_NODIRATIME
59 #define MOUNT_ATTR_NODIRATIME 0x00000080
60 #endif
61
62 #ifndef MOUNT_ATTR__ATIME
63 #define MOUNT_ATTR__ATIME 0x00000070
64 #endif
65
66 #ifndef MOUNT_ATTR_RELATIME
67 #define MOUNT_ATTR_RELATIME 0x00000000
68 #endif
69
70 #ifndef MOUNT_ATTR_NOATIME
71 #define MOUNT_ATTR_NOATIME 0x00000010
72 #endif
73
74 #ifndef MOUNT_ATTR_STRICTATIME
75 #define MOUNT_ATTR_STRICTATIME 0x00000020
76 #endif
77
78 #ifndef AT_RECURSIVE
79 #define AT_RECURSIVE 0x8000
80 #endif
81
82 #ifndef MS_SHARED
83 #define MS_SHARED (1 << 20)
84 #endif
85
86 #define DEFAULT_THREADS 4
87 #define ptr_to_int(p) ((int)((intptr_t)(p)))
88 #define int_to_ptr(u) ((void *)((intptr_t)(u)))
89
90 #ifndef __NR_mount_setattr
91 #if defined __alpha__
92 #define __NR_mount_setattr 552
93 #elif defined _MIPS_SIM
94 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
95 #define __NR_mount_setattr (442 + 4000)
96 #endif
97 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
98 #define __NR_mount_setattr (442 + 6000)
99 #endif
100 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
101 #define __NR_mount_setattr (442 + 5000)
102 #endif
103 #elif defined __ia64__
104 #define __NR_mount_setattr (442 + 1024)
105 #else
106 #define __NR_mount_setattr 442
107 #endif
108 #endif
109
110 #ifndef MOUNT_ATTR_IDMAP
111 #define MOUNT_ATTR_IDMAP 0x00100000
112 #endif
113
114 #ifndef MOUNT_ATTR_NOSYMFOLLOW
115 #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
116 #endif
117
sys_mount_setattr(int dfd,const char * path,unsigned int flags,struct mount_attr * attr,size_t size)118 static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags,
119 struct mount_attr *attr, size_t size)
120 {
121 return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
122 }
123
write_nointr(int fd,const void * buf,size_t count)124 static ssize_t write_nointr(int fd, const void *buf, size_t count)
125 {
126 ssize_t ret;
127
128 do {
129 ret = write(fd, buf, count);
130 } while (ret < 0 && errno == EINTR);
131
132 return ret;
133 }
134
write_file(const char * path,const void * buf,size_t count)135 static int write_file(const char *path, const void *buf, size_t count)
136 {
137 int fd;
138 ssize_t ret;
139
140 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
141 if (fd < 0)
142 return -1;
143
144 ret = write_nointr(fd, buf, count);
145 close(fd);
146 if (ret < 0 || (size_t)ret != count)
147 return -1;
148
149 return 0;
150 }
151
create_and_enter_userns(void)152 static int create_and_enter_userns(void)
153 {
154 uid_t uid;
155 gid_t gid;
156 char map[100];
157
158 uid = getuid();
159 gid = getgid();
160
161 if (unshare(CLONE_NEWUSER))
162 return -1;
163
164 if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
165 errno != ENOENT)
166 return -1;
167
168 snprintf(map, sizeof(map), "0 %d 1", uid);
169 if (write_file("/proc/self/uid_map", map, strlen(map)))
170 return -1;
171
172
173 snprintf(map, sizeof(map), "0 %d 1", gid);
174 if (write_file("/proc/self/gid_map", map, strlen(map)))
175 return -1;
176
177 if (setgid(0))
178 return -1;
179
180 if (setuid(0))
181 return -1;
182
183 return 0;
184 }
185
prepare_unpriv_mountns(void)186 static int prepare_unpriv_mountns(void)
187 {
188 if (create_and_enter_userns())
189 return -1;
190
191 if (unshare(CLONE_NEWNS))
192 return -1;
193
194 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
195 return -1;
196
197 return 0;
198 }
199
200 #ifndef ST_NOSYMFOLLOW
201 #define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */
202 #endif
203
read_mnt_flags(const char * path)204 static int read_mnt_flags(const char *path)
205 {
206 int ret;
207 struct statvfs stat;
208 unsigned int mnt_flags;
209
210 ret = statvfs(path, &stat);
211 if (ret != 0)
212 return -EINVAL;
213
214 if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC |
215 ST_NOATIME | ST_NODIRATIME | ST_RELATIME |
216 ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW))
217 return -EINVAL;
218
219 mnt_flags = 0;
220 if (stat.f_flag & ST_RDONLY)
221 mnt_flags |= MS_RDONLY;
222 if (stat.f_flag & ST_NOSUID)
223 mnt_flags |= MS_NOSUID;
224 if (stat.f_flag & ST_NODEV)
225 mnt_flags |= MS_NODEV;
226 if (stat.f_flag & ST_NOEXEC)
227 mnt_flags |= MS_NOEXEC;
228 if (stat.f_flag & ST_NOATIME)
229 mnt_flags |= MS_NOATIME;
230 if (stat.f_flag & ST_NODIRATIME)
231 mnt_flags |= MS_NODIRATIME;
232 if (stat.f_flag & ST_RELATIME)
233 mnt_flags |= MS_RELATIME;
234 if (stat.f_flag & ST_SYNCHRONOUS)
235 mnt_flags |= MS_SYNCHRONOUS;
236 if (stat.f_flag & ST_MANDLOCK)
237 mnt_flags |= ST_MANDLOCK;
238 if (stat.f_flag & ST_NOSYMFOLLOW)
239 mnt_flags |= ST_NOSYMFOLLOW;
240
241 return mnt_flags;
242 }
243
get_field(char * src,int nfields)244 static char *get_field(char *src, int nfields)
245 {
246 int i;
247 char *p = src;
248
249 for (i = 0; i < nfields; i++) {
250 while (*p && *p != ' ' && *p != '\t')
251 p++;
252
253 if (!*p)
254 break;
255
256 p++;
257 }
258
259 return p;
260 }
261
null_endofword(char * word)262 static void null_endofword(char *word)
263 {
264 while (*word && *word != ' ' && *word != '\t')
265 word++;
266 *word = '\0';
267 }
268
is_shared_mount(const char * path)269 static bool is_shared_mount(const char *path)
270 {
271 size_t len = 0;
272 char *line = NULL;
273 FILE *f = NULL;
274
275 f = fopen("/proc/self/mountinfo", "re");
276 if (!f)
277 return false;
278
279 while (getline(&line, &len, f) != -1) {
280 char *opts, *target;
281
282 target = get_field(line, 4);
283 if (!target)
284 continue;
285
286 opts = get_field(target, 2);
287 if (!opts)
288 continue;
289
290 null_endofword(target);
291
292 if (strcmp(target, path) != 0)
293 continue;
294
295 null_endofword(opts);
296 if (strstr(opts, "shared:"))
297 return true;
298 }
299
300 free(line);
301 fclose(f);
302
303 return false;
304 }
305
mount_setattr_thread(void * data)306 static void *mount_setattr_thread(void *data)
307 {
308 struct mount_attr attr = {
309 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID,
310 .attr_clr = 0,
311 .propagation = MS_SHARED,
312 };
313
314 if (sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)))
315 pthread_exit(int_to_ptr(-1));
316
317 pthread_exit(int_to_ptr(0));
318 }
319
320 /* Attempt to de-conflict with the selftests tree. */
321 #ifndef SKIP
322 #define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__)
323 #endif
324
mount_setattr_supported(void)325 static bool mount_setattr_supported(void)
326 {
327 int ret;
328
329 ret = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0);
330 if (ret < 0 && errno == ENOSYS)
331 return false;
332
333 return true;
334 }
335
FIXTURE(mount_setattr)336 FIXTURE(mount_setattr) {
337 };
338
339 #define NOSYMFOLLOW_TARGET "/mnt/A/AA/data"
340 #define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink"
341
FIXTURE_SETUP(mount_setattr)342 FIXTURE_SETUP(mount_setattr)
343 {
344 int fd = -EBADF;
345
346 if (!mount_setattr_supported())
347 SKIP(return, "mount_setattr syscall not supported");
348
349 ASSERT_EQ(prepare_unpriv_mountns(), 0);
350
351 (void)umount2("/mnt", MNT_DETACH);
352 (void)umount2("/tmp", MNT_DETACH);
353
354 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
355 "size=100000,mode=700"), 0);
356
357 ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
358
359 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
360 "size=100000,mode=700"), 0);
361
362 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
363
364 ASSERT_EQ(mkdir("/tmp/target1", 0777), 0);
365
366 ASSERT_EQ(mkdir("/tmp/target2", 0777), 0);
367
368 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
369 "size=100000,mode=700"), 0);
370
371 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
372 "size=100000,mode=700"), 0);
373
374 ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
375
376 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
377 "size=100000,mode=700"), 0);
378
379 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
380
381 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
382
383 ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
384
385 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
386 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
387
388 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
389
390 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
391 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
392
393 fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC);
394 ASSERT_GT(fd, 0);
395 ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0);
396 ASSERT_EQ(close(fd), 0);
397 }
398
FIXTURE_TEARDOWN(mount_setattr)399 FIXTURE_TEARDOWN(mount_setattr)
400 {
401 if (!mount_setattr_supported())
402 SKIP(return, "mount_setattr syscall not supported");
403
404 (void)umount2("/mnt/A", MNT_DETACH);
405 (void)umount2("/tmp", MNT_DETACH);
406 }
407
TEST_F(mount_setattr,invalid_attributes)408 TEST_F(mount_setattr, invalid_attributes)
409 {
410 struct mount_attr invalid_attr = {
411 .attr_set = (1U << 31),
412 };
413
414 if (!mount_setattr_supported())
415 SKIP(return, "mount_setattr syscall not supported");
416
417 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
418 sizeof(invalid_attr)), 0);
419
420 invalid_attr.attr_set = 0;
421 invalid_attr.attr_clr = (1U << 31);
422 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
423 sizeof(invalid_attr)), 0);
424
425 invalid_attr.attr_clr = 0;
426 invalid_attr.propagation = (1U << 31);
427 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
428 sizeof(invalid_attr)), 0);
429
430 invalid_attr.attr_set = (1U << 31);
431 invalid_attr.attr_clr = (1U << 31);
432 invalid_attr.propagation = (1U << 31);
433 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
434 sizeof(invalid_attr)), 0);
435
436 ASSERT_NE(sys_mount_setattr(-1, "mnt/A", AT_RECURSIVE, &invalid_attr,
437 sizeof(invalid_attr)), 0);
438 }
439
TEST_F(mount_setattr,extensibility)440 TEST_F(mount_setattr, extensibility)
441 {
442 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
443 char *s = "dummy";
444 struct mount_attr invalid_attr = {};
445 struct mount_attr_large {
446 struct mount_attr attr1;
447 struct mount_attr attr2;
448 struct mount_attr attr3;
449 } large_attr = {};
450
451 if (!mount_setattr_supported())
452 SKIP(return, "mount_setattr syscall not supported");
453
454 old_flags = read_mnt_flags("/mnt/A");
455 ASSERT_GT(old_flags, 0);
456
457 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, NULL,
458 sizeof(invalid_attr)), 0);
459 ASSERT_EQ(errno, EFAULT);
460
461 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, (void *)s,
462 sizeof(invalid_attr)), 0);
463 ASSERT_EQ(errno, EINVAL);
464
465 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 0), 0);
466 ASSERT_EQ(errno, EINVAL);
467
468 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
469 sizeof(invalid_attr) / 2), 0);
470 ASSERT_EQ(errno, EINVAL);
471
472 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
473 sizeof(invalid_attr) / 2), 0);
474 ASSERT_EQ(errno, EINVAL);
475
476 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
477 (void *)&large_attr, sizeof(large_attr)), 0);
478
479 large_attr.attr3.attr_set = MOUNT_ATTR_RDONLY;
480 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
481 (void *)&large_attr, sizeof(large_attr)), 0);
482
483 large_attr.attr3.attr_set = 0;
484 large_attr.attr1.attr_set = MOUNT_ATTR_RDONLY;
485 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
486 (void *)&large_attr, sizeof(large_attr)), 0);
487
488 expected_flags = old_flags;
489 expected_flags |= MS_RDONLY;
490
491 new_flags = read_mnt_flags("/mnt/A");
492 ASSERT_EQ(new_flags, expected_flags);
493
494 new_flags = read_mnt_flags("/mnt/A/AA");
495 ASSERT_EQ(new_flags, expected_flags);
496
497 new_flags = read_mnt_flags("/mnt/A/AA/B");
498 ASSERT_EQ(new_flags, expected_flags);
499
500 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
501 ASSERT_EQ(new_flags, expected_flags);
502 }
503
TEST_F(mount_setattr,basic)504 TEST_F(mount_setattr, basic)
505 {
506 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
507 struct mount_attr attr = {
508 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
509 .attr_clr = MOUNT_ATTR__ATIME,
510 };
511
512 if (!mount_setattr_supported())
513 SKIP(return, "mount_setattr syscall not supported");
514
515 old_flags = read_mnt_flags("/mnt/A");
516 ASSERT_GT(old_flags, 0);
517
518 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", 0, &attr, sizeof(attr)), 0);
519
520 expected_flags = old_flags;
521 expected_flags |= MS_RDONLY;
522 expected_flags |= MS_NOEXEC;
523 expected_flags &= ~MS_NOATIME;
524 expected_flags |= MS_RELATIME;
525
526 new_flags = read_mnt_flags("/mnt/A");
527 ASSERT_EQ(new_flags, expected_flags);
528
529 new_flags = read_mnt_flags("/mnt/A/AA");
530 ASSERT_EQ(new_flags, old_flags);
531
532 new_flags = read_mnt_flags("/mnt/A/AA/B");
533 ASSERT_EQ(new_flags, old_flags);
534
535 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
536 ASSERT_EQ(new_flags, old_flags);
537 }
538
TEST_F(mount_setattr,basic_recursive)539 TEST_F(mount_setattr, basic_recursive)
540 {
541 int fd;
542 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
543 struct mount_attr attr = {
544 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
545 .attr_clr = MOUNT_ATTR__ATIME,
546 };
547
548 if (!mount_setattr_supported())
549 SKIP(return, "mount_setattr syscall not supported");
550
551 old_flags = read_mnt_flags("/mnt/A");
552 ASSERT_GT(old_flags, 0);
553
554 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
555
556 expected_flags = old_flags;
557 expected_flags |= MS_RDONLY;
558 expected_flags |= MS_NOEXEC;
559 expected_flags &= ~MS_NOATIME;
560 expected_flags |= MS_RELATIME;
561
562 new_flags = read_mnt_flags("/mnt/A");
563 ASSERT_EQ(new_flags, expected_flags);
564
565 new_flags = read_mnt_flags("/mnt/A/AA");
566 ASSERT_EQ(new_flags, expected_flags);
567
568 new_flags = read_mnt_flags("/mnt/A/AA/B");
569 ASSERT_EQ(new_flags, expected_flags);
570
571 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
572 ASSERT_EQ(new_flags, expected_flags);
573
574 memset(&attr, 0, sizeof(attr));
575 attr.attr_clr = MOUNT_ATTR_RDONLY;
576 attr.propagation = MS_SHARED;
577 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
578
579 expected_flags &= ~MS_RDONLY;
580 new_flags = read_mnt_flags("/mnt/A");
581 ASSERT_EQ(new_flags, expected_flags);
582
583 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
584
585 new_flags = read_mnt_flags("/mnt/A/AA");
586 ASSERT_EQ(new_flags, expected_flags);
587
588 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
589
590 new_flags = read_mnt_flags("/mnt/A/AA/B");
591 ASSERT_EQ(new_flags, expected_flags);
592
593 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
594
595 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
596 ASSERT_EQ(new_flags, expected_flags);
597
598 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
599
600 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
601 ASSERT_GE(fd, 0);
602
603 /*
604 * We're holding a fd open for writing so this needs to fail somewhere
605 * in the middle and the mount options need to be unchanged.
606 */
607 attr.attr_set = MOUNT_ATTR_RDONLY;
608 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
609
610 new_flags = read_mnt_flags("/mnt/A");
611 ASSERT_EQ(new_flags, expected_flags);
612
613 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
614
615 new_flags = read_mnt_flags("/mnt/A/AA");
616 ASSERT_EQ(new_flags, expected_flags);
617
618 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
619
620 new_flags = read_mnt_flags("/mnt/A/AA/B");
621 ASSERT_EQ(new_flags, expected_flags);
622
623 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
624
625 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
626 ASSERT_EQ(new_flags, expected_flags);
627
628 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
629
630 EXPECT_EQ(close(fd), 0);
631 }
632
TEST_F(mount_setattr,mount_has_writers)633 TEST_F(mount_setattr, mount_has_writers)
634 {
635 int fd, dfd;
636 unsigned int old_flags = 0, new_flags = 0;
637 struct mount_attr attr = {
638 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
639 .attr_clr = MOUNT_ATTR__ATIME,
640 .propagation = MS_SHARED,
641 };
642
643 if (!mount_setattr_supported())
644 SKIP(return, "mount_setattr syscall not supported");
645
646 old_flags = read_mnt_flags("/mnt/A");
647 ASSERT_GT(old_flags, 0);
648
649 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
650 ASSERT_GE(fd, 0);
651
652 /*
653 * We're holding a fd open to a mount somwhere in the middle so this
654 * needs to fail somewhere in the middle. After this the mount options
655 * need to be unchanged.
656 */
657 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
658
659 new_flags = read_mnt_flags("/mnt/A");
660 ASSERT_EQ(new_flags, old_flags);
661
662 ASSERT_EQ(is_shared_mount("/mnt/A"), false);
663
664 new_flags = read_mnt_flags("/mnt/A/AA");
665 ASSERT_EQ(new_flags, old_flags);
666
667 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), false);
668
669 new_flags = read_mnt_flags("/mnt/A/AA/B");
670 ASSERT_EQ(new_flags, old_flags);
671
672 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), false);
673
674 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
675 ASSERT_EQ(new_flags, old_flags);
676
677 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), false);
678
679 dfd = open("/mnt/A/AA/B", O_DIRECTORY | O_CLOEXEC);
680 ASSERT_GE(dfd, 0);
681 EXPECT_EQ(fsync(dfd), 0);
682 EXPECT_EQ(close(dfd), 0);
683
684 EXPECT_EQ(fsync(fd), 0);
685 EXPECT_EQ(close(fd), 0);
686
687 /* All writers are gone so this should succeed. */
688 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
689 }
690
TEST_F(mount_setattr,mixed_mount_options)691 TEST_F(mount_setattr, mixed_mount_options)
692 {
693 unsigned int old_flags1 = 0, old_flags2 = 0, new_flags = 0, expected_flags = 0;
694 struct mount_attr attr = {
695 .attr_clr = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME,
696 .attr_set = MOUNT_ATTR_RELATIME,
697 };
698
699 if (!mount_setattr_supported())
700 SKIP(return, "mount_setattr syscall not supported");
701
702 old_flags1 = read_mnt_flags("/mnt/B");
703 ASSERT_GT(old_flags1, 0);
704
705 old_flags2 = read_mnt_flags("/mnt/B/BB");
706 ASSERT_GT(old_flags2, 0);
707
708 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/B", AT_RECURSIVE, &attr, sizeof(attr)), 0);
709
710 expected_flags = old_flags2;
711 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
712 expected_flags |= MS_RELATIME;
713
714 new_flags = read_mnt_flags("/mnt/B");
715 ASSERT_EQ(new_flags, expected_flags);
716
717 expected_flags = old_flags2;
718 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
719 expected_flags |= MS_RELATIME;
720
721 new_flags = read_mnt_flags("/mnt/B/BB");
722 ASSERT_EQ(new_flags, expected_flags);
723 }
724
TEST_F(mount_setattr,time_changes)725 TEST_F(mount_setattr, time_changes)
726 {
727 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
728 struct mount_attr attr = {
729 .attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME,
730 };
731
732 if (!mount_setattr_supported())
733 SKIP(return, "mount_setattr syscall not supported");
734
735 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
736
737 attr.attr_set = MOUNT_ATTR_STRICTATIME;
738 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
739
740 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
741 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
742
743 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
744 attr.attr_clr = MOUNT_ATTR__ATIME;
745 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
746
747 attr.attr_set = 0;
748 attr.attr_clr = MOUNT_ATTR_STRICTATIME;
749 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
750
751 attr.attr_clr = MOUNT_ATTR_NOATIME;
752 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
753
754 old_flags = read_mnt_flags("/mnt/A");
755 ASSERT_GT(old_flags, 0);
756
757 attr.attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME;
758 attr.attr_clr = MOUNT_ATTR__ATIME;
759 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
760
761 expected_flags = old_flags;
762 expected_flags |= MS_NOATIME;
763 expected_flags |= MS_NODIRATIME;
764
765 new_flags = read_mnt_flags("/mnt/A");
766 ASSERT_EQ(new_flags, expected_flags);
767
768 new_flags = read_mnt_flags("/mnt/A/AA");
769 ASSERT_EQ(new_flags, expected_flags);
770
771 new_flags = read_mnt_flags("/mnt/A/AA/B");
772 ASSERT_EQ(new_flags, expected_flags);
773
774 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
775 ASSERT_EQ(new_flags, expected_flags);
776
777 memset(&attr, 0, sizeof(attr));
778 attr.attr_set &= ~MOUNT_ATTR_NOATIME;
779 attr.attr_set |= MOUNT_ATTR_RELATIME;
780 attr.attr_clr |= MOUNT_ATTR__ATIME;
781 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
782
783 expected_flags &= ~MS_NOATIME;
784 expected_flags |= MS_RELATIME;
785
786 new_flags = read_mnt_flags("/mnt/A");
787 ASSERT_EQ(new_flags, expected_flags);
788
789 new_flags = read_mnt_flags("/mnt/A/AA");
790 ASSERT_EQ(new_flags, expected_flags);
791
792 new_flags = read_mnt_flags("/mnt/A/AA/B");
793 ASSERT_EQ(new_flags, expected_flags);
794
795 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
796 ASSERT_EQ(new_flags, expected_flags);
797
798 memset(&attr, 0, sizeof(attr));
799 attr.attr_set &= ~MOUNT_ATTR_RELATIME;
800 attr.attr_set |= MOUNT_ATTR_STRICTATIME;
801 attr.attr_clr |= MOUNT_ATTR__ATIME;
802 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
803
804 expected_flags &= ~MS_RELATIME;
805
806 new_flags = read_mnt_flags("/mnt/A");
807 ASSERT_EQ(new_flags, expected_flags);
808
809 new_flags = read_mnt_flags("/mnt/A/AA");
810 ASSERT_EQ(new_flags, expected_flags);
811
812 new_flags = read_mnt_flags("/mnt/A/AA/B");
813 ASSERT_EQ(new_flags, expected_flags);
814
815 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
816 ASSERT_EQ(new_flags, expected_flags);
817
818 memset(&attr, 0, sizeof(attr));
819 attr.attr_set &= ~MOUNT_ATTR_STRICTATIME;
820 attr.attr_set |= MOUNT_ATTR_NOATIME;
821 attr.attr_clr |= MOUNT_ATTR__ATIME;
822 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
823
824 expected_flags |= MS_NOATIME;
825 new_flags = read_mnt_flags("/mnt/A");
826 ASSERT_EQ(new_flags, expected_flags);
827
828 new_flags = read_mnt_flags("/mnt/A/AA");
829 ASSERT_EQ(new_flags, expected_flags);
830
831 new_flags = read_mnt_flags("/mnt/A/AA/B");
832 ASSERT_EQ(new_flags, expected_flags);
833
834 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
835 ASSERT_EQ(new_flags, expected_flags);
836
837 memset(&attr, 0, sizeof(attr));
838 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
839
840 new_flags = read_mnt_flags("/mnt/A");
841 ASSERT_EQ(new_flags, expected_flags);
842
843 new_flags = read_mnt_flags("/mnt/A/AA");
844 ASSERT_EQ(new_flags, expected_flags);
845
846 new_flags = read_mnt_flags("/mnt/A/AA/B");
847 ASSERT_EQ(new_flags, expected_flags);
848
849 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
850 ASSERT_EQ(new_flags, expected_flags);
851
852 memset(&attr, 0, sizeof(attr));
853 attr.attr_clr = MOUNT_ATTR_NODIRATIME;
854 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
855
856 expected_flags &= ~MS_NODIRATIME;
857
858 new_flags = read_mnt_flags("/mnt/A");
859 ASSERT_EQ(new_flags, expected_flags);
860
861 new_flags = read_mnt_flags("/mnt/A/AA");
862 ASSERT_EQ(new_flags, expected_flags);
863
864 new_flags = read_mnt_flags("/mnt/A/AA/B");
865 ASSERT_EQ(new_flags, expected_flags);
866
867 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
868 ASSERT_EQ(new_flags, expected_flags);
869 }
870
TEST_F(mount_setattr,multi_threaded)871 TEST_F(mount_setattr, multi_threaded)
872 {
873 int i, j, nthreads, ret = 0;
874 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
875 pthread_attr_t pattr;
876 pthread_t threads[DEFAULT_THREADS];
877
878 if (!mount_setattr_supported())
879 SKIP(return, "mount_setattr syscall not supported");
880
881 old_flags = read_mnt_flags("/mnt/A");
882 ASSERT_GT(old_flags, 0);
883
884 /* Try to change mount options from multiple threads. */
885 nthreads = get_nprocs_conf();
886 if (nthreads > DEFAULT_THREADS)
887 nthreads = DEFAULT_THREADS;
888
889 pthread_attr_init(&pattr);
890 for (i = 0; i < nthreads; i++)
891 ASSERT_EQ(pthread_create(&threads[i], &pattr, mount_setattr_thread, NULL), 0);
892
893 for (j = 0; j < i; j++) {
894 void *retptr = NULL;
895
896 EXPECT_EQ(pthread_join(threads[j], &retptr), 0);
897
898 ret += ptr_to_int(retptr);
899 EXPECT_EQ(ret, 0);
900 }
901 pthread_attr_destroy(&pattr);
902
903 ASSERT_EQ(ret, 0);
904
905 expected_flags = old_flags;
906 expected_flags |= MS_RDONLY;
907 expected_flags |= MS_NOSUID;
908 new_flags = read_mnt_flags("/mnt/A");
909 ASSERT_EQ(new_flags, expected_flags);
910
911 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
912
913 new_flags = read_mnt_flags("/mnt/A/AA");
914 ASSERT_EQ(new_flags, expected_flags);
915
916 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
917
918 new_flags = read_mnt_flags("/mnt/A/AA/B");
919 ASSERT_EQ(new_flags, expected_flags);
920
921 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
922
923 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
924 ASSERT_EQ(new_flags, expected_flags);
925
926 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
927 }
928
TEST_F(mount_setattr,wrong_user_namespace)929 TEST_F(mount_setattr, wrong_user_namespace)
930 {
931 int ret;
932 struct mount_attr attr = {
933 .attr_set = MOUNT_ATTR_RDONLY,
934 };
935
936 if (!mount_setattr_supported())
937 SKIP(return, "mount_setattr syscall not supported");
938
939 EXPECT_EQ(create_and_enter_userns(), 0);
940 ret = sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr));
941 ASSERT_LT(ret, 0);
942 ASSERT_EQ(errno, EPERM);
943 }
944
TEST_F(mount_setattr,wrong_mount_namespace)945 TEST_F(mount_setattr, wrong_mount_namespace)
946 {
947 int fd, ret;
948 struct mount_attr attr = {
949 .attr_set = MOUNT_ATTR_RDONLY,
950 };
951
952 if (!mount_setattr_supported())
953 SKIP(return, "mount_setattr syscall not supported");
954
955 fd = open("/mnt/A", O_DIRECTORY | O_CLOEXEC);
956 ASSERT_GE(fd, 0);
957
958 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
959
960 ret = sys_mount_setattr(fd, "", AT_EMPTY_PATH | AT_RECURSIVE, &attr, sizeof(attr));
961 ASSERT_LT(ret, 0);
962 ASSERT_EQ(errno, EINVAL);
963 }
964
FIXTURE(mount_setattr_idmapped)965 FIXTURE(mount_setattr_idmapped) {
966 };
967
FIXTURE_SETUP(mount_setattr_idmapped)968 FIXTURE_SETUP(mount_setattr_idmapped)
969 {
970 int img_fd = -EBADF;
971
972 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
973
974 ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0), 0);
975
976 (void)umount2("/mnt", MNT_DETACH);
977 (void)umount2("/tmp", MNT_DETACH);
978
979 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
980 "size=100000,mode=700"), 0);
981
982 ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
983 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/b", S_IFREG | 0644, 0), 0);
984 ASSERT_EQ(chown("/tmp/B/b", 0, 0), 0);
985
986 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
987 "size=100000,mode=700"), 0);
988
989 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
990 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/BB/b", S_IFREG | 0644, 0), 0);
991 ASSERT_EQ(chown("/tmp/B/BB/b", 0, 0), 0);
992
993 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
994 "size=100000,mode=700"), 0);
995
996 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
997 "size=2m,mode=700"), 0);
998
999 ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
1000
1001 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
1002 "size=100000,mode=700"), 0);
1003
1004 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
1005
1006 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
1007
1008 ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
1009
1010 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
1011 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
1012
1013 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
1014
1015 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
1016 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
1017
1018 ASSERT_EQ(mkdir("/mnt/C", 0777), 0);
1019 ASSERT_EQ(mkdir("/mnt/D", 0777), 0);
1020 img_fd = openat(-EBADF, "/mnt/C/ext4.img", O_CREAT | O_WRONLY, 0600);
1021 ASSERT_GE(img_fd, 0);
1022 ASSERT_EQ(ftruncate(img_fd, 2147483648 /* 2 GB */), 0);
1023 ASSERT_EQ(system("mkfs.ext4 -q /mnt/C/ext4.img"), 0);
1024 ASSERT_EQ(system("mount -o loop -t ext4 /mnt/C/ext4.img /mnt/D/"), 0);
1025 ASSERT_EQ(close(img_fd), 0);
1026 }
1027
FIXTURE_TEARDOWN(mount_setattr_idmapped)1028 FIXTURE_TEARDOWN(mount_setattr_idmapped)
1029 {
1030 (void)umount2("/mnt/A", MNT_DETACH);
1031 (void)umount2("/tmp", MNT_DETACH);
1032 }
1033
1034 /**
1035 * Validate that negative fd values are rejected.
1036 */
TEST_F(mount_setattr_idmapped,invalid_fd_negative)1037 TEST_F(mount_setattr_idmapped, invalid_fd_negative)
1038 {
1039 struct mount_attr attr = {
1040 .attr_set = MOUNT_ATTR_IDMAP,
1041 .userns_fd = -EBADF,
1042 };
1043
1044 if (!mount_setattr_supported())
1045 SKIP(return, "mount_setattr syscall not supported");
1046
1047 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1048 TH_LOG("failure: created idmapped mount with negative fd");
1049 }
1050 }
1051
1052 /**
1053 * Validate that excessively large fd values are rejected.
1054 */
TEST_F(mount_setattr_idmapped,invalid_fd_large)1055 TEST_F(mount_setattr_idmapped, invalid_fd_large)
1056 {
1057 struct mount_attr attr = {
1058 .attr_set = MOUNT_ATTR_IDMAP,
1059 .userns_fd = INT64_MAX,
1060 };
1061
1062 if (!mount_setattr_supported())
1063 SKIP(return, "mount_setattr syscall not supported");
1064
1065 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1066 TH_LOG("failure: created idmapped mount with too large fd value");
1067 }
1068 }
1069
1070 /**
1071 * Validate that closed fd values are rejected.
1072 */
TEST_F(mount_setattr_idmapped,invalid_fd_closed)1073 TEST_F(mount_setattr_idmapped, invalid_fd_closed)
1074 {
1075 int fd;
1076 struct mount_attr attr = {
1077 .attr_set = MOUNT_ATTR_IDMAP,
1078 };
1079
1080 if (!mount_setattr_supported())
1081 SKIP(return, "mount_setattr syscall not supported");
1082
1083 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1084 ASSERT_GE(fd, 0);
1085 ASSERT_GE(close(fd), 0);
1086
1087 attr.userns_fd = fd;
1088 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1089 TH_LOG("failure: created idmapped mount with closed fd");
1090 }
1091 }
1092
1093 /**
1094 * Validate that the initial user namespace is rejected.
1095 */
TEST_F(mount_setattr_idmapped,invalid_fd_initial_userns)1096 TEST_F(mount_setattr_idmapped, invalid_fd_initial_userns)
1097 {
1098 int open_tree_fd = -EBADF;
1099 struct mount_attr attr = {
1100 .attr_set = MOUNT_ATTR_IDMAP,
1101 };
1102
1103 if (!mount_setattr_supported())
1104 SKIP(return, "mount_setattr syscall not supported");
1105
1106 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1107 AT_NO_AUTOMOUNT |
1108 AT_SYMLINK_NOFOLLOW |
1109 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1110 ASSERT_GE(open_tree_fd, 0);
1111
1112 attr.userns_fd = open("/proc/1/ns/user", O_RDONLY | O_CLOEXEC);
1113 ASSERT_GE(attr.userns_fd, 0);
1114 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1115 ASSERT_EQ(errno, EPERM);
1116 ASSERT_EQ(close(attr.userns_fd), 0);
1117 ASSERT_EQ(close(open_tree_fd), 0);
1118 }
1119
map_ids(pid_t pid,unsigned long nsid,unsigned long hostid,unsigned long range)1120 static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid,
1121 unsigned long range)
1122 {
1123 char map[100], procfile[256];
1124
1125 snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid);
1126 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1127 if (write_file(procfile, map, strlen(map)))
1128 return -1;
1129
1130
1131 snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid);
1132 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1133 if (write_file(procfile, map, strlen(map)))
1134 return -1;
1135
1136 return 0;
1137 }
1138
1139 #define __STACK_SIZE (8 * 1024 * 1024)
do_clone(int (* fn)(void *),void * arg,int flags)1140 static pid_t do_clone(int (*fn)(void *), void *arg, int flags)
1141 {
1142 void *stack;
1143
1144 stack = malloc(__STACK_SIZE);
1145 if (!stack)
1146 return -ENOMEM;
1147
1148 #ifdef __ia64__
1149 return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1150 #else
1151 return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1152 #endif
1153 }
1154
get_userns_fd_cb(void * data)1155 static int get_userns_fd_cb(void *data)
1156 {
1157 return kill(getpid(), SIGSTOP);
1158 }
1159
wait_for_pid(pid_t pid)1160 static int wait_for_pid(pid_t pid)
1161 {
1162 int status, ret;
1163
1164 again:
1165 ret = waitpid(pid, &status, 0);
1166 if (ret == -1) {
1167 if (errno == EINTR)
1168 goto again;
1169
1170 return -1;
1171 }
1172
1173 if (!WIFEXITED(status))
1174 return -1;
1175
1176 return WEXITSTATUS(status);
1177 }
1178
get_userns_fd(unsigned long nsid,unsigned long hostid,unsigned long range)1179 static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range)
1180 {
1181 int ret;
1182 pid_t pid;
1183 char path[256];
1184
1185 pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER);
1186 if (pid < 0)
1187 return -errno;
1188
1189 ret = map_ids(pid, nsid, hostid, range);
1190 if (ret < 0)
1191 return ret;
1192
1193 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
1194 ret = open(path, O_RDONLY | O_CLOEXEC);
1195 kill(pid, SIGKILL);
1196 wait_for_pid(pid);
1197 return ret;
1198 }
1199
1200 /**
1201 * Validate that an attached mount in our mount namespace cannot be idmapped.
1202 * (The kernel enforces that the mount's mount namespace and the caller's mount
1203 * namespace match.)
1204 */
TEST_F(mount_setattr_idmapped,attached_mount_inside_current_mount_namespace)1205 TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace)
1206 {
1207 int open_tree_fd = -EBADF;
1208 struct mount_attr attr = {
1209 .attr_set = MOUNT_ATTR_IDMAP,
1210 };
1211
1212 if (!mount_setattr_supported())
1213 SKIP(return, "mount_setattr syscall not supported");
1214
1215 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1216 AT_EMPTY_PATH |
1217 AT_NO_AUTOMOUNT |
1218 AT_SYMLINK_NOFOLLOW |
1219 OPEN_TREE_CLOEXEC);
1220 ASSERT_GE(open_tree_fd, 0);
1221
1222 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1223 ASSERT_GE(attr.userns_fd, 0);
1224 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1225 ASSERT_EQ(close(attr.userns_fd), 0);
1226 ASSERT_EQ(close(open_tree_fd), 0);
1227 }
1228
1229 /**
1230 * Validate that idmapping a mount is rejected if the mount's mount namespace
1231 * and our mount namespace don't match.
1232 * (The kernel enforces that the mount's mount namespace and the caller's mount
1233 * namespace match.)
1234 */
TEST_F(mount_setattr_idmapped,attached_mount_outside_current_mount_namespace)1235 TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace)
1236 {
1237 int open_tree_fd = -EBADF;
1238 struct mount_attr attr = {
1239 .attr_set = MOUNT_ATTR_IDMAP,
1240 };
1241
1242 if (!mount_setattr_supported())
1243 SKIP(return, "mount_setattr syscall not supported");
1244
1245 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1246 AT_EMPTY_PATH |
1247 AT_NO_AUTOMOUNT |
1248 AT_SYMLINK_NOFOLLOW |
1249 OPEN_TREE_CLOEXEC);
1250 ASSERT_GE(open_tree_fd, 0);
1251
1252 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1253
1254 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1255 ASSERT_GE(attr.userns_fd, 0);
1256 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
1257 sizeof(attr)), 0);
1258 ASSERT_EQ(close(attr.userns_fd), 0);
1259 ASSERT_EQ(close(open_tree_fd), 0);
1260 }
1261
1262 /**
1263 * Validate that an attached mount in our mount namespace can be idmapped.
1264 */
TEST_F(mount_setattr_idmapped,detached_mount_inside_current_mount_namespace)1265 TEST_F(mount_setattr_idmapped, detached_mount_inside_current_mount_namespace)
1266 {
1267 int open_tree_fd = -EBADF;
1268 struct mount_attr attr = {
1269 .attr_set = MOUNT_ATTR_IDMAP,
1270 };
1271
1272 if (!mount_setattr_supported())
1273 SKIP(return, "mount_setattr syscall not supported");
1274
1275 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1276 AT_EMPTY_PATH |
1277 AT_NO_AUTOMOUNT |
1278 AT_SYMLINK_NOFOLLOW |
1279 OPEN_TREE_CLOEXEC |
1280 OPEN_TREE_CLONE);
1281 ASSERT_GE(open_tree_fd, 0);
1282
1283 /* Changing mount properties on a detached mount. */
1284 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1285 ASSERT_GE(attr.userns_fd, 0);
1286 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1287 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1288 ASSERT_EQ(close(attr.userns_fd), 0);
1289 ASSERT_EQ(close(open_tree_fd), 0);
1290 }
1291
1292 /**
1293 * Validate that a detached mount not in our mount namespace can be idmapped.
1294 */
TEST_F(mount_setattr_idmapped,detached_mount_outside_current_mount_namespace)1295 TEST_F(mount_setattr_idmapped, detached_mount_outside_current_mount_namespace)
1296 {
1297 int open_tree_fd = -EBADF;
1298 struct mount_attr attr = {
1299 .attr_set = MOUNT_ATTR_IDMAP,
1300 };
1301
1302 if (!mount_setattr_supported())
1303 SKIP(return, "mount_setattr syscall not supported");
1304
1305 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1306 AT_EMPTY_PATH |
1307 AT_NO_AUTOMOUNT |
1308 AT_SYMLINK_NOFOLLOW |
1309 OPEN_TREE_CLOEXEC |
1310 OPEN_TREE_CLONE);
1311 ASSERT_GE(open_tree_fd, 0);
1312
1313 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1314
1315 /* Changing mount properties on a detached mount. */
1316 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1317 ASSERT_GE(attr.userns_fd, 0);
1318 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1319 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1320 ASSERT_EQ(close(attr.userns_fd), 0);
1321 ASSERT_EQ(close(open_tree_fd), 0);
1322 }
1323
1324 /**
1325 * Validate that currently changing the idmapping of an idmapped mount fails.
1326 */
TEST_F(mount_setattr_idmapped,change_idmapping)1327 TEST_F(mount_setattr_idmapped, change_idmapping)
1328 {
1329 int open_tree_fd = -EBADF;
1330 struct mount_attr attr = {
1331 .attr_set = MOUNT_ATTR_IDMAP,
1332 };
1333
1334 if (!mount_setattr_supported())
1335 SKIP(return, "mount_setattr syscall not supported");
1336
1337 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1338 AT_EMPTY_PATH |
1339 AT_NO_AUTOMOUNT |
1340 AT_SYMLINK_NOFOLLOW |
1341 OPEN_TREE_CLOEXEC |
1342 OPEN_TREE_CLONE);
1343 ASSERT_GE(open_tree_fd, 0);
1344
1345 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1346 ASSERT_GE(attr.userns_fd, 0);
1347 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1348 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1349 ASSERT_EQ(close(attr.userns_fd), 0);
1350
1351 /* Change idmapping on a detached mount that is already idmapped. */
1352 attr.userns_fd = get_userns_fd(0, 20000, 10000);
1353 ASSERT_GE(attr.userns_fd, 0);
1354 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1355 ASSERT_EQ(close(attr.userns_fd), 0);
1356 ASSERT_EQ(close(open_tree_fd), 0);
1357 }
1358
expected_uid_gid(int dfd,const char * path,int flags,uid_t expected_uid,gid_t expected_gid)1359 static bool expected_uid_gid(int dfd, const char *path, int flags,
1360 uid_t expected_uid, gid_t expected_gid)
1361 {
1362 int ret;
1363 struct stat st;
1364
1365 ret = fstatat(dfd, path, &st, flags);
1366 if (ret < 0)
1367 return false;
1368
1369 return st.st_uid == expected_uid && st.st_gid == expected_gid;
1370 }
1371
TEST_F(mount_setattr_idmapped,idmap_mount_tree_invalid)1372 TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
1373 {
1374 int open_tree_fd = -EBADF;
1375 struct mount_attr attr = {
1376 .attr_set = MOUNT_ATTR_IDMAP,
1377 };
1378
1379 if (!mount_setattr_supported())
1380 SKIP(return, "mount_setattr syscall not supported");
1381
1382 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1383 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1384
1385 ASSERT_EQ(mount("testing", "/mnt/A", "ramfs", MS_NOATIME | MS_NODEV,
1386 "size=100000,mode=700"), 0);
1387
1388 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
1389
1390 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
1391
1392 open_tree_fd = sys_open_tree(-EBADF, "/mnt/A",
1393 AT_RECURSIVE |
1394 AT_EMPTY_PATH |
1395 AT_NO_AUTOMOUNT |
1396 AT_SYMLINK_NOFOLLOW |
1397 OPEN_TREE_CLOEXEC |
1398 OPEN_TREE_CLONE);
1399 ASSERT_GE(open_tree_fd, 0);
1400
1401 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1402 ASSERT_GE(attr.userns_fd, 0);
1403 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1404 ASSERT_EQ(close(attr.userns_fd), 0);
1405 ASSERT_EQ(close(open_tree_fd), 0);
1406
1407 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1408 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1409 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0);
1410 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0);
1411
1412 (void)umount2("/mnt/A", MNT_DETACH);
1413 }
1414
TEST_F(mount_setattr,mount_attr_nosymfollow)1415 TEST_F(mount_setattr, mount_attr_nosymfollow)
1416 {
1417 int fd;
1418 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
1419 struct mount_attr attr = {
1420 .attr_set = MOUNT_ATTR_NOSYMFOLLOW,
1421 };
1422
1423 if (!mount_setattr_supported())
1424 SKIP(return, "mount_setattr syscall not supported");
1425
1426 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1427 ASSERT_GT(fd, 0);
1428 ASSERT_EQ(close(fd), 0);
1429
1430 old_flags = read_mnt_flags("/mnt/A");
1431 ASSERT_GT(old_flags, 0);
1432
1433 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1434
1435 expected_flags = old_flags;
1436 expected_flags |= ST_NOSYMFOLLOW;
1437
1438 new_flags = read_mnt_flags("/mnt/A");
1439 ASSERT_EQ(new_flags, expected_flags);
1440
1441 new_flags = read_mnt_flags("/mnt/A/AA");
1442 ASSERT_EQ(new_flags, expected_flags);
1443
1444 new_flags = read_mnt_flags("/mnt/A/AA/B");
1445 ASSERT_EQ(new_flags, expected_flags);
1446
1447 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1448 ASSERT_EQ(new_flags, expected_flags);
1449
1450 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1451 ASSERT_LT(fd, 0);
1452 ASSERT_EQ(errno, ELOOP);
1453
1454 attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW;
1455 attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW;
1456
1457 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1458
1459 expected_flags &= ~ST_NOSYMFOLLOW;
1460 new_flags = read_mnt_flags("/mnt/A");
1461 ASSERT_EQ(new_flags, expected_flags);
1462
1463 new_flags = read_mnt_flags("/mnt/A/AA");
1464 ASSERT_EQ(new_flags, expected_flags);
1465
1466 new_flags = read_mnt_flags("/mnt/A/AA/B");
1467 ASSERT_EQ(new_flags, expected_flags);
1468
1469 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1470 ASSERT_EQ(new_flags, expected_flags);
1471
1472 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1473 ASSERT_GT(fd, 0);
1474 ASSERT_EQ(close(fd), 0);
1475 }
1476
TEST_F(mount_setattr,open_tree_detached)1477 TEST_F(mount_setattr, open_tree_detached)
1478 {
1479 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1480 struct statx stx;
1481
1482 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1483 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1484 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1485 OPEN_TREE_CLONE);
1486 ASSERT_GE(fd_tree_base, 0);
1487 /*
1488 * /mnt testing tmpfs
1489 * |-/mnt/A testing tmpfs
1490 * | `-/mnt/A/AA testing tmpfs
1491 * | `-/mnt/A/AA/B testing tmpfs
1492 * | `-/mnt/A/AA/B/BB testing tmpfs
1493 * `-/mnt/B testing ramfs
1494 */
1495 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1496 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1497 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0);
1498 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1499 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0);
1500 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1501 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0);
1502 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1503
1504 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA",
1505 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1506 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1507 OPEN_TREE_CLONE);
1508 ASSERT_GE(fd_tree_subdir, 0);
1509 /*
1510 * /AA testing tmpfs
1511 * `-/AA/B testing tmpfs
1512 * `-/AA/B/BB testing tmpfs
1513 */
1514 ASSERT_EQ(statx(fd_tree_subdir, "B", 0, 0, &stx), 0);
1515 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1516 ASSERT_EQ(statx(fd_tree_subdir, "B/BB", 0, 0, &stx), 0);
1517 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1518
1519 ASSERT_EQ(move_mount(fd_tree_subdir, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1520 /*
1521 * /tmp/target1 testing tmpfs
1522 * `-/tmp/target1/B testing tmpfs
1523 * `-/tmp/target1/B/BB testing tmpfs
1524 */
1525 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, 0, &stx), 0);
1526 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1527 ASSERT_EQ(statx(-EBADF, "/tmp/target1/B", 0, 0, &stx), 0);
1528 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1529 ASSERT_EQ(statx(-EBADF, "/tmp/target1/B/BB", 0, 0, &stx), 0);
1530 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1531
1532 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target2", MOVE_MOUNT_F_EMPTY_PATH), 0);
1533 /*
1534 * /tmp/target2 testing tmpfs
1535 * |-/tmp/target2/A testing tmpfs
1536 * | `-/tmp/target2/A/AA testing tmpfs
1537 * | `-/tmp/target2/A/AA/B testing tmpfs
1538 * | `-/tmp/target2/A/AA/B/BB testing tmpfs
1539 * `-/tmp/target2/B testing ramfs
1540 */
1541 ASSERT_EQ(statx(-EBADF, "/tmp/target2", 0, 0, &stx), 0);
1542 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1543 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A", 0, 0, &stx), 0);
1544 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1545 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA", 0, 0, &stx), 0);
1546 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1547 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA/B", 0, 0, &stx), 0);
1548 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1549 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA/B/BB", 0, 0, &stx), 0);
1550 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1551 ASSERT_EQ(statx(-EBADF, "/tmp/target2/B", 0, 0, &stx), 0);
1552 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1553
1554 EXPECT_EQ(close(fd_tree_base), 0);
1555 EXPECT_EQ(close(fd_tree_subdir), 0);
1556 }
1557
TEST_F(mount_setattr,open_tree_detached_fail)1558 TEST_F(mount_setattr, open_tree_detached_fail)
1559 {
1560 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1561 struct statx stx;
1562
1563 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1564 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1565 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1566 OPEN_TREE_CLONE);
1567 ASSERT_GE(fd_tree_base, 0);
1568 /*
1569 * /mnt testing tmpfs
1570 * |-/mnt/A testing tmpfs
1571 * | `-/mnt/A/AA testing tmpfs
1572 * | `-/mnt/A/AA/B testing tmpfs
1573 * | `-/mnt/A/AA/B/BB testing tmpfs
1574 * `-/mnt/B testing ramfs
1575 */
1576 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1577 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1578 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0);
1579 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1580 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0);
1581 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1582 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0);
1583 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1584
1585 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1586
1587 /*
1588 * The origin mount namespace of the anonymous mount namespace
1589 * of @fd_tree_base doesn't match the caller's mount namespace
1590 * anymore so creation of another detached mounts must fail.
1591 */
1592 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA",
1593 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1594 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1595 OPEN_TREE_CLONE);
1596 ASSERT_LT(fd_tree_subdir, 0);
1597 ASSERT_EQ(errno, EINVAL);
1598 }
1599
TEST_F(mount_setattr,open_tree_detached_fail2)1600 TEST_F(mount_setattr, open_tree_detached_fail2)
1601 {
1602 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1603 struct statx stx;
1604
1605 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1606 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1607 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1608 OPEN_TREE_CLONE);
1609 ASSERT_GE(fd_tree_base, 0);
1610 /*
1611 * /mnt testing tmpfs
1612 * |-/mnt/A testing tmpfs
1613 * | `-/mnt/A/AA testing tmpfs
1614 * | `-/mnt/A/AA/B testing tmpfs
1615 * | `-/mnt/A/AA/B/BB testing tmpfs
1616 * `-/mnt/B testing ramfs
1617 */
1618 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1619 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1620 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0);
1621 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1622 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0);
1623 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1624 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0);
1625 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1626
1627 EXPECT_EQ(create_and_enter_userns(), 0);
1628
1629 /*
1630 * The caller entered a new user namespace. They will have
1631 * CAP_SYS_ADMIN in this user namespace. However, they're still
1632 * located in a mount namespace that is owned by an ancestor
1633 * user namespace in which they hold no privilege. Creating a
1634 * detached mount must thus fail.
1635 */
1636 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA",
1637 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1638 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1639 OPEN_TREE_CLONE);
1640 ASSERT_LT(fd_tree_subdir, 0);
1641 ASSERT_EQ(errno, EPERM);
1642 }
1643
TEST_F(mount_setattr,open_tree_detached_fail3)1644 TEST_F(mount_setattr, open_tree_detached_fail3)
1645 {
1646 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1647 struct statx stx;
1648
1649 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1650 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1651 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1652 OPEN_TREE_CLONE);
1653 ASSERT_GE(fd_tree_base, 0);
1654 /*
1655 * /mnt testing tmpfs
1656 * |-/mnt/A testing tmpfs
1657 * | `-/mnt/A/AA testing tmpfs
1658 * | `-/mnt/A/AA/B testing tmpfs
1659 * | `-/mnt/A/AA/B/BB testing tmpfs
1660 * `-/mnt/B testing ramfs
1661 */
1662 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1663 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1664 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0);
1665 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1666 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0);
1667 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1668 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0);
1669 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1670
1671 EXPECT_EQ(prepare_unpriv_mountns(), 0);
1672
1673 /*
1674 * The caller entered a new mount namespace. They will have
1675 * CAP_SYS_ADMIN in the owning user namespace of their mount
1676 * namespace.
1677 *
1678 * However, the origin mount namespace of the anonymous mount
1679 * namespace of @fd_tree_base doesn't match the caller's mount
1680 * namespace anymore so creation of another detached mounts must
1681 * fail.
1682 */
1683 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA",
1684 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1685 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1686 OPEN_TREE_CLONE);
1687 ASSERT_LT(fd_tree_subdir, 0);
1688 ASSERT_EQ(errno, EINVAL);
1689 }
1690
TEST_F(mount_setattr,open_tree_subfolder)1691 TEST_F(mount_setattr, open_tree_subfolder)
1692 {
1693 int fd_context, fd_tmpfs, fd_tree;
1694
1695 fd_context = sys_fsopen("tmpfs", 0);
1696 ASSERT_GE(fd_context, 0);
1697
1698 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
1699
1700 fd_tmpfs = sys_fsmount(fd_context, 0, 0);
1701 ASSERT_GE(fd_tmpfs, 0);
1702
1703 EXPECT_EQ(close(fd_context), 0);
1704
1705 ASSERT_EQ(mkdirat(fd_tmpfs, "subdir", 0755), 0);
1706
1707 fd_tree = sys_open_tree(fd_tmpfs, "subdir",
1708 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1709 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1710 OPEN_TREE_CLONE);
1711 ASSERT_GE(fd_tree, 0);
1712
1713 EXPECT_EQ(close(fd_tmpfs), 0);
1714
1715 ASSERT_EQ(mkdirat(-EBADF, "/mnt/open_tree_subfolder", 0755), 0);
1716
1717 ASSERT_EQ(sys_move_mount(fd_tree, "", -EBADF, "/mnt/open_tree_subfolder", MOVE_MOUNT_F_EMPTY_PATH), 0);
1718
1719 EXPECT_EQ(close(fd_tree), 0);
1720
1721 ASSERT_EQ(umount2("/mnt/open_tree_subfolder", 0), 0);
1722
1723 EXPECT_EQ(rmdir("/mnt/open_tree_subfolder"), 0);
1724 }
1725
TEST_F(mount_setattr,mount_detached_mount_on_detached_mount_then_close)1726 TEST_F(mount_setattr, mount_detached_mount_on_detached_mount_then_close)
1727 {
1728 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1729 struct statx stx;
1730
1731 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1732 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1733 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1734 ASSERT_GE(fd_tree_base, 0);
1735 /*
1736 * /mnt testing tmpfs
1737 */
1738 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1739 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1740
1741 fd_tree_subdir = sys_open_tree(fd_tree_base, "",
1742 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1743 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC |
1744 OPEN_TREE_CLONE);
1745 ASSERT_GE(fd_tree_subdir, 0);
1746 /*
1747 * /mnt testing tmpfs
1748 */
1749 ASSERT_EQ(statx(fd_tree_subdir, "A", 0, 0, &stx), 0);
1750 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1751
1752 /*
1753 * /mnt testing tmpfs
1754 * `-/mnt testing tmpfs
1755 */
1756 ASSERT_EQ(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1757 ASSERT_EQ(statx(fd_tree_subdir, "", AT_EMPTY_PATH, 0, &stx), 0);
1758 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1759
1760 ASSERT_NE(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1761
1762 EXPECT_EQ(close(fd_tree_base), 0);
1763 EXPECT_EQ(close(fd_tree_subdir), 0);
1764 }
1765
TEST_F(mount_setattr,mount_detached_mount_on_detached_mount_and_attach)1766 TEST_F(mount_setattr, mount_detached_mount_on_detached_mount_and_attach)
1767 {
1768 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1769 struct statx stx;
1770 __u64 mnt_id = 0;
1771
1772 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1773 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1774 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1775 ASSERT_GE(fd_tree_base, 0);
1776 /*
1777 * /mnt testing tmpfs
1778 */
1779 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1780 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1781
1782 fd_tree_subdir = sys_open_tree(fd_tree_base, "",
1783 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1784 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC |
1785 OPEN_TREE_CLONE);
1786 ASSERT_GE(fd_tree_subdir, 0);
1787 /*
1788 * /mnt testing tmpfs
1789 */
1790 ASSERT_EQ(statx(fd_tree_subdir, "A", 0, 0, &stx), 0);
1791 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1792
1793 /*
1794 * /mnt testing tmpfs
1795 * `-/mnt testing tmpfs
1796 */
1797 ASSERT_EQ(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1798 ASSERT_EQ(statx(fd_tree_subdir, "", AT_EMPTY_PATH, STATX_MNT_ID_UNIQUE, &stx), 0);
1799 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1800 ASSERT_TRUE(stx.stx_mask & STATX_MNT_ID_UNIQUE);
1801 mnt_id = stx.stx_mnt_id;
1802
1803 ASSERT_NE(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1804
1805 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1806 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, STATX_MNT_ID_UNIQUE, &stx), 0);
1807 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1808 ASSERT_TRUE(stx.stx_mask & STATX_MNT_ID_UNIQUE);
1809 ASSERT_EQ(stx.stx_mnt_id, mnt_id);
1810
1811 EXPECT_EQ(close(fd_tree_base), 0);
1812 EXPECT_EQ(close(fd_tree_subdir), 0);
1813 }
1814
TEST_F(mount_setattr,move_mount_detached_fail)1815 TEST_F(mount_setattr, move_mount_detached_fail)
1816 {
1817 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF;
1818 struct statx stx;
1819
1820 fd_tree_base = sys_open_tree(-EBADF, "/mnt",
1821 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1822 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1823 ASSERT_GE(fd_tree_base, 0);
1824
1825 /* Attach the mount to the caller's mount namespace. */
1826 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1827
1828 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0);
1829 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1830
1831 fd_tree_subdir = sys_open_tree(-EBADF, "/tmp/B",
1832 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1833 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1834 ASSERT_GE(fd_tree_subdir, 0);
1835 ASSERT_EQ(statx(fd_tree_subdir, "BB", 0, 0, &stx), 0);
1836 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1837
1838 /* Not allowed to move an attached mount to a detached mount. */
1839 ASSERT_NE(move_mount(fd_tree_base, "", fd_tree_subdir, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1840 ASSERT_EQ(errno, EINVAL);
1841
1842 EXPECT_EQ(close(fd_tree_base), 0);
1843 EXPECT_EQ(close(fd_tree_subdir), 0);
1844 }
1845
TEST_F(mount_setattr,attach_detached_mount_then_umount_then_close)1846 TEST_F(mount_setattr, attach_detached_mount_then_umount_then_close)
1847 {
1848 int fd_tree = -EBADF;
1849 struct statx stx;
1850
1851 fd_tree = sys_open_tree(-EBADF, "/mnt",
1852 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1853 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1854 OPEN_TREE_CLONE);
1855 ASSERT_GE(fd_tree, 0);
1856
1857 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx), 0);
1858 /* We copied with AT_RECURSIVE so /mnt/A must be a mountpoint. */
1859 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1860
1861 /* Attach the mount to the caller's mount namespace. */
1862 ASSERT_EQ(move_mount(fd_tree, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1863
1864 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, 0, &stx), 0);
1865 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT);
1866
1867 ASSERT_EQ(umount2("/tmp/target1", MNT_DETACH), 0);
1868
1869 /*
1870 * This tests whether dissolve_on_fput() handles a NULL mount
1871 * namespace correctly, i.e., that it doesn't splat.
1872 */
1873 EXPECT_EQ(close(fd_tree), 0);
1874 }
1875
TEST_F(mount_setattr,mount_detached1_onto_detached2_then_close_detached1_then_mount_detached2_onto_attached)1876 TEST_F(mount_setattr, mount_detached1_onto_detached2_then_close_detached1_then_mount_detached2_onto_attached)
1877 {
1878 int fd_tree1 = -EBADF, fd_tree2 = -EBADF;
1879
1880 /*
1881 * |-/mnt/A testing tmpfs
1882 * `-/mnt/A/AA testing tmpfs
1883 * `-/mnt/A/AA/B testing tmpfs
1884 * `-/mnt/A/AA/B/BB testing tmpfs
1885 */
1886 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A",
1887 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1888 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1889 OPEN_TREE_CLONE);
1890 ASSERT_GE(fd_tree1, 0);
1891
1892 /*
1893 * `-/mnt/B testing ramfs
1894 */
1895 fd_tree2 = sys_open_tree(-EBADF, "/mnt/B",
1896 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1897 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC |
1898 OPEN_TREE_CLONE);
1899 ASSERT_GE(fd_tree2, 0);
1900
1901 /*
1902 * Move the source detached mount tree to the target detached
1903 * mount tree. This will move all the mounts in the source mount
1904 * tree from the source anonymous mount namespace to the target
1905 * anonymous mount namespace.
1906 *
1907 * The source detached mount tree and the target detached mount
1908 * tree now both refer to the same anonymous mount namespace.
1909 *
1910 * |-"" testing ramfs
1911 * `-"" testing tmpfs
1912 * `-""/AA testing tmpfs
1913 * `-""/AA/B testing tmpfs
1914 * `-""/AA/B/BB testing tmpfs
1915 */
1916 ASSERT_EQ(move_mount(fd_tree1, "", fd_tree2, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
1917
1918 /*
1919 * The source detached mount tree @fd_tree1 is now an attached
1920 * mount, i.e., it has a parent. Specifically, it now has the
1921 * root mount of the mount tree of @fd_tree2 as its parent.
1922 *
1923 * That means we are no longer allowed to attach it as we only
1924 * allow attaching the root of an anonymous mount tree, not
1925 * random bits and pieces. Verify that the kernel enforces this.
1926 */
1927 ASSERT_NE(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1928
1929 /*
1930 * Closing the source detached mount tree must not unmount and
1931 * free the shared anonymous mount namespace. The kernel will
1932 * quickly yell at us because the anonymous mount namespace
1933 * won't be empty when it's freed.
1934 */
1935 EXPECT_EQ(close(fd_tree1), 0);
1936
1937 /*
1938 * Attach the mount tree to a non-anonymous mount namespace.
1939 * This can only succeed if closing fd_tree1 had proper
1940 * semantics and didn't cause the anonymous mount namespace to
1941 * be freed. If it did this will trigger a UAF which will be
1942 * visible on any KASAN enabled kernel.
1943 *
1944 * |-/tmp/target1 testing ramfs
1945 * `-/tmp/target1 testing tmpfs
1946 * `-/tmp/target1/AA testing tmpfs
1947 * `-/tmp/target1/AA/B testing tmpfs
1948 * `-/tmp/target1/AA/B/BB testing tmpfs
1949 */
1950 ASSERT_EQ(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1951 EXPECT_EQ(close(fd_tree2), 0);
1952 }
1953
TEST_F(mount_setattr,two_detached_mounts_referring_to_same_anonymous_mount_namespace)1954 TEST_F(mount_setattr, two_detached_mounts_referring_to_same_anonymous_mount_namespace)
1955 {
1956 int fd_tree1 = -EBADF, fd_tree2 = -EBADF;
1957
1958 /*
1959 * Copy the following mount tree:
1960 *
1961 * |-/mnt/A testing tmpfs
1962 * `-/mnt/A/AA testing tmpfs
1963 * `-/mnt/A/AA/B testing tmpfs
1964 * `-/mnt/A/AA/B/BB testing tmpfs
1965 */
1966 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A",
1967 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1968 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
1969 OPEN_TREE_CLONE);
1970 ASSERT_GE(fd_tree1, 0);
1971
1972 /*
1973 * Create an O_PATH file descriptors with a separate struct file
1974 * that refers to the same detached mount tree as @fd_tree1
1975 */
1976 fd_tree2 = sys_open_tree(fd_tree1, "",
1977 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
1978 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC);
1979 ASSERT_GE(fd_tree2, 0);
1980
1981 /*
1982 * Copy the following mount tree:
1983 *
1984 * |-/tmp/target1 testing tmpfs
1985 * `-/tmp/target1/AA testing tmpfs
1986 * `-/tmp/target1/AA/B testing tmpfs
1987 * `-/tmp/target1/AA/B/BB testing tmpfs
1988 */
1989 ASSERT_EQ(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1990
1991 /*
1992 * This must fail as this would mean adding the same mount tree
1993 * into the same mount tree.
1994 */
1995 ASSERT_NE(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
1996 }
1997
TEST_F(mount_setattr,two_detached_subtrees_of_same_anonymous_mount_namespace)1998 TEST_F(mount_setattr, two_detached_subtrees_of_same_anonymous_mount_namespace)
1999 {
2000 int fd_tree1 = -EBADF, fd_tree2 = -EBADF;
2001
2002 /*
2003 * Copy the following mount tree:
2004 *
2005 * |-/mnt/A testing tmpfs
2006 * `-/mnt/A/AA testing tmpfs
2007 * `-/mnt/A/AA/B testing tmpfs
2008 * `-/mnt/A/AA/B/BB testing tmpfs
2009 */
2010 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A",
2011 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
2012 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
2013 OPEN_TREE_CLONE);
2014 ASSERT_GE(fd_tree1, 0);
2015
2016 /*
2017 * Create an O_PATH file descriptors with a separate struct file that
2018 * refers to a subtree of the same detached mount tree as @fd_tree1
2019 */
2020 fd_tree2 = sys_open_tree(fd_tree1, "AA",
2021 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
2022 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC);
2023 ASSERT_GE(fd_tree2, 0);
2024
2025 /*
2026 * This must fail as it is only possible to attach the root of a
2027 * detached mount tree.
2028 */
2029 ASSERT_NE(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
2030
2031 ASSERT_EQ(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0);
2032 }
2033
TEST_F(mount_setattr,detached_tree_propagation)2034 TEST_F(mount_setattr, detached_tree_propagation)
2035 {
2036 int fd_tree = -EBADF;
2037 struct statx stx1, stx2, stx3, stx4;
2038
2039 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
2040 ASSERT_EQ(mount(NULL, "/mnt", NULL, MS_REC | MS_SHARED, NULL), 0);
2041
2042 /*
2043 * Copy the following mount tree:
2044 *
2045 * /mnt testing tmpfs
2046 * |-/mnt/A testing tmpfs
2047 * | `-/mnt/A/AA testing tmpfs
2048 * | `-/mnt/A/AA/B testing tmpfs
2049 * | `-/mnt/A/AA/B/BB testing tmpfs
2050 * `-/mnt/B testing ramfs
2051 */
2052 fd_tree = sys_open_tree(-EBADF, "/mnt",
2053 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
2054 AT_RECURSIVE | OPEN_TREE_CLOEXEC |
2055 OPEN_TREE_CLONE);
2056 ASSERT_GE(fd_tree, 0);
2057
2058 ASSERT_EQ(statx(-EBADF, "/mnt/A", 0, 0, &stx1), 0);
2059 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx2), 0);
2060
2061 /*
2062 * Copying the mount namespace like done above doesn't alter the
2063 * mounts in any way so the filesystem mounted on /mnt must be
2064 * identical even though the mounts will differ. Use the device
2065 * information to verify that. Note that tmpfs will have a 0
2066 * major number so comparing the major number is misleading.
2067 */
2068 ASSERT_EQ(stx1.stx_dev_minor, stx2.stx_dev_minor);
2069
2070 /* Mount a tmpfs filesystem over /mnt/A. */
2071 ASSERT_EQ(mount(NULL, "/mnt/A", "tmpfs", 0, NULL), 0);
2072
2073
2074 ASSERT_EQ(statx(-EBADF, "/mnt/A", 0, 0, &stx3), 0);
2075 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx4), 0);
2076
2077 /*
2078 * A new filesystem has been mounted on top of /mnt/A which
2079 * means that the device information will be different for any
2080 * statx() that was taken from /mnt/A before the mount compared
2081 * to one after the mount.
2082 */
2083 ASSERT_NE(stx1.stx_dev_minor, stx3.stx_dev_minor);
2084 ASSERT_EQ(stx1.stx_dev_minor, stx4.stx_dev_minor);
2085
2086 EXPECT_EQ(close(fd_tree), 0);
2087 }
2088
2089 TEST_HARNESS_MAIN
2090