~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mount_setattr/mount_setattr_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php