1
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
22#include "../kselftest_harness.h"
23
24#ifndef CLONE_NEWNS
25#define CLONE_NEWNS 0x00020000
26#endif
27
28#ifndef CLONE_NEWUSER
29#define CLONE_NEWUSER 0x10000000
30#endif
31
32#ifndef MS_REC
33#define MS_REC 16384
34#endif
35
36#ifndef MS_RELATIME
37#define MS_RELATIME (1 << 21)
38#endif
39
40#ifndef MS_STRICTATIME
41#define MS_STRICTATIME (1 << 24)
42#endif
43
44#ifndef MOUNT_ATTR_RDONLY
45#define MOUNT_ATTR_RDONLY 0x00000001
46#endif
47
48#ifndef MOUNT_ATTR_NOSUID
49#define MOUNT_ATTR_NOSUID 0x00000002
50#endif
51
52#ifndef MOUNT_ATTR_NOEXEC
53#define MOUNT_ATTR_NOEXEC 0x00000008
54#endif
55
56#ifndef MOUNT_ATTR_NODIRATIME
57#define MOUNT_ATTR_NODIRATIME 0x00000080
58#endif
59
60#ifndef MOUNT_ATTR__ATIME
61#define MOUNT_ATTR__ATIME 0x00000070
62#endif
63
64#ifndef MOUNT_ATTR_RELATIME
65#define MOUNT_ATTR_RELATIME 0x00000000
66#endif
67
68#ifndef MOUNT_ATTR_NOATIME
69#define MOUNT_ATTR_NOATIME 0x00000010
70#endif
71
72#ifndef MOUNT_ATTR_STRICTATIME
73#define MOUNT_ATTR_STRICTATIME 0x00000020
74#endif
75
76#ifndef AT_RECURSIVE
77#define AT_RECURSIVE 0x8000
78#endif
79
80#ifndef MS_SHARED
81#define MS_SHARED (1 << 20)
82#endif
83
84#define DEFAULT_THREADS 4
85#define ptr_to_int(p) ((int)((intptr_t)(p)))
86#define int_to_ptr(u) ((void *)((intptr_t)(u)))
87
88#ifndef __NR_mount_setattr
89 #if defined __alpha__
90 #define __NR_mount_setattr 552
91 #elif defined _MIPS_SIM
92 #if _MIPS_SIM == _MIPS_SIM_ABI32
93 #define __NR_mount_setattr (442 + 4000)
94 #endif
95 #if _MIPS_SIM == _MIPS_SIM_NABI32
96 #define __NR_mount_setattr (442 + 6000)
97 #endif
98 #if _MIPS_SIM == _MIPS_SIM_ABI64
99 #define __NR_mount_setattr (442 + 5000)
100 #endif
101 #elif defined __ia64__
102 #define __NR_mount_setattr (442 + 1024)
103 #else
104 #define __NR_mount_setattr 442
105 #endif
106
107struct mount_attr {
108 __u64 attr_set;
109 __u64 attr_clr;
110 __u64 propagation;
111 __u64 userns_fd;
112};
113#endif
114
115#ifndef __NR_open_tree
116 #if defined __alpha__
117 #define __NR_open_tree 538
118 #elif defined _MIPS_SIM
119 #if _MIPS_SIM == _MIPS_SIM_ABI32
120 #define __NR_open_tree 4428
121 #endif
122 #if _MIPS_SIM == _MIPS_SIM_NABI32
123 #define __NR_open_tree 6428
124 #endif
125 #if _MIPS_SIM == _MIPS_SIM_ABI64
126 #define __NR_open_tree 5428
127 #endif
128 #elif defined __ia64__
129 #define __NR_open_tree (428 + 1024)
130 #else
131 #define __NR_open_tree 428
132 #endif
133#endif
134
135#ifndef MOUNT_ATTR_IDMAP
136#define MOUNT_ATTR_IDMAP 0x00100000
137#endif
138
139#ifndef MOUNT_ATTR_NOSYMFOLLOW
140#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
141#endif
142
143static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags,
144 struct mount_attr *attr, size_t size)
145{
146 return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
147}
148
149#ifndef OPEN_TREE_CLONE
150#define OPEN_TREE_CLONE 1
151#endif
152
153#ifndef OPEN_TREE_CLOEXEC
154#define OPEN_TREE_CLOEXEC O_CLOEXEC
155#endif
156
157#ifndef AT_RECURSIVE
158#define AT_RECURSIVE 0x8000
159#endif
160
161static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
162{
163 return syscall(__NR_open_tree, dfd, filename, flags);
164}
165
166static ssize_t write_nointr(int fd, const void *buf, size_t count)
167{
168 ssize_t ret;
169
170 do {
171 ret = write(fd, buf, count);
172 } while (ret < 0 && errno == EINTR);
173
174 return ret;
175}
176
177static int write_file(const char *path, const void *buf, size_t count)
178{
179 int fd;
180 ssize_t ret;
181
182 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
183 if (fd < 0)
184 return -1;
185
186 ret = write_nointr(fd, buf, count);
187 close(fd);
188 if (ret < 0 || (size_t)ret != count)
189 return -1;
190
191 return 0;
192}
193
194static int create_and_enter_userns(void)
195{
196 uid_t uid;
197 gid_t gid;
198 char map[100];
199
200 uid = getuid();
201 gid = getgid();
202
203 if (unshare(CLONE_NEWUSER))
204 return -1;
205
206 if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
207 errno != ENOENT)
208 return -1;
209
210 snprintf(map, sizeof(map), "0 %d 1", uid);
211 if (write_file("/proc/self/uid_map", map, strlen(map)))
212 return -1;
213
214
215 snprintf(map, sizeof(map), "0 %d 1", gid);
216 if (write_file("/proc/self/gid_map", map, strlen(map)))
217 return -1;
218
219 if (setgid(0))
220 return -1;
221
222 if (setuid(0))
223 return -1;
224
225 return 0;
226}
227
228static int prepare_unpriv_mountns(void)
229{
230 if (create_and_enter_userns())
231 return -1;
232
233 if (unshare(CLONE_NEWNS))
234 return -1;
235
236 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
237 return -1;
238
239 return 0;
240}
241
242#ifndef ST_NOSYMFOLLOW
243#define ST_NOSYMFOLLOW 0x2000
244#endif
245
246static int read_mnt_flags(const char *path)
247{
248 int ret;
249 struct statvfs stat;
250 unsigned int mnt_flags;
251
252 ret = statvfs(path, &stat);
253 if (ret != 0)
254 return -EINVAL;
255
256 if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC |
257 ST_NOATIME | ST_NODIRATIME | ST_RELATIME |
258 ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW))
259 return -EINVAL;
260
261 mnt_flags = 0;
262 if (stat.f_flag & ST_RDONLY)
263 mnt_flags |= MS_RDONLY;
264 if (stat.f_flag & ST_NOSUID)
265 mnt_flags |= MS_NOSUID;
266 if (stat.f_flag & ST_NODEV)
267 mnt_flags |= MS_NODEV;
268 if (stat.f_flag & ST_NOEXEC)
269 mnt_flags |= MS_NOEXEC;
270 if (stat.f_flag & ST_NOATIME)
271 mnt_flags |= MS_NOATIME;
272 if (stat.f_flag & ST_NODIRATIME)
273 mnt_flags |= MS_NODIRATIME;
274 if (stat.f_flag & ST_RELATIME)
275 mnt_flags |= MS_RELATIME;
276 if (stat.f_flag & ST_SYNCHRONOUS)
277 mnt_flags |= MS_SYNCHRONOUS;
278 if (stat.f_flag & ST_MANDLOCK)
279 mnt_flags |= ST_MANDLOCK;
280 if (stat.f_flag & ST_NOSYMFOLLOW)
281 mnt_flags |= ST_NOSYMFOLLOW;
282
283 return mnt_flags;
284}
285
286static char *get_field(char *src, int nfields)
287{
288 int i;
289 char *p = src;
290
291 for (i = 0; i < nfields; i++) {
292 while (*p && *p != ' ' && *p != '\t')
293 p++;
294
295 if (!*p)
296 break;
297
298 p++;
299 }
300
301 return p;
302}
303
304static void null_endofword(char *word)
305{
306 while (*word && *word != ' ' && *word != '\t')
307 word++;
308 *word = '\0';
309}
310
311static bool is_shared_mount(const char *path)
312{
313 size_t len = 0;
314 char *line = NULL;
315 FILE *f = NULL;
316
317 f = fopen("/proc/self/mountinfo", "re");
318 if (!f)
319 return false;
320
321 while (getline(&line, &len, f) != -1) {
322 char *opts, *target;
323
324 target = get_field(line, 4);
325 if (!target)
326 continue;
327
328 opts = get_field(target, 2);
329 if (!opts)
330 continue;
331
332 null_endofword(target);
333
334 if (strcmp(target, path) != 0)
335 continue;
336
337 null_endofword(opts);
338 if (strstr(opts, "shared:"))
339 return true;
340 }
341
342 free(line);
343 fclose(f);
344
345 return false;
346}
347
348static void *mount_setattr_thread(void *data)
349{
350 struct mount_attr attr = {
351 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID,
352 .attr_clr = 0,
353 .propagation = MS_SHARED,
354 };
355
356 if (sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)))
357 pthread_exit(int_to_ptr(-1));
358
359 pthread_exit(int_to_ptr(0));
360}
361
362
363#ifndef SKIP
364#define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__)
365#endif
366
367static bool mount_setattr_supported(void)
368{
369 int ret;
370
371 ret = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0);
372 if (ret < 0 && errno == ENOSYS)
373 return false;
374
375 return true;
376}
377
378FIXTURE(mount_setattr) {
379};
380
381#define NOSYMFOLLOW_TARGET "/mnt/A/AA/data"
382#define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink"
383
384FIXTURE_SETUP(mount_setattr)
385{
386 int fd = -EBADF;
387
388 if (!mount_setattr_supported())
389 SKIP(return, "mount_setattr syscall not supported");
390
391 ASSERT_EQ(prepare_unpriv_mountns(), 0);
392
393 (void)umount2("/mnt", MNT_DETACH);
394 (void)umount2("/tmp", MNT_DETACH);
395
396 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
397 "size=100000,mode=700"), 0);
398
399 ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
400
401 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
402 "size=100000,mode=700"), 0);
403
404 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
405
406 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
407 "size=100000,mode=700"), 0);
408
409 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
410 "size=100000,mode=700"), 0);
411
412 ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
413
414 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
415 "size=100000,mode=700"), 0);
416
417 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
418
419 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
420
421 ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
422
423 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
424 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
425
426 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
427
428 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
429 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
430
431 fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC);
432 ASSERT_GT(fd, 0);
433 ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0);
434 ASSERT_EQ(close(fd), 0);
435}
436
437FIXTURE_TEARDOWN(mount_setattr)
438{
439 if (!mount_setattr_supported())
440 SKIP(return, "mount_setattr syscall not supported");
441
442 (void)umount2("/mnt/A", MNT_DETACH);
443 (void)umount2("/tmp", MNT_DETACH);
444}
445
446TEST_F(mount_setattr, invalid_attributes)
447{
448 struct mount_attr invalid_attr = {
449 .attr_set = (1U << 31),
450 };
451
452 if (!mount_setattr_supported())
453 SKIP(return, "mount_setattr syscall not supported");
454
455 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
456 sizeof(invalid_attr)), 0);
457
458 invalid_attr.attr_set = 0;
459 invalid_attr.attr_clr = (1U << 31);
460 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
461 sizeof(invalid_attr)), 0);
462
463 invalid_attr.attr_clr = 0;
464 invalid_attr.propagation = (1U << 31);
465 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
466 sizeof(invalid_attr)), 0);
467
468 invalid_attr.attr_set = (1U << 31);
469 invalid_attr.attr_clr = (1U << 31);
470 invalid_attr.propagation = (1U << 31);
471 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
472 sizeof(invalid_attr)), 0);
473
474 ASSERT_NE(sys_mount_setattr(-1, "mnt/A", AT_RECURSIVE, &invalid_attr,
475 sizeof(invalid_attr)), 0);
476}
477
478TEST_F(mount_setattr, extensibility)
479{
480 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
481 char *s = "dummy";
482 struct mount_attr invalid_attr = {};
483 struct mount_attr_large {
484 struct mount_attr attr1;
485 struct mount_attr attr2;
486 struct mount_attr attr3;
487 } large_attr = {};
488
489 if (!mount_setattr_supported())
490 SKIP(return, "mount_setattr syscall not supported");
491
492 old_flags = read_mnt_flags("/mnt/A");
493 ASSERT_GT(old_flags, 0);
494
495 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, NULL,
496 sizeof(invalid_attr)), 0);
497 ASSERT_EQ(errno, EFAULT);
498
499 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, (void *)s,
500 sizeof(invalid_attr)), 0);
501 ASSERT_EQ(errno, EINVAL);
502
503 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 0), 0);
504 ASSERT_EQ(errno, EINVAL);
505
506 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
507 sizeof(invalid_attr) / 2), 0);
508 ASSERT_EQ(errno, EINVAL);
509
510 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr,
511 sizeof(invalid_attr) / 2), 0);
512 ASSERT_EQ(errno, EINVAL);
513
514 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
515 (void *)&large_attr, sizeof(large_attr)), 0);
516
517 large_attr.attr3.attr_set = MOUNT_ATTR_RDONLY;
518 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
519 (void *)&large_attr, sizeof(large_attr)), 0);
520
521 large_attr.attr3.attr_set = 0;
522 large_attr.attr1.attr_set = MOUNT_ATTR_RDONLY;
523 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE,
524 (void *)&large_attr, sizeof(large_attr)), 0);
525
526 expected_flags = old_flags;
527 expected_flags |= MS_RDONLY;
528
529 new_flags = read_mnt_flags("/mnt/A");
530 ASSERT_EQ(new_flags, expected_flags);
531
532 new_flags = read_mnt_flags("/mnt/A/AA");
533 ASSERT_EQ(new_flags, expected_flags);
534
535 new_flags = read_mnt_flags("/mnt/A/AA/B");
536 ASSERT_EQ(new_flags, expected_flags);
537
538 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
539 ASSERT_EQ(new_flags, expected_flags);
540}
541
542TEST_F(mount_setattr, basic)
543{
544 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
545 struct mount_attr attr = {
546 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
547 .attr_clr = MOUNT_ATTR__ATIME,
548 };
549
550 if (!mount_setattr_supported())
551 SKIP(return, "mount_setattr syscall not supported");
552
553 old_flags = read_mnt_flags("/mnt/A");
554 ASSERT_GT(old_flags, 0);
555
556 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", 0, &attr, sizeof(attr)), 0);
557
558 expected_flags = old_flags;
559 expected_flags |= MS_RDONLY;
560 expected_flags |= MS_NOEXEC;
561 expected_flags &= ~MS_NOATIME;
562 expected_flags |= MS_RELATIME;
563
564 new_flags = read_mnt_flags("/mnt/A");
565 ASSERT_EQ(new_flags, expected_flags);
566
567 new_flags = read_mnt_flags("/mnt/A/AA");
568 ASSERT_EQ(new_flags, old_flags);
569
570 new_flags = read_mnt_flags("/mnt/A/AA/B");
571 ASSERT_EQ(new_flags, old_flags);
572
573 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
574 ASSERT_EQ(new_flags, old_flags);
575}
576
577TEST_F(mount_setattr, basic_recursive)
578{
579 int fd;
580 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
581 struct mount_attr attr = {
582 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
583 .attr_clr = MOUNT_ATTR__ATIME,
584 };
585
586 if (!mount_setattr_supported())
587 SKIP(return, "mount_setattr syscall not supported");
588
589 old_flags = read_mnt_flags("/mnt/A");
590 ASSERT_GT(old_flags, 0);
591
592 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
593
594 expected_flags = old_flags;
595 expected_flags |= MS_RDONLY;
596 expected_flags |= MS_NOEXEC;
597 expected_flags &= ~MS_NOATIME;
598 expected_flags |= MS_RELATIME;
599
600 new_flags = read_mnt_flags("/mnt/A");
601 ASSERT_EQ(new_flags, expected_flags);
602
603 new_flags = read_mnt_flags("/mnt/A/AA");
604 ASSERT_EQ(new_flags, expected_flags);
605
606 new_flags = read_mnt_flags("/mnt/A/AA/B");
607 ASSERT_EQ(new_flags, expected_flags);
608
609 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
610 ASSERT_EQ(new_flags, expected_flags);
611
612 memset(&attr, 0, sizeof(attr));
613 attr.attr_clr = MOUNT_ATTR_RDONLY;
614 attr.propagation = MS_SHARED;
615 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
616
617 expected_flags &= ~MS_RDONLY;
618 new_flags = read_mnt_flags("/mnt/A");
619 ASSERT_EQ(new_flags, expected_flags);
620
621 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
622
623 new_flags = read_mnt_flags("/mnt/A/AA");
624 ASSERT_EQ(new_flags, expected_flags);
625
626 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
627
628 new_flags = read_mnt_flags("/mnt/A/AA/B");
629 ASSERT_EQ(new_flags, expected_flags);
630
631 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
632
633 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
634 ASSERT_EQ(new_flags, expected_flags);
635
636 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
637
638 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
639 ASSERT_GE(fd, 0);
640
641
642
643
644
645 attr.attr_set = MOUNT_ATTR_RDONLY;
646 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
647
648 new_flags = read_mnt_flags("/mnt/A");
649 ASSERT_EQ(new_flags, expected_flags);
650
651 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
652
653 new_flags = read_mnt_flags("/mnt/A/AA");
654 ASSERT_EQ(new_flags, expected_flags);
655
656 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
657
658 new_flags = read_mnt_flags("/mnt/A/AA/B");
659 ASSERT_EQ(new_flags, expected_flags);
660
661 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
662
663 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
664 ASSERT_EQ(new_flags, expected_flags);
665
666 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
667
668 EXPECT_EQ(close(fd), 0);
669}
670
671TEST_F(mount_setattr, mount_has_writers)
672{
673 int fd, dfd;
674 unsigned int old_flags = 0, new_flags = 0;
675 struct mount_attr attr = {
676 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME,
677 .attr_clr = MOUNT_ATTR__ATIME,
678 .propagation = MS_SHARED,
679 };
680
681 if (!mount_setattr_supported())
682 SKIP(return, "mount_setattr syscall not supported");
683
684 old_flags = read_mnt_flags("/mnt/A");
685 ASSERT_GT(old_flags, 0);
686
687 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777);
688 ASSERT_GE(fd, 0);
689
690
691
692
693
694
695 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
696
697 new_flags = read_mnt_flags("/mnt/A");
698 ASSERT_EQ(new_flags, old_flags);
699
700 ASSERT_EQ(is_shared_mount("/mnt/A"), false);
701
702 new_flags = read_mnt_flags("/mnt/A/AA");
703 ASSERT_EQ(new_flags, old_flags);
704
705 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), false);
706
707 new_flags = read_mnt_flags("/mnt/A/AA/B");
708 ASSERT_EQ(new_flags, old_flags);
709
710 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), false);
711
712 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
713 ASSERT_EQ(new_flags, old_flags);
714
715 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), false);
716
717 dfd = open("/mnt/A/AA/B", O_DIRECTORY | O_CLOEXEC);
718 ASSERT_GE(dfd, 0);
719 EXPECT_EQ(fsync(dfd), 0);
720 EXPECT_EQ(close(dfd), 0);
721
722 EXPECT_EQ(fsync(fd), 0);
723 EXPECT_EQ(close(fd), 0);
724
725
726 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
727}
728
729TEST_F(mount_setattr, mixed_mount_options)
730{
731 unsigned int old_flags1 = 0, old_flags2 = 0, new_flags = 0, expected_flags = 0;
732 struct mount_attr attr = {
733 .attr_clr = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME,
734 .attr_set = MOUNT_ATTR_RELATIME,
735 };
736
737 if (!mount_setattr_supported())
738 SKIP(return, "mount_setattr syscall not supported");
739
740 old_flags1 = read_mnt_flags("/mnt/B");
741 ASSERT_GT(old_flags1, 0);
742
743 old_flags2 = read_mnt_flags("/mnt/B/BB");
744 ASSERT_GT(old_flags2, 0);
745
746 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/B", AT_RECURSIVE, &attr, sizeof(attr)), 0);
747
748 expected_flags = old_flags2;
749 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
750 expected_flags |= MS_RELATIME;
751
752 new_flags = read_mnt_flags("/mnt/B");
753 ASSERT_EQ(new_flags, expected_flags);
754
755 expected_flags = old_flags2;
756 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID);
757 expected_flags |= MS_RELATIME;
758
759 new_flags = read_mnt_flags("/mnt/B/BB");
760 ASSERT_EQ(new_flags, expected_flags);
761}
762
763TEST_F(mount_setattr, time_changes)
764{
765 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
766 struct mount_attr attr = {
767 .attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME,
768 };
769
770 if (!mount_setattr_supported())
771 SKIP(return, "mount_setattr syscall not supported");
772
773 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
774
775 attr.attr_set = MOUNT_ATTR_STRICTATIME;
776 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
777
778 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
779 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
780
781 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME;
782 attr.attr_clr = MOUNT_ATTR__ATIME;
783 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
784
785 attr.attr_set = 0;
786 attr.attr_clr = MOUNT_ATTR_STRICTATIME;
787 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
788
789 attr.attr_clr = MOUNT_ATTR_NOATIME;
790 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
791
792 old_flags = read_mnt_flags("/mnt/A");
793 ASSERT_GT(old_flags, 0);
794
795 attr.attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME;
796 attr.attr_clr = MOUNT_ATTR__ATIME;
797 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
798
799 expected_flags = old_flags;
800 expected_flags |= MS_NOATIME;
801 expected_flags |= MS_NODIRATIME;
802
803 new_flags = read_mnt_flags("/mnt/A");
804 ASSERT_EQ(new_flags, expected_flags);
805
806 new_flags = read_mnt_flags("/mnt/A/AA");
807 ASSERT_EQ(new_flags, expected_flags);
808
809 new_flags = read_mnt_flags("/mnt/A/AA/B");
810 ASSERT_EQ(new_flags, expected_flags);
811
812 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
813 ASSERT_EQ(new_flags, expected_flags);
814
815 memset(&attr, 0, sizeof(attr));
816 attr.attr_set &= ~MOUNT_ATTR_NOATIME;
817 attr.attr_set |= MOUNT_ATTR_RELATIME;
818 attr.attr_clr |= MOUNT_ATTR__ATIME;
819 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
820
821 expected_flags &= ~MS_NOATIME;
822 expected_flags |= MS_RELATIME;
823
824 new_flags = read_mnt_flags("/mnt/A");
825 ASSERT_EQ(new_flags, expected_flags);
826
827 new_flags = read_mnt_flags("/mnt/A/AA");
828 ASSERT_EQ(new_flags, expected_flags);
829
830 new_flags = read_mnt_flags("/mnt/A/AA/B");
831 ASSERT_EQ(new_flags, expected_flags);
832
833 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
834 ASSERT_EQ(new_flags, expected_flags);
835
836 memset(&attr, 0, sizeof(attr));
837 attr.attr_set &= ~MOUNT_ATTR_RELATIME;
838 attr.attr_set |= MOUNT_ATTR_STRICTATIME;
839 attr.attr_clr |= MOUNT_ATTR__ATIME;
840 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
841
842 expected_flags &= ~MS_RELATIME;
843
844 new_flags = read_mnt_flags("/mnt/A");
845 ASSERT_EQ(new_flags, expected_flags);
846
847 new_flags = read_mnt_flags("/mnt/A/AA");
848 ASSERT_EQ(new_flags, expected_flags);
849
850 new_flags = read_mnt_flags("/mnt/A/AA/B");
851 ASSERT_EQ(new_flags, expected_flags);
852
853 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
854 ASSERT_EQ(new_flags, expected_flags);
855
856 memset(&attr, 0, sizeof(attr));
857 attr.attr_set &= ~MOUNT_ATTR_STRICTATIME;
858 attr.attr_set |= MOUNT_ATTR_NOATIME;
859 attr.attr_clr |= MOUNT_ATTR__ATIME;
860 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
861
862 expected_flags |= MS_NOATIME;
863 new_flags = read_mnt_flags("/mnt/A");
864 ASSERT_EQ(new_flags, expected_flags);
865
866 new_flags = read_mnt_flags("/mnt/A/AA");
867 ASSERT_EQ(new_flags, expected_flags);
868
869 new_flags = read_mnt_flags("/mnt/A/AA/B");
870 ASSERT_EQ(new_flags, expected_flags);
871
872 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
873 ASSERT_EQ(new_flags, expected_flags);
874
875 memset(&attr, 0, sizeof(attr));
876 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
877
878 new_flags = read_mnt_flags("/mnt/A");
879 ASSERT_EQ(new_flags, expected_flags);
880
881 new_flags = read_mnt_flags("/mnt/A/AA");
882 ASSERT_EQ(new_flags, expected_flags);
883
884 new_flags = read_mnt_flags("/mnt/A/AA/B");
885 ASSERT_EQ(new_flags, expected_flags);
886
887 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
888 ASSERT_EQ(new_flags, expected_flags);
889
890 memset(&attr, 0, sizeof(attr));
891 attr.attr_clr = MOUNT_ATTR_NODIRATIME;
892 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
893
894 expected_flags &= ~MS_NODIRATIME;
895
896 new_flags = read_mnt_flags("/mnt/A");
897 ASSERT_EQ(new_flags, expected_flags);
898
899 new_flags = read_mnt_flags("/mnt/A/AA");
900 ASSERT_EQ(new_flags, expected_flags);
901
902 new_flags = read_mnt_flags("/mnt/A/AA/B");
903 ASSERT_EQ(new_flags, expected_flags);
904
905 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
906 ASSERT_EQ(new_flags, expected_flags);
907}
908
909TEST_F(mount_setattr, multi_threaded)
910{
911 int i, j, nthreads, ret = 0;
912 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
913 pthread_attr_t pattr;
914 pthread_t threads[DEFAULT_THREADS];
915
916 if (!mount_setattr_supported())
917 SKIP(return, "mount_setattr syscall not supported");
918
919 old_flags = read_mnt_flags("/mnt/A");
920 ASSERT_GT(old_flags, 0);
921
922
923 nthreads = get_nprocs_conf();
924 if (nthreads > DEFAULT_THREADS)
925 nthreads = DEFAULT_THREADS;
926
927 pthread_attr_init(&pattr);
928 for (i = 0; i < nthreads; i++)
929 ASSERT_EQ(pthread_create(&threads[i], &pattr, mount_setattr_thread, NULL), 0);
930
931 for (j = 0; j < i; j++) {
932 void *retptr = NULL;
933
934 EXPECT_EQ(pthread_join(threads[j], &retptr), 0);
935
936 ret += ptr_to_int(retptr);
937 EXPECT_EQ(ret, 0);
938 }
939 pthread_attr_destroy(&pattr);
940
941 ASSERT_EQ(ret, 0);
942
943 expected_flags = old_flags;
944 expected_flags |= MS_RDONLY;
945 expected_flags |= MS_NOSUID;
946 new_flags = read_mnt_flags("/mnt/A");
947 ASSERT_EQ(new_flags, expected_flags);
948
949 ASSERT_EQ(is_shared_mount("/mnt/A"), true);
950
951 new_flags = read_mnt_flags("/mnt/A/AA");
952 ASSERT_EQ(new_flags, expected_flags);
953
954 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true);
955
956 new_flags = read_mnt_flags("/mnt/A/AA/B");
957 ASSERT_EQ(new_flags, expected_flags);
958
959 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true);
960
961 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
962 ASSERT_EQ(new_flags, expected_flags);
963
964 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true);
965}
966
967TEST_F(mount_setattr, wrong_user_namespace)
968{
969 int ret;
970 struct mount_attr attr = {
971 .attr_set = MOUNT_ATTR_RDONLY,
972 };
973
974 if (!mount_setattr_supported())
975 SKIP(return, "mount_setattr syscall not supported");
976
977 EXPECT_EQ(create_and_enter_userns(), 0);
978 ret = sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr));
979 ASSERT_LT(ret, 0);
980 ASSERT_EQ(errno, EPERM);
981}
982
983TEST_F(mount_setattr, wrong_mount_namespace)
984{
985 int fd, ret;
986 struct mount_attr attr = {
987 .attr_set = MOUNT_ATTR_RDONLY,
988 };
989
990 if (!mount_setattr_supported())
991 SKIP(return, "mount_setattr syscall not supported");
992
993 fd = open("/mnt/A", O_DIRECTORY | O_CLOEXEC);
994 ASSERT_GE(fd, 0);
995
996 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
997
998 ret = sys_mount_setattr(fd, "", AT_EMPTY_PATH | AT_RECURSIVE, &attr, sizeof(attr));
999 ASSERT_LT(ret, 0);
1000 ASSERT_EQ(errno, EINVAL);
1001}
1002
1003FIXTURE(mount_setattr_idmapped) {
1004};
1005
1006FIXTURE_SETUP(mount_setattr_idmapped)
1007{
1008 int img_fd = -EBADF;
1009
1010 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1011
1012 ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0), 0);
1013
1014 (void)umount2("/mnt", MNT_DETACH);
1015 (void)umount2("/tmp", MNT_DETACH);
1016
1017 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV,
1018 "size=100000,mode=700"), 0);
1019
1020 ASSERT_EQ(mkdir("/tmp/B", 0777), 0);
1021 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/b", S_IFREG | 0644, 0), 0);
1022 ASSERT_EQ(chown("/tmp/B/b", 0, 0), 0);
1023
1024 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV,
1025 "size=100000,mode=700"), 0);
1026
1027 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0);
1028 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/BB/b", S_IFREG | 0644, 0), 0);
1029 ASSERT_EQ(chown("/tmp/B/BB/b", 0, 0), 0);
1030
1031 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV,
1032 "size=100000,mode=700"), 0);
1033
1034 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
1035 "size=100000,mode=700"), 0);
1036
1037 ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
1038
1039 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV,
1040 "size=100000,mode=700"), 0);
1041
1042 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
1043
1044 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
1045
1046 ASSERT_EQ(mkdir("/mnt/B", 0777), 0);
1047
1048 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs",
1049 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0);
1050
1051 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0);
1052
1053 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts",
1054 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0);
1055
1056 ASSERT_EQ(mkdir("/mnt/C", 0777), 0);
1057 ASSERT_EQ(mkdir("/mnt/D", 0777), 0);
1058 img_fd = openat(-EBADF, "/mnt/C/ext4.img", O_CREAT | O_WRONLY, 0600);
1059 ASSERT_GE(img_fd, 0);
1060 ASSERT_EQ(ftruncate(img_fd, 1024 * 2048), 0);
1061 ASSERT_EQ(system("mkfs.ext4 -q /mnt/C/ext4.img"), 0);
1062 ASSERT_EQ(system("mount -o loop -t ext4 /mnt/C/ext4.img /mnt/D/"), 0);
1063 ASSERT_EQ(close(img_fd), 0);
1064}
1065
1066FIXTURE_TEARDOWN(mount_setattr_idmapped)
1067{
1068 (void)umount2("/mnt/A", MNT_DETACH);
1069 (void)umount2("/tmp", MNT_DETACH);
1070}
1071
1072
1073
1074
1075TEST_F(mount_setattr_idmapped, invalid_fd_negative)
1076{
1077 struct mount_attr attr = {
1078 .attr_set = MOUNT_ATTR_IDMAP,
1079 .userns_fd = -EBADF,
1080 };
1081
1082 if (!mount_setattr_supported())
1083 SKIP(return, "mount_setattr syscall not supported");
1084
1085 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1086 TH_LOG("failure: created idmapped mount with negative fd");
1087 }
1088}
1089
1090
1091
1092
1093TEST_F(mount_setattr_idmapped, invalid_fd_large)
1094{
1095 struct mount_attr attr = {
1096 .attr_set = MOUNT_ATTR_IDMAP,
1097 .userns_fd = INT64_MAX,
1098 };
1099
1100 if (!mount_setattr_supported())
1101 SKIP(return, "mount_setattr syscall not supported");
1102
1103 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1104 TH_LOG("failure: created idmapped mount with too large fd value");
1105 }
1106}
1107
1108
1109
1110
1111TEST_F(mount_setattr_idmapped, invalid_fd_closed)
1112{
1113 int fd;
1114 struct mount_attr attr = {
1115 .attr_set = MOUNT_ATTR_IDMAP,
1116 };
1117
1118 if (!mount_setattr_supported())
1119 SKIP(return, "mount_setattr syscall not supported");
1120
1121 fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1122 ASSERT_GE(fd, 0);
1123 ASSERT_GE(close(fd), 0);
1124
1125 attr.userns_fd = fd;
1126 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) {
1127 TH_LOG("failure: created idmapped mount with closed fd");
1128 }
1129}
1130
1131
1132
1133
1134TEST_F(mount_setattr_idmapped, invalid_fd_initial_userns)
1135{
1136 int open_tree_fd = -EBADF;
1137 struct mount_attr attr = {
1138 .attr_set = MOUNT_ATTR_IDMAP,
1139 };
1140
1141 if (!mount_setattr_supported())
1142 SKIP(return, "mount_setattr syscall not supported");
1143
1144 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1145 AT_NO_AUTOMOUNT |
1146 AT_SYMLINK_NOFOLLOW |
1147 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
1148 ASSERT_GE(open_tree_fd, 0);
1149
1150 attr.userns_fd = open("/proc/1/ns/user", O_RDONLY | O_CLOEXEC);
1151 ASSERT_GE(attr.userns_fd, 0);
1152 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1153 ASSERT_EQ(errno, EPERM);
1154 ASSERT_EQ(close(attr.userns_fd), 0);
1155 ASSERT_EQ(close(open_tree_fd), 0);
1156}
1157
1158static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid,
1159 unsigned long range)
1160{
1161 char map[100], procfile[256];
1162
1163 snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid);
1164 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1165 if (write_file(procfile, map, strlen(map)))
1166 return -1;
1167
1168
1169 snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid);
1170 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range);
1171 if (write_file(procfile, map, strlen(map)))
1172 return -1;
1173
1174 return 0;
1175}
1176
1177#define __STACK_SIZE (8 * 1024 * 1024)
1178static pid_t do_clone(int (*fn)(void *), void *arg, int flags)
1179{
1180 void *stack;
1181
1182 stack = malloc(__STACK_SIZE);
1183 if (!stack)
1184 return -ENOMEM;
1185
1186#ifdef __ia64__
1187 return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1188#else
1189 return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL);
1190#endif
1191}
1192
1193static int get_userns_fd_cb(void *data)
1194{
1195 return kill(getpid(), SIGSTOP);
1196}
1197
1198static int wait_for_pid(pid_t pid)
1199{
1200 int status, ret;
1201
1202again:
1203 ret = waitpid(pid, &status, 0);
1204 if (ret == -1) {
1205 if (errno == EINTR)
1206 goto again;
1207
1208 return -1;
1209 }
1210
1211 if (!WIFEXITED(status))
1212 return -1;
1213
1214 return WEXITSTATUS(status);
1215}
1216
1217static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range)
1218{
1219 int ret;
1220 pid_t pid;
1221 char path[256];
1222
1223 pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER);
1224 if (pid < 0)
1225 return -errno;
1226
1227 ret = map_ids(pid, nsid, hostid, range);
1228 if (ret < 0)
1229 return ret;
1230
1231 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
1232 ret = open(path, O_RDONLY | O_CLOEXEC);
1233 kill(pid, SIGKILL);
1234 wait_for_pid(pid);
1235 return ret;
1236}
1237
1238
1239
1240
1241
1242
1243TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace)
1244{
1245 int open_tree_fd = -EBADF;
1246 struct mount_attr attr = {
1247 .attr_set = MOUNT_ATTR_IDMAP,
1248 };
1249
1250 if (!mount_setattr_supported())
1251 SKIP(return, "mount_setattr syscall not supported");
1252
1253 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1254 AT_EMPTY_PATH |
1255 AT_NO_AUTOMOUNT |
1256 AT_SYMLINK_NOFOLLOW |
1257 OPEN_TREE_CLOEXEC);
1258 ASSERT_GE(open_tree_fd, 0);
1259
1260 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1261 ASSERT_GE(attr.userns_fd, 0);
1262 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1263 ASSERT_EQ(close(attr.userns_fd), 0);
1264 ASSERT_EQ(close(open_tree_fd), 0);
1265}
1266
1267
1268
1269
1270
1271
1272
1273TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace)
1274{
1275 int open_tree_fd = -EBADF;
1276 struct mount_attr attr = {
1277 .attr_set = MOUNT_ATTR_IDMAP,
1278 };
1279
1280 if (!mount_setattr_supported())
1281 SKIP(return, "mount_setattr syscall not supported");
1282
1283 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1284 AT_EMPTY_PATH |
1285 AT_NO_AUTOMOUNT |
1286 AT_SYMLINK_NOFOLLOW |
1287 OPEN_TREE_CLOEXEC);
1288 ASSERT_GE(open_tree_fd, 0);
1289
1290 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1291
1292 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1293 ASSERT_GE(attr.userns_fd, 0);
1294 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
1295 sizeof(attr)), 0);
1296 ASSERT_EQ(close(attr.userns_fd), 0);
1297 ASSERT_EQ(close(open_tree_fd), 0);
1298}
1299
1300
1301
1302
1303TEST_F(mount_setattr_idmapped, detached_mount_inside_current_mount_namespace)
1304{
1305 int open_tree_fd = -EBADF;
1306 struct mount_attr attr = {
1307 .attr_set = MOUNT_ATTR_IDMAP,
1308 };
1309
1310 if (!mount_setattr_supported())
1311 SKIP(return, "mount_setattr syscall not supported");
1312
1313 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1314 AT_EMPTY_PATH |
1315 AT_NO_AUTOMOUNT |
1316 AT_SYMLINK_NOFOLLOW |
1317 OPEN_TREE_CLOEXEC |
1318 OPEN_TREE_CLONE);
1319 ASSERT_GE(open_tree_fd, 0);
1320
1321
1322 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1323 ASSERT_GE(attr.userns_fd, 0);
1324 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1325 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1326 ASSERT_EQ(close(attr.userns_fd), 0);
1327 ASSERT_EQ(close(open_tree_fd), 0);
1328}
1329
1330
1331
1332
1333TEST_F(mount_setattr_idmapped, detached_mount_outside_current_mount_namespace)
1334{
1335 int open_tree_fd = -EBADF;
1336 struct mount_attr attr = {
1337 .attr_set = MOUNT_ATTR_IDMAP,
1338 };
1339
1340 if (!mount_setattr_supported())
1341 SKIP(return, "mount_setattr syscall not supported");
1342
1343 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1344 AT_EMPTY_PATH |
1345 AT_NO_AUTOMOUNT |
1346 AT_SYMLINK_NOFOLLOW |
1347 OPEN_TREE_CLOEXEC |
1348 OPEN_TREE_CLONE);
1349 ASSERT_GE(open_tree_fd, 0);
1350
1351 ASSERT_EQ(unshare(CLONE_NEWNS), 0);
1352
1353
1354 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1355 ASSERT_GE(attr.userns_fd, 0);
1356 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1357 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1358 ASSERT_EQ(close(attr.userns_fd), 0);
1359 ASSERT_EQ(close(open_tree_fd), 0);
1360}
1361
1362
1363
1364
1365TEST_F(mount_setattr_idmapped, change_idmapping)
1366{
1367 int open_tree_fd = -EBADF;
1368 struct mount_attr attr = {
1369 .attr_set = MOUNT_ATTR_IDMAP,
1370 };
1371
1372 if (!mount_setattr_supported())
1373 SKIP(return, "mount_setattr syscall not supported");
1374
1375 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D",
1376 AT_EMPTY_PATH |
1377 AT_NO_AUTOMOUNT |
1378 AT_SYMLINK_NOFOLLOW |
1379 OPEN_TREE_CLOEXEC |
1380 OPEN_TREE_CLONE);
1381 ASSERT_GE(open_tree_fd, 0);
1382
1383 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1384 ASSERT_GE(attr.userns_fd, 0);
1385 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "",
1386 AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1387 ASSERT_EQ(close(attr.userns_fd), 0);
1388
1389
1390 attr.userns_fd = get_userns_fd(0, 20000, 10000);
1391 ASSERT_GE(attr.userns_fd, 0);
1392 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1393 ASSERT_EQ(close(attr.userns_fd), 0);
1394 ASSERT_EQ(close(open_tree_fd), 0);
1395}
1396
1397static bool expected_uid_gid(int dfd, const char *path, int flags,
1398 uid_t expected_uid, gid_t expected_gid)
1399{
1400 int ret;
1401 struct stat st;
1402
1403 ret = fstatat(dfd, path, &st, flags);
1404 if (ret < 0)
1405 return false;
1406
1407 return st.st_uid == expected_uid && st.st_gid == expected_gid;
1408}
1409
1410TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
1411{
1412 int open_tree_fd = -EBADF;
1413 struct mount_attr attr = {
1414 .attr_set = MOUNT_ATTR_IDMAP,
1415 };
1416
1417 if (!mount_setattr_supported())
1418 SKIP(return, "mount_setattr syscall not supported");
1419
1420 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1421 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1422
1423 open_tree_fd = sys_open_tree(-EBADF, "/mnt/A",
1424 AT_RECURSIVE |
1425 AT_EMPTY_PATH |
1426 AT_NO_AUTOMOUNT |
1427 AT_SYMLINK_NOFOLLOW |
1428 OPEN_TREE_CLOEXEC |
1429 OPEN_TREE_CLONE);
1430 ASSERT_GE(open_tree_fd, 0);
1431
1432 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1433 ASSERT_GE(attr.userns_fd, 0);
1434 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
1435 ASSERT_EQ(close(attr.userns_fd), 0);
1436 ASSERT_EQ(close(open_tree_fd), 0);
1437
1438 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
1439 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
1440 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0);
1441 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0);
1442}
1443
1444TEST_F(mount_setattr, mount_attr_nosymfollow)
1445{
1446 int fd;
1447 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0;
1448 struct mount_attr attr = {
1449 .attr_set = MOUNT_ATTR_NOSYMFOLLOW,
1450 };
1451
1452 if (!mount_setattr_supported())
1453 SKIP(return, "mount_setattr syscall not supported");
1454
1455 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1456 ASSERT_GT(fd, 0);
1457 ASSERT_EQ(close(fd), 0);
1458
1459 old_flags = read_mnt_flags("/mnt/A");
1460 ASSERT_GT(old_flags, 0);
1461
1462 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1463
1464 expected_flags = old_flags;
1465 expected_flags |= ST_NOSYMFOLLOW;
1466
1467 new_flags = read_mnt_flags("/mnt/A");
1468 ASSERT_EQ(new_flags, expected_flags);
1469
1470 new_flags = read_mnt_flags("/mnt/A/AA");
1471 ASSERT_EQ(new_flags, expected_flags);
1472
1473 new_flags = read_mnt_flags("/mnt/A/AA/B");
1474 ASSERT_EQ(new_flags, expected_flags);
1475
1476 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1477 ASSERT_EQ(new_flags, expected_flags);
1478
1479 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1480 ASSERT_LT(fd, 0);
1481 ASSERT_EQ(errno, ELOOP);
1482
1483 attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW;
1484 attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW;
1485
1486 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0);
1487
1488 expected_flags &= ~ST_NOSYMFOLLOW;
1489 new_flags = read_mnt_flags("/mnt/A");
1490 ASSERT_EQ(new_flags, expected_flags);
1491
1492 new_flags = read_mnt_flags("/mnt/A/AA");
1493 ASSERT_EQ(new_flags, expected_flags);
1494
1495 new_flags = read_mnt_flags("/mnt/A/AA/B");
1496 ASSERT_EQ(new_flags, expected_flags);
1497
1498 new_flags = read_mnt_flags("/mnt/A/AA/B/BB");
1499 ASSERT_EQ(new_flags, expected_flags);
1500
1501 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC);
1502 ASSERT_GT(fd, 0);
1503 ASSERT_EQ(close(fd), 0);
1504}
1505
1506TEST_HARNESS_MAIN
1507