src/idmapped-mounts: Remove useless header file
[xfstests-dev.git] / src / idmapped-mounts / idmapped-mounts.c
1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef _GNU_SOURCE
3 #define _GNU_SOURCE
4 #endif
5
6 #include "../global.h"
7
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <getopt.h>
12 #include <grp.h>
13 #include <limits.h>
14 #include <linux/limits.h>
15 #include <linux/types.h>
16 #include <pthread.h>
17 #include <sched.h>
18 #include <stdbool.h>
19 #include <sys/fsuid.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/xattr.h>
23 #include <unistd.h>
24
25 #ifdef HAVE_SYS_CAPABILITY_H
26 #include <sys/capability.h>
27 #endif
28
29 #ifdef HAVE_LIBURING_H
30 #include <liburing.h>
31 #endif
32
33 #include "missing.h"
34 #include "utils.h"
35
36 #define T_DIR1 "idmapped_mounts_1"
37 #define FILE1 "file1"
38 #define FILE1_RENAME "file1_rename"
39 #define FILE2 "file2"
40 #define FILE2_RENAME "file2_rename"
41 #define DIR1 "dir1"
42 #define DIR2 "dir2"
43 #define DIR3 "dir3"
44 #define DIR1_RENAME "dir1_rename"
45 #define HARDLINK1 "hardlink1"
46 #define SYMLINK1 "symlink1"
47 #define SYMLINK_USER1 "symlink_user1"
48 #define SYMLINK_USER2 "symlink_user2"
49 #define SYMLINK_USER3 "symlink_user3"
50 #define CHRDEV1 "chrdev1"
51
52 #define log_stderr(format, ...)                                                         \
53         fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \
54                 ##__VA_ARGS__)
55
56 #ifdef DEBUG_TRACE
57 #define log_debug(format, ...)                                           \
58         fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \
59                 __func__, ##__VA_ARGS__)
60 #else
61 #define log_debug(format, ...)
62 #endif
63
64 #define log_error_errno(__ret__, __errno__, format, ...)      \
65         ({                                                    \
66                 typeof(__ret__) __internal_ret__ = (__ret__); \
67                 errno = (__errno__);                          \
68                 log_stderr(format, ##__VA_ARGS__);            \
69                 __internal_ret__;                             \
70         })
71
72 #define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__)
73
74 #define die_errno(__errno__, format, ...)          \
75         ({                                         \
76                 errno = (__errno__);               \
77                 log_stderr(format, ##__VA_ARGS__); \
78                 exit(EXIT_FAILURE);                \
79         })
80
81 #define die(format, ...) die_errno(errno, format, ##__VA_ARGS__)
82
83 uid_t t_overflowuid = 65534;
84 gid_t t_overflowgid = 65534;
85
86 /* path of the test device */
87 const char *t_fstype;
88
89 /* path of the test device */
90 const char *t_device;
91
92 /* mountpoint of the test device */
93 const char *t_mountpoint;
94
95 /* fd for @t_mountpoint */
96 int t_mnt_fd;
97
98 /* fd for @T_DIR1 */
99 int t_dir1_fd;
100
101 /* temporary buffer */
102 char t_buf[PATH_MAX];
103
104 static void stash_overflowuid(void)
105 {
106         int fd;
107         ssize_t ret;
108         char buf[256];
109
110         fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
111         if (fd < 0)
112                 return;
113
114         ret = read(fd, buf, sizeof(buf));
115         close(fd);
116         if (ret < 0)
117                 return;
118
119         t_overflowuid = atoi(buf);
120 }
121
122 static void stash_overflowgid(void)
123 {
124         int fd;
125         ssize_t ret;
126         char buf[256];
127
128         fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
129         if (fd < 0)
130                 return;
131
132         ret = read(fd, buf, sizeof(buf));
133         close(fd);
134         if (ret < 0)
135                 return;
136
137         t_overflowgid = atoi(buf);
138 }
139
140 static bool is_xfs(void)
141 {
142         static int enabled = -1;
143
144         if (enabled == -1)
145                 enabled = !strcmp(t_fstype, "xfs");
146
147         return enabled;
148 }
149
150 static bool protected_symlinks_enabled(void)
151 {
152         static int enabled = -1;
153
154         if (enabled == -1) {
155                 int fd;
156                 ssize_t ret;
157                 char buf[256];
158
159                 enabled = 0;
160
161                 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
162                 if (fd < 0)
163                         return false;
164
165                 ret = read(fd, buf, sizeof(buf));
166                 close(fd);
167                 if (ret < 0)
168                         return false;
169
170                 if (atoi(buf) >= 1)
171                         enabled = 1;
172         }
173
174         return enabled == 1;
175 }
176
177 static bool xfs_irix_sgid_inherit_enabled(void)
178 {
179         static int enabled = -1;
180
181         if (enabled == -1) {
182                 int fd;
183                 ssize_t ret;
184                 char buf[256];
185
186                 enabled = 0;
187
188                 if (is_xfs()) {
189                         fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
190                         if (fd < 0)
191                                 return false;
192
193                         ret = read(fd, buf, sizeof(buf));
194                         close(fd);
195                         if (ret < 0)
196                                 return false;
197
198                         if (atoi(buf) >= 1)
199                                 enabled = 1;
200                 }
201         }
202
203         return enabled == 1;
204 }
205
206 static inline bool caps_supported(void)
207 {
208         bool ret = false;
209
210 #ifdef HAVE_SYS_CAPABILITY_H
211         ret = true;
212 #endif
213
214         return ret;
215 }
216
217 /* caps_down - lower all effective caps */
218 static int caps_down(void)
219 {
220         bool fret = false;
221 #ifdef HAVE_SYS_CAPABILITY_H
222         cap_t caps = NULL;
223         int ret = -1;
224
225         caps = cap_get_proc();
226         if (!caps)
227                 goto out;
228
229         ret = cap_clear_flag(caps, CAP_EFFECTIVE);
230         if (ret)
231                 goto out;
232
233         ret = cap_set_proc(caps);
234         if (ret)
235                 goto out;
236
237         fret = true;
238
239 out:
240         cap_free(caps);
241 #endif
242         return fret;
243 }
244
245 /* caps_up - raise all permitted caps */
246 static int caps_up(void)
247 {
248         bool fret = false;
249 #ifdef HAVE_SYS_CAPABILITY_H
250         cap_t caps = NULL;
251         cap_value_t cap;
252         int ret = -1;
253
254         caps = cap_get_proc();
255         if (!caps)
256                 goto out;
257
258         for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
259                 cap_flag_value_t flag;
260
261                 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
262                 if (ret) {
263                         if (errno == EINVAL)
264                                 break;
265                         else
266                                 goto out;
267                 }
268
269                 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
270                 if (ret)
271                         goto out;
272         }
273
274         ret = cap_set_proc(caps);
275         if (ret)
276                 goto out;
277
278         fret = true;
279 out:
280         cap_free(caps);
281 #endif
282         return fret;
283 }
284
285 /* __expected_uid_gid - check whether file is owned by the provided uid and gid */
286 static bool __expected_uid_gid(int dfd, const char *path, int flags,
287                                uid_t expected_uid, gid_t expected_gid, bool log)
288 {
289         int ret;
290         struct stat st;
291
292         ret = fstatat(dfd, path, &st, flags);
293         if (ret < 0)
294                 return log_errno(false, "failure: fstatat");
295
296         if (log && st.st_uid != expected_uid)
297                 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
298
299         if (log && st.st_gid != expected_gid)
300                 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
301
302         errno = 0; /* Don't report misleading errno. */
303         return st.st_uid == expected_uid && st.st_gid == expected_gid;
304 }
305
306 static bool expected_uid_gid(int dfd, const char *path, int flags,
307                              uid_t expected_uid, gid_t expected_gid)
308 {
309         return __expected_uid_gid(dfd, path, flags,
310                                   expected_uid, expected_gid, true);
311 }
312
313 static bool expected_file_size(int dfd, const char *path,
314                                int flags, off_t expected_size)
315 {
316         int ret;
317         struct stat st;
318
319         ret = fstatat(dfd, path, &st, flags);
320         if (ret < 0)
321                 return log_errno(false, "failure: fstatat");
322
323         if (st.st_size != expected_size)
324                 return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)",
325                                  (size_t)st.st_size, (size_t)expected_size);
326
327         return true;
328 }
329
330 /* is_setid - check whether file is S_ISUID and S_ISGID */
331 static bool is_setid(int dfd, const char *path, int flags)
332 {
333         int ret;
334         struct stat st;
335
336         ret = fstatat(dfd, path, &st, flags);
337         if (ret < 0)
338                 return false;
339
340         errno = 0; /* Don't report misleading errno. */
341         return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
342 }
343
344 /* is_setgid - check whether file or directory is S_ISGID */
345 static bool is_setgid(int dfd, const char *path, int flags)
346 {
347         int ret;
348         struct stat st;
349
350         ret = fstatat(dfd, path, &st, flags);
351         if (ret < 0)
352                 return false;
353
354         errno = 0; /* Don't report misleading errno. */
355         return (st.st_mode & S_ISGID);
356 }
357
358 /* is_sticky - check whether file is S_ISVTX */
359 static bool is_sticky(int dfd, const char *path, int flags)
360 {
361         int ret;
362         struct stat st;
363
364         ret = fstatat(dfd, path, &st, flags);
365         if (ret < 0)
366                 return false;
367
368         errno = 0; /* Don't report misleading errno. */
369         return (st.st_mode & S_ISVTX) > 0;
370 }
371
372 static inline int set_cloexec(int fd)
373 {
374         return fcntl(fd, F_SETFD, FD_CLOEXEC);
375 }
376
377 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
378 {
379         if (setfsgid(fsgid))
380                 return log_errno(false, "failure: setfsgid");
381
382         if (setfsgid(-1) != fsgid)
383                 return log_errno(false, "failure: setfsgid(-1)");
384
385         if (setfsuid(fsuid))
386                 return log_errno(false, "failure: setfsuid");
387
388         if (setfsuid(-1) != fsuid)
389                 return log_errno(false, "failure: setfsuid(-1)");
390
391         return true;
392 }
393
394 static inline bool switch_ids(uid_t uid, gid_t gid)
395 {
396         if (setgroups(0, NULL))
397                 return log_errno(false, "failure: setgroups");
398
399         if (setresgid(gid, gid, gid))
400                 return log_errno(false, "failure: setresgid");
401
402         if (setresuid(uid, uid, uid))
403                 return log_errno(false, "failure: setresuid");
404
405         return true;
406 }
407
408 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
409 {
410         if (setns(fd, CLONE_NEWUSER))
411                 return log_errno(false, "failure: setns");
412
413         if (!switch_ids(uid, gid))
414                 return log_errno(false, "failure: switch_ids");
415
416         if (drop_caps && !caps_down())
417                 return log_errno(false, "failure: caps_down");
418
419         return true;
420 }
421
422 /* rm_r - recursively remove all files */
423 static int rm_r(int fd, const char *path)
424 {
425         int dfd, ret;
426         DIR *dir;
427         struct dirent *direntp;
428
429         if (!path || strcmp(path, "") == 0)
430                 return -1;
431
432         dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
433         if (dfd < 0)
434                 return -1;
435
436         dir = fdopendir(dfd);
437         if (!dir) {
438                 close(dfd);
439                 return -1;
440         }
441
442         while ((direntp = readdir(dir))) {
443                 struct stat st;
444
445                 if (!strcmp(direntp->d_name, ".") ||
446                     !strcmp(direntp->d_name, ".."))
447                         continue;
448
449                 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
450                 if (ret < 0 && errno != ENOENT)
451                         break;
452
453                 if (S_ISDIR(st.st_mode))
454                         ret = rm_r(dfd, direntp->d_name);
455                 else
456                         ret = unlinkat(dfd, direntp->d_name, 0);
457                 if (ret < 0 && errno != ENOENT)
458                         break;
459         }
460
461         ret = unlinkat(fd, path, AT_REMOVEDIR);
462         closedir(dir);
463         return ret;
464 }
465
466 /* chown_r - recursively change ownership of all files */
467 static int chown_r(int fd, const char *path, uid_t uid, gid_t gid)
468 {
469         int dfd, ret;
470         DIR *dir;
471         struct dirent *direntp;
472
473         dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
474         if (dfd < 0)
475                 return -1;
476
477         dir = fdopendir(dfd);
478         if (!dir) {
479                 close(dfd);
480                 return -1;
481         }
482
483         while ((direntp = readdir(dir))) {
484                 struct stat st;
485
486                 if (!strcmp(direntp->d_name, ".") ||
487                     !strcmp(direntp->d_name, ".."))
488                         continue;
489
490                 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
491                 if (ret < 0 && errno != ENOENT)
492                         break;
493
494                 if (S_ISDIR(st.st_mode))
495                         ret = chown_r(dfd, direntp->d_name, uid, gid);
496                 else
497                         ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
498                 if (ret < 0 && errno != ENOENT)
499                         break;
500         }
501
502         ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
503         closedir(dir);
504         return ret;
505 }
506
507 /*
508  * There'll be scenarios where you'll want to see the attributes associated with
509  * a directory tree during debugging or just to make sure things look correct.
510  * Simply uncomment and place the print_r() helper where you need it.
511  */
512 #ifdef DEBUG_TRACE
513 static int fd_cloexec(int fd, bool cloexec)
514 {
515         int oflags, nflags;
516
517         oflags = fcntl(fd, F_GETFD, 0);
518         if (oflags < 0)
519                 return -errno;
520
521         if (cloexec)
522                 nflags = oflags | FD_CLOEXEC;
523         else
524                 nflags = oflags & ~FD_CLOEXEC;
525
526         if (nflags == oflags)
527                 return 0;
528
529         if (fcntl(fd, F_SETFD, nflags) < 0)
530                 return -errno;
531
532         return 0;
533 }
534
535 static inline int dup_cloexec(int fd)
536 {
537         int fd_dup;
538
539         fd_dup = dup(fd);
540         if (fd_dup < 0)
541                 return -errno;
542
543         if (fd_cloexec(fd_dup, true)) {
544                 close(fd_dup);
545                 return -errno;
546         }
547
548         return fd_dup;
549 }
550
551 __attribute__((unused)) static int print_r(int fd, const char *path)
552 {
553         int ret = 0;
554         int dfd, dfd_dup;
555         DIR *dir;
556         struct dirent *direntp;
557         struct stat st;
558
559         if (!path || *path == '\0') {
560                 char buf[sizeof("/proc/self/fd/") + 30];
561
562                 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
563                 if (ret < 0 || (size_t)ret >= sizeof(buf))
564                         return -1;
565
566                 /*
567                  * O_PATH file descriptors can't be used so we need to re-open
568                  * just in case.
569                  */
570                 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
571         } else {
572                 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
573         }
574         if (dfd < 0)
575                 return -1;
576
577         /*
578          * When fdopendir() below succeeds it assumes ownership of the fd so we
579          * to make sure we always have an fd that fdopendir() can own which is
580          * why we dup() in the case where the caller wants us to operate on the
581          * fd directly.
582          */
583         dfd_dup = dup_cloexec(dfd);
584         if (dfd_dup < 0) {
585                 close(dfd);
586                 return -1;
587         }
588
589         dir = fdopendir(dfd);
590         if (!dir) {
591                 close(dfd);
592                 close(dfd_dup);
593                 return -1;
594         }
595         /* Transfer ownership to fdopendir(). */
596         dfd = -EBADF;
597
598         while ((direntp = readdir(dir))) {
599                 if (!strcmp(direntp->d_name, ".") ||
600                     !strcmp(direntp->d_name, ".."))
601                         continue;
602
603                 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
604                 if (ret < 0 && errno != ENOENT)
605                         break;
606
607                 ret = 0;
608                 if (S_ISDIR(st.st_mode))
609                         ret = print_r(dfd_dup, direntp->d_name);
610                 else
611                         fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n",
612                                 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
613                                 dfd_dup, direntp->d_name);
614                 if (ret < 0 && errno != ENOENT)
615                         break;
616         }
617
618         if (!path || *path == '\0')
619                 ret = fstatat(fd, "", &st,
620                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
621                               AT_EMPTY_PATH);
622         else
623                 ret = fstatat(fd, path, &st,
624                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
625         if (!ret)
626                 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s",
627                         (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
628                         (path && *path) ? path : "(null)");
629
630         close(dfd_dup);
631         closedir(dir);
632
633         return ret;
634 }
635 #endif
636
637 /* fd_to_fd - transfer data from one fd to another */
638 static int fd_to_fd(int from, int to)
639 {
640         for (;;) {
641                 uint8_t buf[PATH_MAX];
642                 uint8_t *p = buf;
643                 ssize_t bytes_to_write;
644                 ssize_t bytes_read;
645
646                 bytes_read = read_nointr(from, buf, sizeof buf);
647                 if (bytes_read < 0)
648                         return -1;
649                 if (bytes_read == 0)
650                         break;
651
652                 bytes_to_write = (size_t)bytes_read;
653                 do {
654                         ssize_t bytes_written;
655
656                         bytes_written = write_nointr(to, p, bytes_to_write);
657                         if (bytes_written < 0)
658                                 return -1;
659
660                         bytes_to_write -= bytes_written;
661                         p += bytes_written;
662                 } while (bytes_to_write > 0);
663         }
664
665         return 0;
666 }
667
668 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
669                         int flags)
670 {
671 #ifdef __NR_execveat
672         return syscall(__NR_execveat, fd, path, argv, envp, flags);
673 #else
674         errno = ENOSYS;
675         return -1;
676 #endif
677 }
678
679 #ifndef CAP_NET_RAW
680 #define CAP_NET_RAW 13
681 #endif
682
683 #ifndef VFS_CAP_FLAGS_EFFECTIVE
684 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
685 #endif
686
687 #ifndef VFS_CAP_U32_3
688 #define VFS_CAP_U32_3 2
689 #endif
690
691 #ifndef VFS_CAP_U32
692 #define VFS_CAP_U32 VFS_CAP_U32_3
693 #endif
694
695 #ifndef VFS_CAP_REVISION_1
696 #define VFS_CAP_REVISION_1 0x01000000
697 #endif
698
699 #ifndef VFS_CAP_REVISION_2
700 #define VFS_CAP_REVISION_2 0x02000000
701 #endif
702
703 #ifndef VFS_CAP_REVISION_3
704 #define VFS_CAP_REVISION_3 0x03000000
705 struct vfs_ns_cap_data {
706         __le32 magic_etc;
707         struct {
708                 __le32 permitted;
709                 __le32 inheritable;
710         } data[VFS_CAP_U32];
711         __le32 rootid;
712 };
713 #endif
714
715 #if __BYTE_ORDER == __BIG_ENDIAN
716 #define cpu_to_le16(w16) le16_to_cpu(w16)
717 #define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
718 #define cpu_to_le32(w32) le32_to_cpu(w32)
719 #define le32_to_cpu(w32)                                                                       \
720         ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
721          (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
722 #elif __BYTE_ORDER == __LITTLE_ENDIAN
723 #define cpu_to_le16(w16) ((u_int16_t)(w16))
724 #define le16_to_cpu(w16) ((u_int16_t)(w16))
725 #define cpu_to_le32(w32) ((u_int32_t)(w32))
726 #define le32_to_cpu(w32) ((u_int32_t)(w32))
727 #else
728 #error Expected endianess macro to be set
729 #endif
730
731 /* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */
732 static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid)
733 {
734 #define __cap_raised_permitted(x, ns_cap_data)                                 \
735         ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31)))
736         struct vfs_ns_cap_data ns_xattr = {};
737         ssize_t ret;
738
739         ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
740         if (ret < 0 || ret == 0)
741                 return false;
742
743         if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
744
745                 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
746                         errno = EINVAL;
747                         log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
748                 }
749
750                 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
751                        (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
752         } else {
753                 log_stderr("failure: fscaps version");
754         }
755
756         return false;
757 }
758
759 /* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */
760 static int set_dummy_vfs_caps(int fd, int flags, int rootuid)
761 {
762 #define __raise_cap_permitted(x, ns_cap_data)                                  \
763         ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
764
765         struct vfs_ns_cap_data ns_xattr;
766
767         memset(&ns_xattr, 0, sizeof(ns_xattr));
768         __raise_cap_permitted(CAP_NET_RAW, ns_xattr);
769         ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
770         ns_xattr.rootid = cpu_to_le32(rootuid);
771
772         return fsetxattr(fd, "security.capability",
773                          &ns_xattr, sizeof(ns_xattr), flags);
774 }
775
776 #define safe_close(fd)      \
777         if (fd >= 0) {           \
778                 int _e_ = errno; \
779                 close(fd);       \
780                 errno = _e_;     \
781                 fd = -EBADF;     \
782         }
783
784 static void test_setup(void)
785 {
786         if (mkdirat(t_mnt_fd, T_DIR1, 0777))
787                 die("failure: mkdirat");
788
789         t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
790         if (t_dir1_fd < 0)
791                 die("failure: openat");
792
793         if (fchmod(t_dir1_fd, 0777))
794                 die("failure: fchmod");
795 }
796
797 static void test_cleanup(void)
798 {
799         safe_close(t_dir1_fd);
800         if (rm_r(t_mnt_fd, T_DIR1))
801                 die("failure: rm_r");
802 }
803
804 /* Validate that basic file operations on idmapped mounts. */
805 static int fsids_unmapped(void)
806 {
807         int fret = -1;
808         int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
809         struct mount_attr attr = {
810                 .attr_set = MOUNT_ATTR_IDMAP,
811         };
812
813         /* create hardlink target */
814         hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
815         if (hardlink_target_fd < 0) {
816                 log_stderr("failure: openat");
817                 goto out;
818         }
819
820         /* create directory for rename test */
821         if (mkdirat(t_dir1_fd, DIR1, 0700)) {
822                 log_stderr("failure: mkdirat");
823                 goto out;
824         }
825
826         /* change ownership of all files to uid 0 */
827         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
828                 log_stderr("failure: chown_r");
829                 goto out;
830         }
831
832         /* Changing mount properties on a detached mount. */
833         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
834         if (attr.userns_fd < 0) {
835                 log_stderr("failure: get_userns_fd");
836                 goto out;
837         }
838
839         open_tree_fd = sys_open_tree(t_dir1_fd, "",
840                                      AT_EMPTY_PATH |
841                                      AT_NO_AUTOMOUNT |
842                                      AT_SYMLINK_NOFOLLOW |
843                                      OPEN_TREE_CLOEXEC |
844                                      OPEN_TREE_CLONE);
845         if (open_tree_fd < 0) {
846                 log_stderr("failure: sys_open_tree");
847                 goto out;
848         }
849
850         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
851                 log_stderr("failure: sys_mount_setattr");
852                 goto out;
853         }
854
855         if (!switch_fsids(0, 0)) {
856                 log_stderr("failure: switch_fsids");
857                 goto out;
858         }
859
860         /* The caller's fsids don't have a mappings in the idmapped mount so any
861          * file creation must fail.
862          */
863
864         /* create hardlink */
865         if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
866                 log_stderr("failure: linkat");
867                 goto out;
868         }
869         if (errno != EOVERFLOW) {
870                 log_stderr("failure: errno");
871                 goto out;
872         }
873
874         /* try to rename a file */
875         if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
876                 log_stderr("failure: renameat");
877                 goto out;
878         }
879         if (errno != EOVERFLOW) {
880                 log_stderr("failure: errno");
881                 goto out;
882         }
883
884         /* try to rename a directory */
885         if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
886                 log_stderr("failure: renameat");
887                 goto out;
888         }
889         if (errno != EOVERFLOW) {
890                 log_stderr("failure: errno");
891                 goto out;
892         }
893
894         /* The caller is privileged over the inode so file deletion must work. */
895
896         /* remove file */
897         if (unlinkat(open_tree_fd, FILE1, 0)) {
898                 log_stderr("failure: unlinkat");
899                 goto out;
900         }
901
902         /* remove directory */
903         if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
904                 log_stderr("failure: unlinkat");
905                 goto out;
906         }
907
908         /* The caller's fsids don't have a mappings in the idmapped mount so
909          * any file creation must fail.
910          */
911
912         /* create regular file via open() */
913         file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
914         if (file1_fd >= 0) {
915                 log_stderr("failure: create");
916                 goto out;
917         }
918         if (errno != EOVERFLOW) {
919                 log_stderr("failure: errno");
920                 goto out;
921         }
922
923         /* create regular file via mknod */
924         if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
925                 log_stderr("failure: mknodat");
926                 goto out;
927         }
928         if (errno != EOVERFLOW) {
929                 log_stderr("failure: errno");
930                 goto out;
931         }
932
933         /* create character device */
934         if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
935                 log_stderr("failure: mknodat");
936                 goto out;
937         }
938         if (errno != EOVERFLOW) {
939                 log_stderr("failure: errno");
940                 goto out;
941         }
942
943         /* create symlink */
944         if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
945                 log_stderr("failure: symlinkat");
946                 goto out;
947         }
948         if (errno != EOVERFLOW) {
949                 log_stderr("failure: errno");
950                 goto out;
951         }
952
953         /* create directory */
954         if (!mkdirat(open_tree_fd, DIR1, 0700)) {
955                 log_stderr("failure: mkdirat");
956                 goto out;
957         }
958         if (errno != EOVERFLOW) {
959                 log_stderr("failure: errno");
960                 goto out;
961         }
962
963         fret = 0;
964         log_debug("Ran test");
965 out:
966         safe_close(attr.userns_fd);
967         safe_close(hardlink_target_fd);
968         safe_close(file1_fd);
969         safe_close(open_tree_fd);
970
971         return fret;
972 }
973
974 static int fsids_mapped(void)
975 {
976         int fret = -1;
977         int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
978         struct mount_attr attr = {
979                 .attr_set = MOUNT_ATTR_IDMAP,
980         };
981         pid_t pid;
982
983         if (!caps_supported())
984                 return 0;
985
986         /* create hardlink target */
987         hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
988         if (hardlink_target_fd < 0) {
989                 log_stderr("failure: openat");
990                 goto out;
991         }
992
993         /* create directory for rename test */
994         if (mkdirat(t_dir1_fd, DIR1, 0700)) {
995                 log_stderr("failure: mkdirat");
996                 goto out;
997         }
998
999         /* change ownership of all files to uid 0 */
1000         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1001                 log_stderr("failure: chown_r");
1002                 goto out;
1003         }
1004
1005         /* Changing mount properties on a detached mount. */
1006         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1007         if (attr.userns_fd < 0) {
1008                 log_stderr("failure: get_userns_fd");
1009                 goto out;
1010         }
1011
1012         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1013                                      AT_EMPTY_PATH |
1014                                      AT_NO_AUTOMOUNT |
1015                                      AT_SYMLINK_NOFOLLOW |
1016                                      OPEN_TREE_CLOEXEC |
1017                                      OPEN_TREE_CLONE);
1018         if (open_tree_fd < 0) {
1019                 log_stderr("failure: sys_open_tree");
1020                 goto out;
1021         }
1022
1023         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1024                 log_stderr("failure: sys_mount_setattr");
1025                 goto out;
1026         }
1027
1028         pid = fork();
1029         if (pid < 0) {
1030                 log_stderr("failure: fork");
1031                 goto out;
1032         }
1033         if (pid == 0) {
1034                 if (!switch_fsids(10000, 10000))
1035                         die("failure: switch fsids");
1036
1037                 if (!caps_up())
1038                         die("failure: raise caps");
1039
1040                 /* The caller's fsids now have mappings in the idmapped mount so
1041                  * any file creation must fail.
1042                  */
1043
1044                 /* create hardlink */
1045                 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1046                         die("failure: create hardlink");
1047
1048                 /* try to rename a file */
1049                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1050                         die("failure: rename");
1051
1052                 /* try to rename a directory */
1053                 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1054                         die("failure: rename");
1055
1056                 /* remove file */
1057                 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1058                         die("failure: delete");
1059
1060                 /* remove directory */
1061                 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1062                         die("failure: delete");
1063
1064                 /* The caller's fsids have mappings in the idmapped mount so any
1065                  * file creation must fail.
1066                  */
1067
1068                 /* create regular file via open() */
1069                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1070                 if (file1_fd < 0)
1071                         die("failure: create");
1072
1073                 /* create regular file via mknod */
1074                 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1075                         die("failure: create");
1076
1077                 /* create character device */
1078                 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1079                         die("failure: create");
1080
1081                 /* create symlink */
1082                 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1083                         die("failure: create");
1084
1085                 /* create directory */
1086                 if (mkdirat(open_tree_fd, DIR1, 0700))
1087                         die("failure: create");
1088
1089                 exit(EXIT_SUCCESS);
1090         }
1091         if (wait_for_pid(pid))
1092                 goto out;
1093
1094         fret = 0;
1095         log_debug("Ran test");
1096 out:
1097         safe_close(attr.userns_fd);
1098         safe_close(file1_fd);
1099         safe_close(hardlink_target_fd);
1100         safe_close(open_tree_fd);
1101
1102         return fret;
1103 }
1104
1105 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1106 static int create_in_userns(void)
1107 {
1108         int fret = -1;
1109         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1110         struct mount_attr attr = {
1111                 .attr_set = MOUNT_ATTR_IDMAP,
1112         };
1113         pid_t pid;
1114
1115         /* change ownership of all files to uid 0 */
1116         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1117                 log_stderr("failure: chown_r");
1118                 goto out;
1119         }
1120
1121         /* Changing mount properties on a detached mount. */
1122         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1123         if (attr.userns_fd < 0) {
1124                 log_stderr("failure: get_userns_fd");
1125                 goto out;
1126         }
1127
1128         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1129                                      AT_EMPTY_PATH |
1130                                      AT_NO_AUTOMOUNT |
1131                                      AT_SYMLINK_NOFOLLOW |
1132                                      OPEN_TREE_CLOEXEC |
1133                                      OPEN_TREE_CLONE);
1134         if (open_tree_fd < 0) {
1135                 log_stderr("failure: sys_open_tree");
1136                 goto out;
1137         }
1138
1139         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1140                 log_stderr("failure: sys_mount_setattr");
1141                 goto out;
1142         }
1143
1144         pid = fork();
1145         if (pid < 0) {
1146                 log_stderr("failure: fork");
1147                 goto out;
1148         }
1149         if (pid == 0) {
1150                 if (!switch_userns(attr.userns_fd, 0, 0, false))
1151                         die("failure: switch_userns");
1152
1153                 /* create regular file via open() */
1154                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1155                 if (file1_fd < 0)
1156                         die("failure: open file");
1157                 safe_close(file1_fd);
1158
1159                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1160                         die("failure: check ownership");
1161
1162                 /* create regular file via mknod */
1163                 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1164                         die("failure: create");
1165
1166                 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1167                         die("failure: check ownership");
1168
1169                 /* create symlink */
1170                 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1171                         die("failure: create");
1172
1173                 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1174                         die("failure: check ownership");
1175
1176                 /* create directory */
1177                 if (mkdirat(open_tree_fd, DIR1, 0700))
1178                         die("failure: create");
1179
1180                 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1181                         die("failure: check ownership");
1182
1183                 /* try to rename a file */
1184                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1185                         die("failure: create");
1186
1187                 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1188                         die("failure: check ownership");
1189
1190                 /* try to rename a file */
1191                 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1192                         die("failure: create");
1193
1194                 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1195                         die("failure: check ownership");
1196
1197                 /* remove file */
1198                 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1199                         die("failure: remove");
1200
1201                 /* remove directory */
1202                 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1203                         die("failure: remove");
1204
1205                 exit(EXIT_SUCCESS);
1206         }
1207
1208         if (wait_for_pid(pid))
1209                 goto out;
1210
1211         fret = 0;
1212         log_debug("Ran test");
1213 out:
1214         safe_close(attr.userns_fd);
1215         safe_close(file1_fd);
1216         safe_close(open_tree_fd);
1217
1218         return fret;
1219 }
1220
1221 static int hardlink_crossing_mounts(void)
1222 {
1223         int fret = -1;
1224         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1225
1226         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1227                 log_stderr("failure: chown_r");
1228                 goto out;
1229         }
1230
1231         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1232                                      AT_EMPTY_PATH |
1233                                      AT_NO_AUTOMOUNT |
1234                                      AT_SYMLINK_NOFOLLOW |
1235                                      OPEN_TREE_CLOEXEC |
1236                                      OPEN_TREE_CLONE);
1237         if (open_tree_fd < 0) {
1238                 log_stderr("failure: sys_open_tree");
1239                 goto out;
1240         }
1241
1242         file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1243         if (file1_fd < 0) {
1244                 log_stderr("failure: openat");
1245                 goto out;
1246         }
1247
1248         if (mkdirat(open_tree_fd, DIR1, 0777)) {
1249                 log_stderr("failure: mkdirat");
1250                 goto out;
1251         }
1252
1253         /* We're crossing a mountpoint so this must fail.
1254          *
1255          * Note that this must also fail for non-idmapped mounts but here we're
1256          * interested in making sure we're not introducing an accidental way to
1257          * violate that restriction or that suddenly this becomes possible.
1258          */
1259         if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1260                 log_stderr("failure: linkat");
1261                 goto out;
1262         }
1263         if (errno != EXDEV) {
1264                 log_stderr("failure: errno");
1265                 goto out;
1266         }
1267
1268         fret = 0;
1269         log_debug("Ran test");
1270 out:
1271         safe_close(file1_fd);
1272         safe_close(open_tree_fd);
1273
1274         return fret;
1275 }
1276
1277 static int hardlink_crossing_idmapped_mounts(void)
1278 {
1279         int fret = -1;
1280         int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1281         struct mount_attr attr = {
1282                 .attr_set = MOUNT_ATTR_IDMAP,
1283         };
1284
1285         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1286                 log_stderr("failure: chown_r");
1287                 goto out;
1288         }
1289
1290         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
1291         if (attr.userns_fd < 0) {
1292                 log_stderr("failure: get_userns_fd");
1293                 goto out;
1294         }
1295
1296         open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1297                                      AT_EMPTY_PATH |
1298                                      AT_NO_AUTOMOUNT |
1299                                      AT_SYMLINK_NOFOLLOW |
1300                                      OPEN_TREE_CLOEXEC |
1301                                      OPEN_TREE_CLONE);
1302         if (open_tree_fd1 < 0) {
1303                 log_stderr("failure: sys_open_tree");
1304                 goto out;
1305         }
1306
1307         if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1308                 log_stderr("failure: sys_mount_setattr");
1309                 goto out;
1310         }
1311
1312         file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1313         if (file1_fd < 0) {
1314                 log_stderr("failure: openat");
1315                 goto out;
1316         }
1317
1318         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1319                 log_stderr("failure: expected_uid_gid");
1320                 goto out;
1321         }
1322
1323         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1324                 log_stderr("failure: expected_uid_gid");
1325                 goto out;
1326         }
1327
1328         safe_close(file1_fd);
1329
1330         if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1331                 log_stderr("failure: mkdirat");
1332                 goto out;
1333         }
1334
1335         open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1336                                       AT_NO_AUTOMOUNT |
1337                                       AT_SYMLINK_NOFOLLOW |
1338                                       OPEN_TREE_CLOEXEC |
1339                                       OPEN_TREE_CLONE |
1340                                       AT_RECURSIVE);
1341         if (open_tree_fd2 < 0) {
1342                 log_stderr("failure: sys_open_tree");
1343                 goto out;
1344         }
1345
1346         if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1347                 log_stderr("failure: sys_mount_setattr");
1348                 goto out;
1349         }
1350
1351         /* We're crossing a mountpoint so this must fail.
1352          *
1353          * Note that this must also fail for non-idmapped mounts but here we're
1354          * interested in making sure we're not introducing an accidental way to
1355          * violate that restriction or that suddenly this becomes possible.
1356          */
1357         if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1358                 log_stderr("failure: linkat");
1359                 goto out;
1360         }
1361         if (errno != EXDEV) {
1362                 log_stderr("failure: errno");
1363                 goto out;
1364         }
1365
1366         fret = 0;
1367         log_debug("Ran test");
1368 out:
1369         safe_close(attr.userns_fd);
1370         safe_close(file1_fd);
1371         safe_close(open_tree_fd1);
1372         safe_close(open_tree_fd2);
1373
1374         return fret;
1375 }
1376
1377 static int hardlink_from_idmapped_mount(void)
1378 {
1379         int fret = -1;
1380         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1381         struct mount_attr attr = {
1382                 .attr_set = MOUNT_ATTR_IDMAP,
1383         };
1384
1385         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1386                 log_stderr("failure: chown_r");
1387                 goto out;
1388         }
1389
1390         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
1391         if (attr.userns_fd < 0) {
1392                 log_stderr("failure: get_userns_fd");
1393                 goto out;
1394         }
1395
1396         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1397                                      AT_EMPTY_PATH |
1398                                      AT_NO_AUTOMOUNT |
1399                                      AT_SYMLINK_NOFOLLOW |
1400                                      OPEN_TREE_CLOEXEC |
1401                                      OPEN_TREE_CLONE);
1402         if (open_tree_fd < 0) {
1403                 log_stderr("failure: sys_open_tree");
1404                 goto out;
1405         }
1406
1407         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1408                 log_stderr("failure: sys_mount_setattr");
1409                 goto out;
1410         }
1411
1412         file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1413         if (file1_fd < 0) {
1414                 log_stderr("failure: openat");
1415                 goto out;
1416         }
1417         safe_close(file1_fd);
1418
1419         if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1420                 log_stderr("failure: expected_uid_gid");
1421                 goto out;
1422         }
1423
1424         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1425                 log_stderr("failure: expected_uid_gid");
1426                 goto out;
1427         }
1428
1429         /* We're not crossing a mountpoint so this must succeed. */
1430         if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
1431                 log_stderr("failure: linkat");
1432                 goto out;
1433         }
1434
1435
1436         fret = 0;
1437         log_debug("Ran test");
1438 out:
1439         safe_close(attr.userns_fd);
1440         safe_close(file1_fd);
1441         safe_close(open_tree_fd);
1442
1443         return fret;
1444 }
1445
1446 static int hardlink_from_idmapped_mount_in_userns(void)
1447 {
1448         int fret = -1;
1449         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1450         struct mount_attr attr = {
1451                 .attr_set = MOUNT_ATTR_IDMAP,
1452         };
1453         pid_t pid;
1454
1455         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1456                 log_stderr("failure: chown_r");
1457                 goto out;
1458         }
1459
1460         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1461         if (attr.userns_fd < 0) {
1462                 log_stderr("failure: get_userns_fd");
1463                 goto out;
1464         }
1465
1466         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1467                                      AT_EMPTY_PATH |
1468                                      AT_NO_AUTOMOUNT |
1469                                      AT_SYMLINK_NOFOLLOW |
1470                                      OPEN_TREE_CLOEXEC |
1471                                      OPEN_TREE_CLONE);
1472         if (open_tree_fd < 0) {
1473                 log_stderr("failure: sys_open_tree");
1474                 goto out;
1475         }
1476
1477         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1478                 log_stderr("failure: sys_mount_setattr");
1479                 goto out;
1480         }
1481
1482         pid = fork();
1483         if (pid < 0) {
1484                 log_stderr("failure: fork");
1485                 goto out;
1486         }
1487         if (pid == 0) {
1488                 if (!switch_userns(attr.userns_fd, 0, 0, false))
1489                         die("failure: switch_userns");
1490
1491                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1492                 if (file1_fd < 0)
1493                         die("failure: create");
1494
1495                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1496                         die("failure: check ownership");
1497
1498                 /* We're not crossing a mountpoint so this must succeed. */
1499                 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1500                         die("failure: create");
1501
1502                 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1503                         die("failure: check ownership");
1504
1505                 exit(EXIT_SUCCESS);
1506         }
1507
1508         if (wait_for_pid(pid))
1509                 goto out;
1510
1511         fret = 0;
1512         log_debug("Ran test");
1513 out:
1514         safe_close(attr.userns_fd);
1515         safe_close(file1_fd);
1516         safe_close(open_tree_fd);
1517
1518         return fret;
1519 }
1520
1521 static int rename_crossing_mounts(void)
1522 {
1523         int fret = -1;
1524         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1525
1526         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1527                 log_stderr("failure: chown_r");
1528                 goto out;
1529         }
1530
1531         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1532                                      AT_EMPTY_PATH |
1533                                      AT_NO_AUTOMOUNT |
1534                                      AT_SYMLINK_NOFOLLOW |
1535                                      OPEN_TREE_CLOEXEC |
1536                                      OPEN_TREE_CLONE);
1537         if (open_tree_fd < 0) {
1538                 log_stderr("failure: sys_open_tree");
1539                 goto out;
1540         }
1541
1542         file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1543         if (file1_fd < 0) {
1544                 log_stderr("failure: openat");
1545                 goto out;
1546         }
1547
1548         if (mkdirat(open_tree_fd, DIR1, 0777)) {
1549                 log_stderr("failure: mkdirat");
1550                 goto out;
1551         }
1552
1553         /* We're crossing a mountpoint so this must fail.
1554          *
1555          * Note that this must also fail for non-idmapped mounts but here we're
1556          * interested in making sure we're not introducing an accidental way to
1557          * violate that restriction or that suddenly this becomes possible.
1558          */
1559         if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1560                 log_stderr("failure: renameat");
1561                 goto out;
1562         }
1563         if (errno != EXDEV) {
1564                 log_stderr("failure: errno");
1565                 goto out;
1566         }
1567
1568         fret = 0;
1569         log_debug("Ran test");
1570 out:
1571         safe_close(file1_fd);
1572         safe_close(open_tree_fd);
1573
1574         return fret;
1575 }
1576
1577 static int rename_crossing_idmapped_mounts(void)
1578 {
1579         int fret = -1;
1580         int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1581         struct mount_attr attr = {
1582                 .attr_set = MOUNT_ATTR_IDMAP,
1583         };
1584
1585         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1586                 log_stderr("failure: chown_r");
1587                 goto out;
1588         }
1589
1590         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
1591         if (attr.userns_fd < 0) {
1592                 log_stderr("failure: get_userns_fd");
1593                 goto out;
1594         }
1595
1596         open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1597                                      AT_EMPTY_PATH |
1598                                      AT_NO_AUTOMOUNT |
1599                                      AT_SYMLINK_NOFOLLOW |
1600                                      OPEN_TREE_CLOEXEC |
1601                                      OPEN_TREE_CLONE);
1602         if (open_tree_fd1 < 0) {
1603                 log_stderr("failure: sys_open_tree");
1604                 goto out;
1605         }
1606
1607         if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1608                 log_stderr("failure: sys_mount_setattr");
1609                 goto out;
1610         }
1611
1612         file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1613         if (file1_fd < 0) {
1614                 log_stderr("failure: openat");
1615                 goto out;
1616         }
1617
1618         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1619                 log_stderr("failure: expected_uid_gid");
1620                 goto out;
1621         }
1622
1623         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1624                 log_stderr("failure: expected_uid_gid");
1625                 goto out;
1626         }
1627
1628         if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1629                 log_stderr("failure: mkdirat");
1630                 goto out;
1631         }
1632
1633         open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1634                                       AT_NO_AUTOMOUNT |
1635                                       AT_SYMLINK_NOFOLLOW |
1636                                       OPEN_TREE_CLOEXEC |
1637                                       OPEN_TREE_CLONE |
1638                                       AT_RECURSIVE);
1639         if (open_tree_fd2 < 0) {
1640                 log_stderr("failure: sys_open_tree");
1641                 goto out;
1642         }
1643
1644         if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1645                 log_stderr("failure: sys_mount_setattr");
1646                 goto out;
1647         }
1648
1649         /* We're crossing a mountpoint so this must fail.
1650          *
1651          * Note that this must also fail for non-idmapped mounts but here we're
1652          * interested in making sure we're not introducing an accidental way to
1653          * violate that restriction or that suddenly this becomes possible.
1654          */
1655         if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1656                 log_stderr("failure: renameat");
1657                 goto out;
1658         }
1659         if (errno != EXDEV) {
1660                 log_stderr("failure: errno");
1661                 goto out;
1662         }
1663
1664         fret = 0;
1665         log_debug("Ran test");
1666 out:
1667         safe_close(attr.userns_fd);
1668         safe_close(file1_fd);
1669         safe_close(open_tree_fd1);
1670         safe_close(open_tree_fd2);
1671
1672         return fret;
1673 }
1674
1675 static int rename_from_idmapped_mount(void)
1676 {
1677         int fret = -1;
1678         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1679         struct mount_attr attr = {
1680                 .attr_set = MOUNT_ATTR_IDMAP,
1681         };
1682
1683         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1684                 log_stderr("failure: chown_r");
1685                 goto out;
1686         }
1687
1688         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
1689         if (attr.userns_fd < 0) {
1690                 log_stderr("failure: get_userns_fd");
1691                 goto out;
1692         }
1693
1694         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1695                                      AT_EMPTY_PATH |
1696                                      AT_NO_AUTOMOUNT |
1697                                      AT_SYMLINK_NOFOLLOW |
1698                                      OPEN_TREE_CLOEXEC |
1699                                      OPEN_TREE_CLONE);
1700         if (open_tree_fd < 0) {
1701                 log_stderr("failure: sys_open_tree");
1702                 goto out;
1703         }
1704
1705         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1706                 log_stderr("failure: sys_mount_setattr");
1707                 goto out;
1708         }
1709
1710         file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1711         if (file1_fd < 0) {
1712                 log_stderr("failure: openat");
1713                 goto out;
1714         }
1715
1716         if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1717                 log_stderr("failure: expected_uid_gid");
1718                 goto out;
1719         }
1720
1721         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1722                 log_stderr("failure: expected_uid_gid");
1723                 goto out;
1724         }
1725
1726         /* We're not crossing a mountpoint so this must succeed. */
1727         if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
1728                 log_stderr("failure: renameat");
1729                 goto out;
1730         }
1731
1732         fret = 0;
1733         log_debug("Ran test");
1734 out:
1735         safe_close(attr.userns_fd);
1736         safe_close(file1_fd);
1737         safe_close(open_tree_fd);
1738
1739         return fret;
1740 }
1741
1742 static int rename_from_idmapped_mount_in_userns(void)
1743 {
1744         int fret = -1;
1745         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1746         pid_t pid;
1747         struct mount_attr attr = {
1748                 .attr_set = MOUNT_ATTR_IDMAP,
1749         };
1750
1751         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1752                 log_stderr("failure: chown_r");
1753                 goto out;
1754         }
1755
1756         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1757         if (attr.userns_fd < 0) {
1758                 log_stderr("failure: get_userns_fd");
1759                 goto out;
1760         }
1761
1762         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1763                                      AT_EMPTY_PATH |
1764                                      AT_NO_AUTOMOUNT |
1765                                      AT_SYMLINK_NOFOLLOW |
1766                                      OPEN_TREE_CLOEXEC |
1767                                      OPEN_TREE_CLONE);
1768         if (open_tree_fd < 0) {
1769                 log_stderr("failure: sys_open_tree");
1770                 goto out;
1771         }
1772
1773         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1774                 log_stderr("failure: sys_mount_setattr");
1775                 goto out;
1776         }
1777
1778         pid = fork();
1779         if (pid < 0) {
1780                 log_stderr("failure: fork");
1781                 goto out;
1782         }
1783         if (pid == 0) {
1784                 if (!switch_userns(attr.userns_fd, 0, 0, false))
1785                         die("failure: switch_userns");
1786
1787                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1788                 if (file1_fd < 0)
1789                         die("failure: create");
1790
1791                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1792                         die("failure: check ownership");
1793
1794                 /* We're not crossing a mountpoint so this must succeed. */
1795                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1796                         die("failure: create");
1797
1798                 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1799                         die("failure: check ownership");
1800
1801                 exit(EXIT_SUCCESS);
1802         }
1803
1804         if (wait_for_pid(pid))
1805                 goto out;
1806
1807         fret = 0;
1808         log_debug("Ran test");
1809 out:
1810         safe_close(attr.userns_fd);
1811         safe_close(file1_fd);
1812         safe_close(open_tree_fd);
1813
1814         return fret;
1815 }
1816
1817 static int symlink_regular_mounts(void)
1818 {
1819         int fret = -1;
1820         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1821         struct stat st;
1822
1823         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1824         if (file1_fd < 0) {
1825                 log_stderr("failure: openat");
1826                 goto out;
1827         }
1828
1829         if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1830                 log_stderr("failure: chown_r");
1831                 goto out;
1832         }
1833
1834         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1835                                      AT_EMPTY_PATH |
1836                                      AT_NO_AUTOMOUNT |
1837                                      AT_SYMLINK_NOFOLLOW |
1838                                      OPEN_TREE_CLOEXEC |
1839                                      OPEN_TREE_CLONE);
1840         if (open_tree_fd < 0) {
1841                 log_stderr("failure: sys_open_tree");
1842                 goto out;
1843         }
1844
1845         if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1846                 log_stderr("failure: symlinkat");
1847                 goto out;
1848         }
1849
1850         if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1851                 log_stderr("failure: fchownat");
1852                 goto out;
1853         }
1854
1855         if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1856                 log_stderr("failure: fstatat");
1857                 goto out;
1858         }
1859
1860         if (st.st_uid != 15000 || st.st_gid != 15000) {
1861                 log_stderr("failure: compare ids");
1862                 goto out;
1863         }
1864
1865         if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1866                 log_stderr("failure: fstatat");
1867                 goto out;
1868         }
1869
1870         if (st.st_uid != 10000 || st.st_gid != 10000) {
1871                 log_stderr("failure: compare ids");
1872                 goto out;
1873         }
1874
1875         fret = 0;
1876         log_debug("Ran test");
1877 out:
1878         safe_close(file1_fd);
1879         safe_close(open_tree_fd);
1880
1881         return fret;
1882 }
1883
1884 static int symlink_idmapped_mounts(void)
1885 {
1886         int fret = -1;
1887         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1888         struct mount_attr attr = {
1889                 .attr_set = MOUNT_ATTR_IDMAP,
1890         };
1891         pid_t pid;
1892
1893         if (!caps_supported())
1894                 return 0;
1895
1896         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1897         if (file1_fd < 0) {
1898                 log_stderr("failure: openat");
1899                 goto out;
1900         }
1901
1902         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1903                 log_stderr("failure: chown_r");
1904                 goto out;
1905         }
1906
1907         /* Changing mount properties on a detached mount. */
1908         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1909         if (attr.userns_fd < 0) {
1910                 log_stderr("failure: get_userns_fd");
1911                 goto out;
1912         }
1913
1914         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1915                                      AT_EMPTY_PATH |
1916                                      AT_NO_AUTOMOUNT |
1917                                      AT_SYMLINK_NOFOLLOW |
1918                                      OPEN_TREE_CLOEXEC |
1919                                      OPEN_TREE_CLONE);
1920         if (open_tree_fd < 0) {
1921                 log_stderr("failure: sys_open_tree");
1922                 goto out;
1923         }
1924
1925         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1926                 log_stderr("failure: sys_mount_setattr");
1927                 goto out;
1928         }
1929
1930         pid = fork();
1931         if (pid < 0) {
1932                 log_stderr("failure: fork");
1933                 goto out;
1934         }
1935         if (pid == 0) {
1936                 if (!switch_fsids(10000, 10000))
1937                         die("failure: switch fsids");
1938
1939                 if (!caps_up())
1940                         die("failure: raise caps");
1941
1942                 if (symlinkat(FILE1, open_tree_fd, FILE2))
1943                         die("failure: create");
1944
1945                 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1946                         die("failure: change ownership");
1947
1948                 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1949                         die("failure: check ownership");
1950
1951                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1952                         die("failure: check ownership");
1953
1954                 exit(EXIT_SUCCESS);
1955         }
1956         if (wait_for_pid(pid))
1957                 goto out;
1958
1959         fret = 0;
1960         log_debug("Ran test");
1961 out:
1962         safe_close(attr.userns_fd);
1963         safe_close(file1_fd);
1964         safe_close(open_tree_fd);
1965
1966         return fret;
1967 }
1968
1969 static int symlink_idmapped_mounts_in_userns(void)
1970 {
1971         int fret = -1;
1972         int file1_fd = -EBADF, open_tree_fd = -EBADF;
1973         struct mount_attr attr = {
1974                 .attr_set = MOUNT_ATTR_IDMAP,
1975         };
1976         pid_t pid;
1977
1978         if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1979                 log_stderr("failure: chown_r");
1980                 goto out;
1981         }
1982
1983         /* Changing mount properties on a detached mount. */
1984         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
1985         if (attr.userns_fd < 0) {
1986                 log_stderr("failure: get_userns_fd");
1987                 goto out;
1988         }
1989
1990         open_tree_fd = sys_open_tree(t_dir1_fd, "",
1991                                      AT_EMPTY_PATH |
1992                                      AT_NO_AUTOMOUNT |
1993                                      AT_SYMLINK_NOFOLLOW |
1994                                      OPEN_TREE_CLOEXEC |
1995                                      OPEN_TREE_CLONE);
1996         if (open_tree_fd < 0) {
1997                 log_stderr("failure: sys_open_tree");
1998                 goto out;
1999         }
2000
2001         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2002                 log_stderr("failure: sys_mount_setattr");
2003                 goto out;
2004         }
2005
2006         pid = fork();
2007         if (pid < 0) {
2008                 log_stderr("failure: fork");
2009                 goto out;
2010         }
2011         if (pid == 0) {
2012                 if (!switch_userns(attr.userns_fd, 0, 0, false))
2013                         die("failure: switch_userns");
2014
2015                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2016                 if (file1_fd < 0)
2017                         die("failure: create");
2018                 safe_close(file1_fd);
2019
2020                 if (symlinkat(FILE1, open_tree_fd, FILE2))
2021                         die("failure: create");
2022
2023                 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2024                         die("failure: change ownership");
2025
2026                 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2027                         die("failure: check ownership");
2028
2029                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2030                         die("failure: check ownership");
2031
2032                 exit(EXIT_SUCCESS);
2033         }
2034
2035         if (wait_for_pid(pid))
2036                 goto out;
2037
2038         if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2039                 log_stderr("failure: expected_uid_gid");
2040                 goto out;
2041         }
2042
2043         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2044                 log_stderr("failure: expected_uid_gid");
2045                 goto out;
2046         }
2047
2048         fret = 0;
2049         log_debug("Ran test");
2050 out:
2051         safe_close(attr.userns_fd);
2052         safe_close(file1_fd);
2053         safe_close(open_tree_fd);
2054
2055         return fret;
2056 }
2057
2058 /* Validate that a caller whose fsids map into the idmapped mount within it's
2059  * user namespace cannot create any device nodes.
2060  */
2061 static int device_node_in_userns(void)
2062 {
2063         int fret = -1;
2064         int open_tree_fd = -EBADF;
2065         struct mount_attr attr = {
2066                 .attr_set = MOUNT_ATTR_IDMAP,
2067         };
2068         pid_t pid;
2069
2070         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
2071         if (attr.userns_fd < 0) {
2072                 log_stderr("failure: get_userns_fd");
2073                 goto out;
2074         }
2075
2076         open_tree_fd = sys_open_tree(t_dir1_fd, "",
2077                                      AT_EMPTY_PATH |
2078                                      AT_NO_AUTOMOUNT |
2079                                      AT_SYMLINK_NOFOLLOW |
2080                                      OPEN_TREE_CLOEXEC |
2081                                      OPEN_TREE_CLONE);
2082         if (open_tree_fd < 0) {
2083                 log_stderr("failure: sys_open_tree");
2084                 goto out;
2085         }
2086
2087         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2088                 log_stderr("failure: sys_mount_setattr");
2089                 goto out;
2090         }
2091
2092         pid = fork();
2093         if (pid < 0) {
2094                 log_stderr("failure: fork");
2095                 goto out;
2096         }
2097         if (pid == 0) {
2098                 if (!switch_userns(attr.userns_fd, 0, 0, false))
2099                         die("failure: switch_userns");
2100
2101                 /* create character device */
2102                 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2103                         die("failure: create");
2104
2105                 exit(EXIT_SUCCESS);
2106         }
2107
2108         if (wait_for_pid(pid))
2109                 goto out;
2110
2111         fret = 0;
2112         log_debug("Ran test");
2113 out:
2114         safe_close(attr.userns_fd);
2115         safe_close(open_tree_fd);
2116
2117         return fret;
2118 }
2119
2120
2121 /* Validate that changing file ownership works correctly on idmapped mounts. */
2122 static int expected_uid_gid_idmapped_mounts(void)
2123 {
2124         int fret = -1;
2125         int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2126         struct mount_attr attr1 = {
2127                 .attr_set = MOUNT_ATTR_IDMAP,
2128         };
2129         struct mount_attr attr2 = {
2130                 .attr_set = MOUNT_ATTR_IDMAP,
2131         };
2132         pid_t pid;
2133
2134         if (!switch_fsids(0, 0)) {
2135                 log_stderr("failure: switch_fsids");
2136                 goto out;
2137         }
2138
2139         /* create regular file via open() */
2140         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2141         if (file1_fd < 0) {
2142                 log_stderr("failure: openat");
2143                 goto out;
2144         }
2145
2146         /* create regular file via mknod */
2147         if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2148                 log_stderr("failure: mknodat");
2149                 goto out;
2150         }
2151
2152         /* create character device */
2153         if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2154                 log_stderr("failure: mknodat");
2155                 goto out;
2156         }
2157
2158         /* create hardlink */
2159         if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2160                 log_stderr("failure: linkat");
2161                 goto out;
2162         }
2163
2164         /* create symlink */
2165         if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2166                 log_stderr("failure: symlinkat");
2167                 goto out;
2168         }
2169
2170         /* create directory */
2171         if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2172                 log_stderr("failure: mkdirat");
2173                 goto out;
2174         }
2175
2176         /* Changing mount properties on a detached mount. */
2177         attr1.userns_fd = get_userns_fd(0, 10000, 10000);
2178         if (attr1.userns_fd < 0) {
2179                 log_stderr("failure: get_userns_fd");
2180                 goto out;
2181         }
2182
2183         open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2184                                      AT_EMPTY_PATH |
2185                                      AT_NO_AUTOMOUNT |
2186                                      AT_SYMLINK_NOFOLLOW |
2187                                      OPEN_TREE_CLOEXEC |
2188                                      OPEN_TREE_CLONE);
2189         if (open_tree_fd1 < 0) {
2190                 log_stderr("failure: sys_open_tree");
2191                 goto out;
2192         }
2193
2194         if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2195                 log_stderr("failure: sys_mount_setattr");
2196                 goto out;
2197         }
2198
2199         /* Validate that all files created through the image mountpoint are
2200          * owned by the callers fsuid and fsgid.
2201          */
2202         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2203                 log_stderr("failure: expected_uid_gid");
2204                 goto out;
2205         }
2206         if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2207                 log_stderr("failure: expected_uid_gid");
2208                 goto out;
2209         }
2210         if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2211                 log_stderr("failure: expected_uid_gid");
2212                 goto out;
2213         }
2214         if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2215                 log_stderr("failure: expected_uid_gid");
2216                 goto out;
2217         }
2218         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2219                 log_stderr("failure: expected_uid_gid");
2220                 goto out;
2221         }
2222         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2223                 log_stderr("failure: expected_uid_gid");
2224                 goto out;
2225         }
2226         if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2227                 log_stderr("failure: expected_uid_gid");
2228                 goto out;
2229         }
2230
2231         /* Validate that all files are owned by the uid and gid specified in
2232          * the idmapping of the mount they are accessed from.
2233          */
2234         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2235                 log_stderr("failure: expected_uid_gid");
2236                 goto out;
2237         }
2238         if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2239                 log_stderr("failure: expected_uid_gid");
2240                 goto out;
2241         }
2242         if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2243                 log_stderr("failure: expected_uid_gid");
2244                 goto out;
2245         }
2246         if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2247                 log_stderr("failure: expected_uid_gid");
2248                 goto out;
2249         }
2250         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2251                 log_stderr("failure: expected_uid_gid");
2252                 goto out;
2253         }
2254         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2255                 log_stderr("failure: expected_uid_gid");
2256                 goto out;
2257         }
2258         if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2259                 log_stderr("failure: expected_uid_gid");
2260                 goto out;
2261         }
2262
2263         /* Changing mount properties on a detached mount. */
2264         attr2.userns_fd = get_userns_fd(0, 30000, 2001);
2265         if (attr2.userns_fd < 0) {
2266                 log_stderr("failure: get_userns_fd");
2267                 goto out;
2268         }
2269
2270         open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2271                                      AT_EMPTY_PATH |
2272                                      AT_NO_AUTOMOUNT |
2273                                      AT_SYMLINK_NOFOLLOW |
2274                                      OPEN_TREE_CLOEXEC |
2275                                      OPEN_TREE_CLONE);
2276         if (open_tree_fd2 < 0) {
2277                 log_stderr("failure: sys_open_tree");
2278                 goto out;
2279         }
2280
2281         if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2282                 log_stderr("failure: sys_mount_setattr");
2283                 goto out;
2284         }
2285
2286         /* Validate that all files are owned by the uid and gid specified in
2287          * the idmapping of the mount they are accessed from.
2288          */
2289         if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2290                 log_stderr("failure: expected_uid_gid");
2291                 goto out;
2292         }
2293         if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2294                 log_stderr("failure: expected_uid_gid");
2295                 goto out;
2296         }
2297         if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2298                 log_stderr("failure: expected_uid_gid");
2299                 goto out;
2300         }
2301         if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2302                 log_stderr("failure: expected_uid_gid");
2303                 goto out;
2304         }
2305         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2306                 log_stderr("failure: expected_uid_gid");
2307                 goto out;
2308         }
2309         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2310                 log_stderr("failure: expected_uid_gid");
2311                 goto out;
2312         }
2313         if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2314                 log_stderr("failure: expected_uid_gid");
2315                 goto out;
2316         }
2317
2318         /* Change ownership throught original image mountpoint. */
2319         if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2320                 log_stderr("failure: fchownat");
2321                 goto out;
2322         }
2323         if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2324                 log_stderr("failure: fchownat");
2325                 goto out;
2326         }
2327         if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2328                 log_stderr("failure: fchownat");
2329                 goto out;
2330         }
2331         if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2332                 log_stderr("failure: fchownat");
2333                 goto out;
2334         }
2335         if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2336                 log_stderr("failure: fchownat");
2337                 goto out;
2338         }
2339         if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2340                 log_stderr("failure: fchownat");
2341                 goto out;
2342         }
2343         if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2344                 log_stderr("failure: fchownat");
2345                 goto out;
2346         }
2347
2348         /* Check ownership through original mount. */
2349         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 2000, 2000)) {
2350                 log_stderr("failure: expected_uid_gid");
2351                 goto out;
2352         }
2353         if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2354                 log_stderr("failure: expected_uid_gid");
2355                 goto out;
2356         }
2357         if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2358                 log_stderr("failure: expected_uid_gid");
2359                 goto out;
2360         }
2361         if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2362                 log_stderr("failure: expected_uid_gid");
2363                 goto out;
2364         }
2365         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2366                 log_stderr("failure: expected_uid_gid");
2367                 goto out;
2368         }
2369         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2370                 log_stderr("failure: expected_uid_gid");
2371                 goto out;
2372         }
2373         if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2374                 log_stderr("failure: expected_uid_gid");
2375                 goto out;
2376         }
2377
2378         /* Check ownership through first idmapped mount. */
2379         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 12000, 12000)) {
2380                 log_stderr("failure:expected_uid_gid ");
2381                 goto out;
2382         }
2383         if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2384                 log_stderr("failure: expected_uid_gid");
2385                 goto out;
2386         }
2387         if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2388                 log_stderr("failure: expected_uid_gid");
2389                 goto out;
2390         }
2391         if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2392                 log_stderr("failure: expected_uid_gid");
2393                 goto out;
2394         }
2395         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2396                 log_stderr("failure: expected_uid_gid");
2397                 goto out;
2398         }
2399         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2400                 log_stderr("failure:expected_uid_gid ");
2401                 goto out;
2402         }
2403         if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2404                 log_stderr("failure: expected_uid_gid");
2405                 goto out;
2406         }
2407
2408         /* Check ownership through second idmapped mount. */
2409         if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 32000, 32000)) {
2410                 log_stderr("failure: expected_uid_gid");
2411                 goto out;
2412         }
2413         if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2414                 log_stderr("failure: expected_uid_gid");
2415                 goto out;
2416         }
2417         if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2418                 log_stderr("failure: expected_uid_gid");
2419                 goto out;
2420         }
2421         if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2422                 log_stderr("failure: expected_uid_gid");
2423                 goto out;
2424         }
2425         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2426                 log_stderr("failure: expected_uid_gid");
2427                 goto out;
2428         }
2429         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2430                 log_stderr("failure: expected_uid_gid");
2431                 goto out;
2432         }
2433         if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2434                 log_stderr("failure: expected_uid_gid");
2435                 goto out;
2436         }
2437
2438         pid = fork();
2439         if (pid < 0) {
2440                 log_stderr("failure: fork");
2441                 goto out;
2442         }
2443         if (pid == 0) {
2444                 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2445                         die("failure: switch_userns");
2446
2447                 if (!fchownat(t_dir1_fd, FILE1, 1000, 1000, 0))
2448                         die("failure: fchownat");
2449                 if (!fchownat(t_dir1_fd, FILE2, 1000, 1000, 0))
2450                         die("failure: fchownat");
2451                 if (!fchownat(t_dir1_fd, HARDLINK1, 1000, 1000, 0))
2452                         die("failure: fchownat");
2453                 if (!fchownat(t_dir1_fd, CHRDEV1, 1000, 1000, 0))
2454                         die("failure: fchownat");
2455                 if (!fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2456                         die("failure: fchownat");
2457                 if (!fchownat(t_dir1_fd, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2458                         die("failure: fchownat");
2459                 if (!fchownat(t_dir1_fd, DIR1, 1000, 1000, AT_EMPTY_PATH))
2460                         die("failure: fchownat");
2461
2462                 if (!fchownat(open_tree_fd2, FILE1, 1000, 1000, 0))
2463                         die("failure: fchownat");
2464                 if (!fchownat(open_tree_fd2, FILE2, 1000, 1000, 0))
2465                         die("failure: fchownat");
2466                 if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
2467                         die("failure: fchownat");
2468                 if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
2469                         die("failure: fchownat");
2470                 if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2471                         die("failure: fchownat");
2472                 if (!fchownat(open_tree_fd2, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2473                         die("failure: fchownat");
2474                 if (!fchownat(open_tree_fd2, DIR1, 1000, 1000, AT_EMPTY_PATH))
2475                         die("failure: fchownat");
2476
2477                 if (fchownat(open_tree_fd1, FILE1, 1000, 1000, 0))
2478                         die("failure: fchownat");
2479                 if (fchownat(open_tree_fd1, FILE2, 1000, 1000, 0))
2480                         die("failure: fchownat");
2481                 if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
2482                         die("failure: fchownat");
2483                 if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
2484                         die("failure: fchownat");
2485                 if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2486                         die("failure: fchownat");
2487                 if (fchownat(open_tree_fd1, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2488                         die("failure: fchownat");
2489                 if (fchownat(open_tree_fd1, DIR1, 1000, 1000, AT_EMPTY_PATH))
2490                         die("failure: fchownat");
2491
2492                 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2493                         die("failure: expected_uid_gid");
2494                 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2495                         die("failure: expected_uid_gid");
2496                 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2497                         die("failure: expected_uid_gid");
2498                 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2499                         die("failure: expected_uid_gid");
2500                 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2501                         die("failure: expected_uid_gid");
2502                 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2503                         die("failure: expected_uid_gid");
2504                 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2505                         die("failure: expected_uid_gid");
2506
2507                 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, t_overflowuid, t_overflowgid))
2508                         die("failure: expected_uid_gid");
2509                 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, t_overflowuid, t_overflowgid))
2510                         die("failure: expected_uid_gid");
2511                 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2512                         die("failure: expected_uid_gid");
2513                 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2514                         die("failure: expected_uid_gid");
2515                 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2516                         die("failure: expected_uid_gid");
2517                 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2518                         die("failure: expected_uid_gid");
2519                 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, t_overflowuid, t_overflowgid))
2520                         die("failure: expected_uid_gid");
2521
2522                 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 1000, 1000))
2523                         die("failure: expected_uid_gid");
2524                 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 1000, 1000))
2525                         die("failure: expected_uid_gid");
2526                 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
2527                         die("failure: expected_uid_gid");
2528                 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
2529                         die("failure: expected_uid_gid");
2530                 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2531                         die("failure: expected_uid_gid");
2532                 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 1000, 1000))
2533                         die("failure: expected_uid_gid");
2534                 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 1000, 1000))
2535                         die("failure: expected_uid_gid");
2536
2537                 exit(EXIT_SUCCESS);
2538         }
2539
2540         if (wait_for_pid(pid))
2541                 goto out;
2542
2543         /* Check ownership through original mount. */
2544         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 1000, 1000)) {
2545                 log_stderr("failure: expected_uid_gid");
2546                 goto out;
2547         }
2548         if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2549                 log_stderr("failure: expected_uid_gid");
2550                 goto out;
2551         }
2552         if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2553                 log_stderr("failure: expected_uid_gid");
2554                 goto out;
2555         }
2556         if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2557                 log_stderr("failure: expected_uid_gid");
2558                 goto out;
2559         }
2560         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2561                 log_stderr("failure: expected_uid_gid");
2562                 goto out;
2563         }
2564         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2565                 log_stderr("failure: expected_uid_gid");
2566                 goto out;
2567         }
2568         if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2569                 log_stderr("failure: expected_uid_gid");
2570                 goto out;
2571         }
2572
2573         /* Check ownership through first idmapped mount. */
2574         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 11000, 11000)) {
2575                 log_stderr("failure: expected_uid_gid");
2576                 goto out;
2577         }
2578         if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2579                 log_stderr("failure: expected_uid_gid");
2580                 goto out;
2581         }
2582         if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2583                 log_stderr("failure: expected_uid_gid");
2584                 goto out;
2585         }
2586         if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2587                 log_stderr("failure: expected_uid_gid");
2588                 goto out;
2589         }
2590         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2591                 log_stderr("failure: expected_uid_gid");
2592                 goto out;
2593         }
2594         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2595                 log_stderr("failure: expected_uid_gid");
2596                 goto out;
2597         }
2598         if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2599                 log_stderr("failure: expected_uid_gid");
2600                 goto out;
2601         }
2602
2603         /* Check ownership through second idmapped mount. */
2604         if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 31000, 31000)) {
2605                 log_stderr("failure: expected_uid_gid");
2606                 goto out;
2607         }
2608         if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2609                 log_stderr("failure: expected_uid_gid");
2610                 goto out;
2611         }
2612         if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2613                 log_stderr("failure: expected_uid_gid");
2614                 goto out;
2615         }
2616         if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2617                 log_stderr("failure: expected_uid_gid");
2618                 goto out;
2619         }
2620         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2621                 log_stderr("failure: expected_uid_gid");
2622                 goto out;
2623         }
2624         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2625                 log_stderr("failure: expected_uid_gid");
2626                 goto out;
2627         }
2628         if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2629                 log_stderr("failure: expected_uid_gid");
2630                 goto out;
2631         }
2632
2633         pid = fork();
2634         if (pid < 0) {
2635                 log_stderr("failure: fork");
2636                 goto out;
2637         }
2638         if (pid == 0) {
2639                 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2640                         die("failure: switch_userns");
2641
2642                 if (!fchownat(t_dir1_fd, FILE1, 0, 0, 0))
2643                         die("failure: fchownat");
2644                 if (!fchownat(t_dir1_fd, FILE2, 0, 0, 0))
2645                         die("failure: fchownat");
2646                 if (!fchownat(t_dir1_fd, HARDLINK1, 0, 0, 0))
2647                         die("failure: fchownat");
2648                 if (!fchownat(t_dir1_fd, CHRDEV1, 0, 0, 0))
2649                         die("failure: fchownat");
2650                 if (!fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2651                         die("failure: fchownat");
2652                 if (!fchownat(t_dir1_fd, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2653                         die("failure: fchownat");
2654                 if (!fchownat(t_dir1_fd, DIR1, 0, 0, AT_EMPTY_PATH))
2655                         die("failure: fchownat");
2656
2657                 if (!fchownat(open_tree_fd1, FILE1, 0, 0, 0))
2658                         die("failure: fchownat");
2659                 if (!fchownat(open_tree_fd1, FILE2, 0, 0, 0))
2660                         die("failure: fchownat");
2661                 if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
2662                         die("failure: fchownat");
2663                 if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
2664                         die("failure: fchownat");
2665                 if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2666                         die("failure: fchownat");
2667                 if (!fchownat(open_tree_fd1, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2668                         die("failure: fchownat");
2669                 if (!fchownat(open_tree_fd1, DIR1, 0, 0, AT_EMPTY_PATH))
2670                         die("failure: fchownat");
2671
2672                 if (fchownat(open_tree_fd2, FILE1, 0, 0, 0))
2673                         die("failure: fchownat");
2674                 if (fchownat(open_tree_fd2, FILE2, 0, 0, 0))
2675                         die("failure: fchownat");
2676                 if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
2677                         die("failure: fchownat");
2678                 if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
2679                         die("failure: fchownat");
2680                 if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2681                         die("failure: fchownat");
2682                 if (fchownat(open_tree_fd2, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2683                         die("failure: fchownat");
2684                 if (fchownat(open_tree_fd2, DIR1, 0, 0, AT_EMPTY_PATH))
2685                         die("failure: fchownat");
2686
2687                 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2688                         die("failure: expected_uid_gid");
2689                 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2690                         die("failure: expected_uid_gid");
2691                 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2692                         die("failure: expected_uid_gid");
2693                 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2694                         die("failure: expected_uid_gid");
2695                 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2696                         die("failure: expected_uid_gid");
2697                 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2698                         die("failure: expected_uid_gid");
2699                 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2700                         die("failure: expected_uid_gid");
2701
2702                 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, t_overflowuid, t_overflowgid))
2703                         die("failure: expected_uid_gid");
2704                 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, t_overflowuid, t_overflowgid))
2705                         die("failure: expected_uid_gid");
2706                 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2707                         die("failure: expected_uid_gid");
2708                 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2709                         die("failure: expected_uid_gid");
2710                 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2711                         die("failure: expected_uid_gid");
2712                 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2713                         die("failure: expected_uid_gid");
2714                 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, t_overflowuid, t_overflowgid))
2715                         die("failure: expected_uid_gid");
2716
2717                 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 0, 0))
2718                         die("failure: expected_uid_gid");
2719                 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 0, 0))
2720                         die("failure: expected_uid_gid");
2721                 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
2722                         die("failure: expected_uid_gid");
2723                 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
2724                         die("failure: expected_uid_gid");
2725                 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2726                         die("failure: expected_uid_gid");
2727                 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 0, 0))
2728                         die("failure: expected_uid_gid");
2729                 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 0, 0))
2730                         die("failure: expected_uid_gid");
2731
2732                 exit(EXIT_SUCCESS);
2733         }
2734
2735         if (wait_for_pid(pid))
2736                 goto out;
2737
2738         /* Check ownership through original mount. */
2739         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2740                 log_stderr("failure: expected_uid_gid");
2741                 goto out;
2742         }
2743         if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2744                 log_stderr("failure: expected_uid_gid");
2745                 goto out;
2746         }
2747         if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2748                 log_stderr("failure: expected_uid_gid");
2749                 goto out;
2750         }
2751         if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2752                 log_stderr("failure: expected_uid_gid");
2753                 goto out;
2754         }
2755         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2756                 log_stderr("failure: expected_uid_gid");
2757                 goto out;
2758         }
2759         if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2760                 log_stderr("failure: expected_uid_gid");
2761                 goto out;
2762         }
2763         if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2764                 log_stderr("failure: expected_uid_gid");
2765                 goto out;
2766         }
2767
2768         /* Check ownership through first idmapped mount. */
2769         if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2770                 log_stderr("failure: expected_uid_gid");
2771                 goto out;
2772         }
2773         if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2774                 log_stderr("failure: expected_uid_gid");
2775                 goto out;
2776         }
2777         if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2778                 log_stderr("failure: expected_uid_gid");
2779                 goto out;
2780         }
2781         if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2782                 log_stderr("failure: expected_uid_gid");
2783                 goto out;
2784         }
2785         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2786                 log_stderr("failure: expected_uid_gid");
2787                 goto out;
2788         }
2789         if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2790                 log_stderr("failure: expected_uid_gid");
2791                 goto out;
2792         }
2793         if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2794                 log_stderr("failure: expected_uid_gid");
2795                 goto out;
2796         }
2797
2798         /* Check ownership through second idmapped mount. */
2799         if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2800                 log_stderr("failure: expected_uid_gid");
2801                 goto out;
2802         }
2803         if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2804                 log_stderr("failure: expected_uid_gid");
2805                 goto out;
2806         }
2807         if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2808                 log_stderr("failure: expected_uid_gid");
2809                 goto out;
2810         }
2811         if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2812                 log_stderr("failure: expected_uid_gid");
2813                 goto out;
2814         }
2815         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2816                 log_stderr("failure: expected_uid_gid");
2817                 goto out;
2818         }
2819         if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2820                 log_stderr("failure: expected_uid_gid");
2821                 goto out;
2822         }
2823         if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2824                 log_stderr("failure: expected_uid_gid");
2825                 goto out;
2826         }
2827
2828         fret = 0;
2829         log_debug("Ran test");
2830 out:
2831         safe_close(attr1.userns_fd);
2832         safe_close(attr2.userns_fd);
2833         safe_close(file1_fd);
2834         safe_close(open_tree_fd1);
2835         safe_close(open_tree_fd2);
2836
2837         return fret;
2838 }
2839
2840 static int fscaps(void)
2841 {
2842         int fret = -1;
2843         int file1_fd = -EBADF;
2844         struct mount_attr attr = {
2845                 .attr_set = MOUNT_ATTR_IDMAP,
2846         };
2847         pid_t pid;
2848
2849         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2850         if (file1_fd < 0) {
2851                 log_stderr("failure: openat");
2852                 goto out;
2853         }
2854
2855         /* Skip if vfs caps are unsupported. */
2856         if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2857                 return 0;
2858
2859         /* Changing mount properties on a detached mount. */
2860         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
2861         if (attr.userns_fd < 0) {
2862                 log_stderr("failure: get_userns_fd");
2863                 goto out;
2864         }
2865
2866         if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
2867                 log_stderr("failure: expected_dummy_vfs_caps_uid");
2868                 goto out;
2869         }
2870
2871         pid = fork();
2872         if (pid < 0) {
2873                 log_stderr("failure: fork");
2874                 goto out;
2875         }
2876         if (pid == 0) {
2877                 if (!switch_userns(attr.userns_fd, 0, 0, false))
2878                         die("failure: switch_userns");
2879
2880                 /*
2881                  * On kernels before 5.12 this would succeed and return the
2882                  * unconverted caps. Then - for whatever reason - this behavior
2883                  * got changed and since 5.12 EOVERFLOW is returned when the
2884                  * rootid stored alongside the vfs caps does not map to uid 0 in
2885                  * the caller's user namespace.
2886                  */
2887                 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
2888                         die("failure: expected_dummy_vfs_caps_uid");
2889
2890                 exit(EXIT_SUCCESS);
2891         }
2892
2893         if (wait_for_pid(pid))
2894                 goto out;
2895
2896         if (fremovexattr(file1_fd, "security.capability")) {
2897                 log_stderr("failure: fremovexattr");
2898                 goto out;
2899         }
2900         if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2901                 log_stderr("failure: expected_dummy_vfs_caps_uid");
2902                 goto out;
2903         }
2904         if (errno != ENODATA) {
2905                 log_stderr("failure: errno");
2906                 goto out;
2907         }
2908
2909         if (set_dummy_vfs_caps(file1_fd, 0, 10000)) {
2910                 log_stderr("failure: set_dummy_vfs_caps");
2911                 goto out;
2912         }
2913
2914         if (!expected_dummy_vfs_caps_uid(file1_fd, 10000)) {
2915                 log_stderr("failure: expected_dummy_vfs_caps_uid");
2916                 goto out;
2917         }
2918
2919         pid = fork();
2920         if (pid < 0) {
2921                 log_stderr("failure: fork");
2922                 goto out;
2923         }
2924         if (pid == 0) {
2925                 if (!switch_userns(attr.userns_fd, 0, 0, false))
2926                         die("failure: switch_userns");
2927
2928                 if (!expected_dummy_vfs_caps_uid(file1_fd, 0))
2929                         die("failure: expected_dummy_vfs_caps_uid");
2930
2931                 exit(EXIT_SUCCESS);
2932         }
2933
2934         if (wait_for_pid(pid))
2935                 goto out;
2936
2937         if (fremovexattr(file1_fd, "security.capability")) {
2938                 log_stderr("failure: fremovexattr");
2939                 goto out;
2940         }
2941         if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2942                 log_stderr("failure: expected_dummy_vfs_caps_uid");
2943                 goto out;
2944         }
2945         if (errno != ENODATA) {
2946                 log_stderr("failure: errno");
2947                 goto out;
2948         }
2949
2950         fret = 0;
2951         log_debug("Ran test");
2952 out:
2953         safe_close(attr.userns_fd);
2954         safe_close(file1_fd);
2955
2956         return fret;
2957 }
2958
2959 static int fscaps_idmapped_mounts(void)
2960 {
2961         int fret = -1;
2962         int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
2963         struct mount_attr attr = {
2964                 .attr_set = MOUNT_ATTR_IDMAP,
2965         };
2966         pid_t pid;
2967
2968         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2969         if (file1_fd < 0) {
2970                 log_stderr("failure: openat");
2971                 goto out;
2972         }
2973
2974         /* Skip if vfs caps are unsupported. */
2975         if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2976                 return 0;
2977
2978         if (fremovexattr(file1_fd, "security.capability")) {
2979                 log_stderr("failure: fremovexattr");
2980                 goto out;
2981         }
2982
2983         /* Changing mount properties on a detached mount. */
2984         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
2985         if (attr.userns_fd < 0) {
2986                 log_stderr("failure: get_userns_fd");
2987                 goto out;
2988         }
2989
2990         open_tree_fd = sys_open_tree(t_dir1_fd, "",
2991                                      AT_EMPTY_PATH |
2992                                      AT_NO_AUTOMOUNT |
2993                                      AT_SYMLINK_NOFOLLOW |
2994                                      OPEN_TREE_CLOEXEC |
2995                                      OPEN_TREE_CLONE);
2996         if (open_tree_fd < 0) {
2997                 log_stderr("failure: sys_open_tree");
2998                 goto out;
2999         }
3000
3001         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3002                 log_stderr("failure: sys_mount_setattr");
3003                 goto out;
3004         }
3005
3006         file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3007         if (file1_fd2 < 0) {
3008                 log_stderr("failure: openat");
3009                 goto out;
3010         }
3011
3012         if (!set_dummy_vfs_caps(file1_fd2, 0, 1000)) {
3013                 log_stderr("failure: set_dummy_vfs_caps");
3014                 goto out;
3015         }
3016
3017         if (set_dummy_vfs_caps(file1_fd2, 0, 10000)) {
3018                 log_stderr("failure: set_dummy_vfs_caps");
3019                 goto out;
3020         }
3021
3022         if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3023                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3024                 goto out;
3025         }
3026
3027         if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3028                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3029                 goto out;
3030         }
3031
3032         pid = fork();
3033         if (pid < 0) {
3034                 log_stderr("failure: fork");
3035                 goto out;
3036         }
3037         if (pid == 0) {
3038                 if (!switch_userns(attr.userns_fd, 0, 0, false))
3039                         die("failure: switch_userns");
3040
3041                 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3042                         die("failure: expected_dummy_vfs_caps_uid");
3043
3044                 exit(EXIT_SUCCESS);
3045         }
3046
3047         if (wait_for_pid(pid))
3048                 goto out;
3049
3050         if (fremovexattr(file1_fd2, "security.capability")) {
3051                 log_stderr("failure: fremovexattr");
3052                 goto out;
3053         }
3054         if (expected_dummy_vfs_caps_uid(file1_fd2, -1)) {
3055                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3056                 goto out;
3057         }
3058         if (errno != ENODATA) {
3059                 log_stderr("failure: errno");
3060                 goto out;
3061         }
3062
3063         if (set_dummy_vfs_caps(file1_fd2, 0, 12000)) {
3064                 log_stderr("failure: set_dummy_vfs_caps");
3065                 goto out;
3066         }
3067
3068         if (!expected_dummy_vfs_caps_uid(file1_fd2, 12000)) {
3069                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3070                 goto out;
3071         }
3072
3073         if (!expected_dummy_vfs_caps_uid(file1_fd, 2000)) {
3074                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3075                 goto out;
3076         }
3077
3078         pid = fork();
3079         if (pid < 0) {
3080                 log_stderr("failure: fork");
3081                 goto out;
3082         }
3083         if (pid == 0) {
3084                 if (!switch_userns(attr.userns_fd, 0, 0, false))
3085                         die("failure: switch_userns");
3086
3087                 if (!expected_dummy_vfs_caps_uid(file1_fd2, 2000))
3088                         die("failure: expected_dummy_vfs_caps_uid");
3089
3090                 exit(EXIT_SUCCESS);
3091         }
3092
3093         if (wait_for_pid(pid))
3094                 goto out;
3095
3096         fret = 0;
3097         log_debug("Ran test");
3098 out:
3099         safe_close(attr.userns_fd);
3100         safe_close(file1_fd);
3101         safe_close(file1_fd2);
3102         safe_close(open_tree_fd);
3103
3104         return fret;
3105 }
3106
3107 static int fscaps_idmapped_mounts_in_userns(void)
3108 {
3109         int fret = -1;
3110         int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3111         struct mount_attr attr = {
3112                 .attr_set = MOUNT_ATTR_IDMAP,
3113         };
3114         pid_t pid;
3115
3116         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3117         if (file1_fd < 0) {
3118                 log_stderr("failure: openat");
3119                 goto out;
3120         }
3121
3122         /* Skip if vfs caps are unsupported. */
3123         if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3124                 return 0;
3125
3126         if (fremovexattr(file1_fd, "security.capability")) {
3127                 log_stderr("failure: fremovexattr");
3128                 goto out;
3129         }
3130
3131         /* Changing mount properties on a detached mount. */
3132         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
3133         if (attr.userns_fd < 0) {
3134                 log_stderr("failure: get_userns_fd");
3135                 goto out;
3136         }
3137
3138         open_tree_fd = sys_open_tree(t_dir1_fd, "",
3139                                      AT_EMPTY_PATH |
3140                                      AT_NO_AUTOMOUNT |
3141                                      AT_SYMLINK_NOFOLLOW |
3142                                      OPEN_TREE_CLOEXEC |
3143                                      OPEN_TREE_CLONE);
3144         if (open_tree_fd < 0) {
3145                 log_stderr("failure: sys_open_tree");
3146                 goto out;
3147         }
3148
3149         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3150                 log_stderr("failure: sys_mount_setattr");
3151                 goto out;
3152         }
3153
3154         file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3155         if (file1_fd2 < 0) {
3156                 log_stderr("failure: openat");
3157                 goto out;
3158         }
3159
3160         pid = fork();
3161         if (pid < 0) {
3162                 log_stderr("failure: fork");
3163                 goto out;
3164         }
3165         if (pid == 0) {
3166                 if (!switch_userns(attr.userns_fd, 0, 0, false))
3167                         die("failure: switch_userns");
3168
3169                 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3170                         die("failure: expected_dummy_vfs_caps_uid");
3171                 if (errno != ENODATA)
3172                         die("failure: errno");
3173
3174                 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3175                         die("failure: set_dummy_vfs_caps");
3176
3177                 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3178                         die("failure: expected_dummy_vfs_caps_uid");
3179
3180                 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
3181                         die("failure: expected_dummy_vfs_caps_uid");
3182
3183                 exit(EXIT_SUCCESS);
3184         }
3185
3186         if (wait_for_pid(pid))
3187                 goto out;
3188
3189         if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
3190                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3191                 goto out;
3192         }
3193
3194         fret = 0;
3195         log_debug("Ran test");
3196 out:
3197         safe_close(attr.userns_fd);
3198         safe_close(file1_fd);
3199         safe_close(file1_fd2);
3200         safe_close(open_tree_fd);
3201
3202         return fret;
3203 }
3204
3205 static int fscaps_idmapped_mounts_in_userns_separate_userns(void)
3206 {
3207         int fret = -1;
3208         int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3209         struct mount_attr attr = {
3210                 .attr_set = MOUNT_ATTR_IDMAP,
3211         };
3212         pid_t pid;
3213
3214         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3215         if (file1_fd < 0) {
3216                 log_stderr("failure: openat");
3217                 goto out;
3218         }
3219
3220         /* Skip if vfs caps are unsupported. */
3221         if (set_dummy_vfs_caps(file1_fd, 0, 1000)) {
3222                 log_stderr("failure: set_dummy_vfs_caps");
3223                 goto out;
3224         }
3225
3226         if (fremovexattr(file1_fd, "security.capability")) {
3227                 log_stderr("failure: fremovexattr");
3228                 goto out;
3229         }
3230
3231         /* change ownership of all files to uid 0 */
3232         if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3233                 log_stderr("failure: chown_r");
3234                 goto out;
3235         }
3236
3237         /* Changing mount properties on a detached mount. */
3238         attr.userns_fd  = get_userns_fd(20000, 10000, 10000);
3239         if (attr.userns_fd < 0) {
3240                 log_stderr("failure: get_userns_fd");
3241                 goto out;
3242         }
3243
3244         open_tree_fd = sys_open_tree(t_dir1_fd, "",
3245                                      AT_EMPTY_PATH |
3246                                      AT_NO_AUTOMOUNT |
3247                                      AT_SYMLINK_NOFOLLOW |
3248                                      OPEN_TREE_CLOEXEC |
3249                                      OPEN_TREE_CLONE);
3250         if (open_tree_fd < 0) {
3251                 log_stderr("failure: sys_open_tree");
3252                 goto out;
3253         }
3254
3255         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3256                 log_stderr("failure: sys_mount_setattr");
3257                 goto out;
3258         }
3259
3260         file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3261         if (file1_fd2 < 0) {
3262                 log_stderr("failure: openat");
3263                 goto out;
3264         }
3265
3266         pid = fork();
3267         if (pid < 0) {
3268                 log_stderr("failure: fork");
3269                 goto out;
3270         }
3271         if (pid == 0) {
3272                 int userns_fd;
3273
3274                 userns_fd = get_userns_fd(0, 10000, 10000);
3275                 if (userns_fd < 0)
3276                         die("failure: get_userns_fd");
3277
3278                 if (!switch_userns(userns_fd, 0, 0, false))
3279                         die("failure: switch_userns");
3280
3281                 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3282                         die("failure: set fscaps");
3283
3284                 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3285                         die("failure: expected_dummy_vfs_caps_uid");
3286
3287                 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000) && errno != EOVERFLOW)
3288                         die("failure: expected_dummy_vfs_caps_uid");
3289
3290                 exit(EXIT_SUCCESS);
3291         }
3292
3293         if (wait_for_pid(pid))
3294                 goto out;
3295
3296         if (!expected_dummy_vfs_caps_uid(file1_fd, 20000)) {
3297                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3298                 goto out;
3299         }
3300
3301         pid = fork();
3302         if (pid < 0) {
3303                 log_stderr("failure: fork");
3304                 goto out;
3305         }
3306         if (pid == 0) {
3307                 int userns_fd;
3308
3309                 userns_fd = get_userns_fd(0, 10000, 10000);
3310                 if (userns_fd < 0)
3311                         die("failure: get_userns_fd");
3312
3313                 if (!switch_userns(userns_fd, 0, 0, false))
3314                         die("failure: switch_userns");
3315
3316                 if (fremovexattr(file1_fd2, "security.capability"))
3317                         die("failure: fremovexattr");
3318                 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3319                         die("failure: expected_dummy_vfs_caps_uid");
3320                 if (errno != ENODATA)
3321                         die("failure: errno");
3322
3323                 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3324                         die("failure: set_dummy_vfs_caps");
3325
3326                 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3327                         die("failure: expected_dummy_vfs_caps_uid");
3328
3329                 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000) && errno != EOVERFLOW)
3330                         die("failure: expected_dummy_vfs_caps_uid");
3331
3332                 exit(EXIT_SUCCESS);
3333         }
3334
3335         if (wait_for_pid(pid))
3336                 goto out;
3337
3338         if (!expected_dummy_vfs_caps_uid(file1_fd, 21000)) {
3339                 log_stderr("failure: expected_dummy_vfs_caps_uid");
3340                 goto out;
3341         }
3342
3343         fret = 0;
3344         log_debug("Ran test");
3345 out:
3346         safe_close(attr.userns_fd);
3347         safe_close(file1_fd);
3348         safe_close(file1_fd2);
3349         safe_close(open_tree_fd);
3350
3351         return fret;
3352 }
3353
3354 /* Validate that when the IDMAP_MOUNT_TEST_RUN_SETID environment variable is set
3355  * to 1 that we are executed with setid privileges and if set to 0 we are not.
3356  * If the env variable isn't set the tests are not run.
3357  */
3358 static void __attribute__((constructor)) setuid_rexec(void)
3359 {
3360         const char *expected_euid_str, *expected_egid_str, *rexec;
3361
3362         rexec = getenv("IDMAP_MOUNT_TEST_RUN_SETID");
3363         /* This is a regular test-suite run. */
3364         if (!rexec)
3365                 return;
3366
3367         expected_euid_str = getenv("EXPECTED_EUID");
3368         expected_egid_str = getenv("EXPECTED_EGID");
3369
3370         if (expected_euid_str && expected_egid_str) {
3371                 uid_t expected_euid;
3372                 gid_t expected_egid;
3373
3374                 expected_euid = atoi(expected_euid_str);
3375                 expected_egid = atoi(expected_egid_str);
3376
3377                 if (strcmp(rexec, "1") == 0) {
3378                         /* we're expecting to run setid */
3379                         if ((getuid() != geteuid()) && (expected_euid == geteuid()) &&
3380                             (getgid() != getegid()) && (expected_egid == getegid()))
3381                                 exit(EXIT_SUCCESS);
3382                 } else if (strcmp(rexec, "0") == 0) {
3383                         /* we're expecting to not run setid */
3384                         if ((getuid() == geteuid()) && (expected_euid == geteuid()) &&
3385                             (getgid() == getegid()) && (expected_egid == getegid()))
3386                                 exit(EXIT_SUCCESS);
3387                         else
3388                                 die("failure: non-setid");
3389                 }
3390         }
3391
3392         exit(EXIT_FAILURE);
3393 }
3394
3395 /* Validate that setid transitions are handled correctly. */
3396 static int setid_binaries(void)
3397 {
3398         int fret = -1;
3399         int file1_fd = -EBADF, exec_fd = -EBADF;
3400         pid_t pid;
3401
3402         /* create a file to be used as setuid binary */
3403         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3404         if (file1_fd < 0) {
3405                 log_stderr("failure: openat");
3406                 goto out;
3407         }
3408
3409         /* open our own executable */
3410         exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3411         if (exec_fd < 0) {
3412                 log_stderr("failure: openat");
3413                 goto out;
3414         }
3415
3416         /* copy our own executable into the file we created */
3417         if (fd_to_fd(exec_fd, file1_fd)) {
3418                 log_stderr("failure: fd_to_fd");
3419                 goto out;
3420         }
3421
3422         /* chown the file to the uid and gid we want to assume */
3423         if (fchown(file1_fd, 5000, 5000)) {
3424                 log_stderr("failure: fchown");
3425                 goto out;
3426         }
3427
3428         /* set the setid bits and grant execute permissions to the group */
3429         if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3430                 log_stderr("failure: fchmod");
3431                 goto out;
3432         }
3433
3434         /* Verify that the sid bits got raised. */
3435         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3436                 log_stderr("failure: is_setid");
3437                 goto out;
3438         }
3439
3440         safe_close(exec_fd);
3441         safe_close(file1_fd);
3442
3443         /* Verify we run setid binary as uid and gid 5000 from the original
3444          * mount.
3445          */
3446         pid = fork();
3447         if (pid < 0) {
3448                 log_stderr("failure: fork");
3449                 goto out;
3450         }
3451         if (pid == 0) {
3452                 static char *envp[] = {
3453                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
3454                         "EXPECTED_EUID=5000",
3455                         "EXPECTED_EGID=5000",
3456                         NULL,
3457                 };
3458                 static char *argv[] = {
3459                         NULL,
3460                 };
3461
3462                 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 5000, 5000))
3463                         die("failure: expected_uid_gid");
3464
3465                 sys_execveat(t_dir1_fd, FILE1, argv, envp, 0);
3466                 die("failure: sys_execveat");
3467
3468                 exit(EXIT_FAILURE);
3469         }
3470         if (wait_for_pid(pid))
3471                 goto out;
3472
3473         fret = 0;
3474         log_debug("Ran test");
3475 out:
3476
3477         return fret;
3478 }
3479
3480 /* Validate that setid transitions are handled correctly on idmapped mounts. */
3481 static int setid_binaries_idmapped_mounts(void)
3482 {
3483         int fret = -1;
3484         int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3485         struct mount_attr attr = {
3486                 .attr_set = MOUNT_ATTR_IDMAP,
3487         };
3488         pid_t pid;
3489
3490         if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3491                 log_stderr("failure: mkdirat");
3492                 goto out;
3493         }
3494
3495         /* create a file to be used as setuid binary */
3496         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3497         if (file1_fd < 0) {
3498                 log_stderr("failure: openat");
3499                 goto out;
3500         }
3501
3502         /* open our own executable */
3503         exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3504         if (exec_fd < 0) {
3505                 log_stderr("failure:openat ");
3506                 goto out;
3507         }
3508
3509         /* copy our own executable into the file we created */
3510         if (fd_to_fd(exec_fd, file1_fd)) {
3511                 log_stderr("failure: fd_to_fd");
3512                 goto out;
3513         }
3514
3515         /* chown the file to the uid and gid we want to assume */
3516         if (fchown(file1_fd, 5000, 5000)) {
3517                 log_stderr("failure: fchown");
3518                 goto out;
3519         }
3520
3521         /* set the setid bits and grant execute permissions to the group */
3522         if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3523                 log_stderr("failure: fchmod");
3524                 goto out;
3525         }
3526
3527         /* Verify that the sid bits got raised. */
3528         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3529                 log_stderr("failure: is_setid");
3530                 goto out;
3531         }
3532
3533         safe_close(exec_fd);
3534         safe_close(file1_fd);
3535
3536         /* Changing mount properties on a detached mount. */
3537         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
3538         if (attr.userns_fd < 0) {
3539                 log_stderr("failure: get_userns_fd");
3540                 goto out;
3541         }
3542
3543         open_tree_fd = sys_open_tree(t_dir1_fd, "",
3544                                      AT_EMPTY_PATH |
3545                                      AT_NO_AUTOMOUNT |
3546                                      AT_SYMLINK_NOFOLLOW |
3547                                      OPEN_TREE_CLOEXEC |
3548                                      OPEN_TREE_CLONE);
3549         if (open_tree_fd < 0) {
3550                 log_stderr("failure: sys_open_tree");
3551                 goto out;
3552         }
3553
3554         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3555                 log_stderr("failure: sys_mount_setattr");
3556                 goto out;
3557         }
3558
3559         /* A detached mount will have an anonymous mount namespace attached to
3560          * it. This means that we can't execute setid binaries on a detached
3561          * mount because the mnt_may_suid() helper will fail the check_mount()
3562          * part of its check which compares the caller's mount namespace to the
3563          * detached mount's mount namespace. Since by definition an anonymous
3564          * mount namespace is not equale to any mount namespace currently in
3565          * use this can't work. So attach the mount to the filesystem first
3566          * before performing this check.
3567          */
3568         if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3569                 log_stderr("failure: sys_move_mount");
3570                 goto out;
3571         }
3572
3573         /* Verify we run setid binary as uid and gid 10000 from idmapped mount mount. */
3574         pid = fork();
3575         if (pid < 0) {
3576                 log_stderr("failure: fork");
3577                 goto out;
3578         }
3579         if (pid == 0) {
3580                 static char *envp[] = {
3581                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
3582                         "EXPECTED_EUID=15000",
3583                         "EXPECTED_EGID=15000",
3584                         NULL,
3585                 };
3586                 static char *argv[] = {
3587                         NULL,
3588                 };
3589
3590                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 15000, 15000))
3591                         die("failure: expected_uid_gid");
3592
3593                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3594                 die("failure: sys_execveat");
3595
3596                 exit(EXIT_FAILURE);
3597         }
3598
3599         if (wait_for_pid(pid))
3600                 goto out;
3601
3602         fret = 0;
3603         log_debug("Ran test");
3604 out:
3605         safe_close(exec_fd);
3606         safe_close(file1_fd);
3607         safe_close(open_tree_fd);
3608
3609         snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3610         sys_umount2(t_buf, MNT_DETACH);
3611         rm_r(t_mnt_fd, DIR1);
3612
3613         return fret;
3614 }
3615
3616 /* Validate that setid transitions are handled correctly on idmapped mounts
3617  * running in a user namespace where the uid and gid of the setid binary have no
3618  * mapping.
3619  */
3620 static int setid_binaries_idmapped_mounts_in_userns(void)
3621 {
3622         int fret = -1;
3623         int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3624         struct mount_attr attr = {
3625                 .attr_set = MOUNT_ATTR_IDMAP,
3626         };
3627         pid_t pid;
3628
3629         if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3630                 log_stderr("failure: ");
3631                 goto out;
3632         }
3633
3634         /* create a file to be used as setuid binary */
3635         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3636         if (file1_fd < 0) {
3637                 log_stderr("failure: openat");
3638                 goto out;
3639         }
3640
3641         /* open our own executable */
3642         exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3643         if (exec_fd < 0) {
3644                 log_stderr("failure: openat");
3645                 goto out;
3646         }
3647
3648         /* copy our own executable into the file we created */
3649         if (fd_to_fd(exec_fd, file1_fd)) {
3650                 log_stderr("failure: fd_to_fd");
3651                 goto out;
3652         }
3653
3654         safe_close(exec_fd);
3655
3656         /* chown the file to the uid and gid we want to assume */
3657         if (fchown(file1_fd, 5000, 5000)) {
3658                 log_stderr("failure: fchown");
3659                 goto out;
3660         }
3661
3662         /* set the setid bits and grant execute permissions to the group */
3663         if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3664                 log_stderr("failure: fchmod");
3665                 goto out;
3666         }
3667
3668         /* Verify that the sid bits got raised. */
3669         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3670                 log_stderr("failure: is_setid");
3671                 goto out;
3672         }
3673
3674         safe_close(file1_fd);
3675
3676         /* Changing mount properties on a detached mount. */
3677         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
3678         if (attr.userns_fd < 0) {
3679                 log_stderr("failure: get_userns_fd");
3680                 goto out;
3681         }
3682
3683         open_tree_fd = sys_open_tree(t_dir1_fd, "",
3684                                      AT_EMPTY_PATH |
3685                                      AT_NO_AUTOMOUNT |
3686                                      AT_SYMLINK_NOFOLLOW |
3687                                      OPEN_TREE_CLOEXEC |
3688                                      OPEN_TREE_CLONE);
3689         if (open_tree_fd < 0) {
3690                 log_stderr("failure: sys_open_tree");
3691                 goto out;
3692         }
3693
3694         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3695                 log_stderr("failure: sys_mount_setattr");
3696                 goto out;
3697         }
3698
3699         /* A detached mount will have an anonymous mount namespace attached to
3700          * it. This means that we can't execute setid binaries on a detached
3701          * mount because the mnt_may_suid() helper will fail the check_mount()
3702          * part of its check which compares the caller's mount namespace to the
3703          * detached mount's mount namespace. Since by definition an anonymous
3704          * mount namespace is not equale to any mount namespace currently in
3705          * use this can't work. So attach the mount to the filesystem first
3706          * before performing this check.
3707          */
3708         if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3709                 log_stderr("failure: sys_move_mount");
3710                 goto out;
3711         }
3712
3713         pid = fork();
3714         if (pid < 0) {
3715                 log_stderr("failure: fork");
3716                 goto out;
3717         }
3718         if (pid == 0) {
3719                 static char *envp[] = {
3720                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
3721                         "EXPECTED_EUID=5000",
3722                         "EXPECTED_EGID=5000",
3723                         NULL,
3724                 };
3725                 static char *argv[] = {
3726                         NULL,
3727                 };
3728
3729                 if (!switch_userns(attr.userns_fd, 0, 0, false))
3730                         die("failure: switch_userns");
3731
3732                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
3733                         die("failure: expected_uid_gid");
3734
3735                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3736                 die("failure: sys_execveat");
3737
3738                 exit(EXIT_FAILURE);
3739         }
3740
3741         if (wait_for_pid(pid)) {
3742                 log_stderr("failure: wait_for_pid");
3743                 goto out;
3744         }
3745
3746         file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3747         if (file1_fd < 0) {
3748                 log_stderr("failure: openat");
3749                 goto out;
3750         }
3751
3752         /* chown the file to the uid and gid we want to assume */
3753         if (fchown(file1_fd, 0, 0)) {
3754                 log_stderr("failure: fchown");
3755                 goto out;
3756         }
3757
3758         /* set the setid bits and grant execute permissions to the group */
3759         if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3760                 log_stderr("failure: fchmod");
3761                 goto out;
3762         }
3763
3764         /* Verify that the sid bits got raised. */
3765         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3766                 log_stderr("failure: is_setid");
3767                 goto out;
3768         }
3769
3770         safe_close(file1_fd);
3771
3772         pid = fork();
3773         if (pid < 0) {
3774                 log_stderr("failure: fork");
3775                 goto out;
3776         }
3777         if (pid == 0) {
3778                 static char *envp[] = {
3779                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
3780                         "EXPECTED_EUID=0",
3781                         "EXPECTED_EGID=0",
3782                         NULL,
3783                 };
3784                 static char *argv[] = {
3785                         NULL,
3786                 };
3787
3788                 if (!caps_supported()) {
3789                         log_debug("skip: capability library not installed");
3790                         exit(EXIT_SUCCESS);
3791                 }
3792
3793                 if (!switch_userns(attr.userns_fd, 5000, 5000, true))
3794                         die("failure: switch_userns");
3795
3796                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
3797                         die("failure: expected_uid_gid");
3798
3799                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3800                 die("failure: sys_execveat");
3801
3802                 exit(EXIT_FAILURE);
3803         }
3804
3805         if (wait_for_pid(pid)) {
3806                 log_stderr("failure: wait_for_pid");
3807                 goto out;
3808         }
3809
3810         file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3811         if (file1_fd < 0) {
3812                 log_stderr("failure: openat");
3813                 goto out;
3814         }
3815
3816         /* chown the file to the uid and gid we want to assume */
3817         if (fchown(file1_fd, 30000, 30000)) {
3818                 log_stderr("failure: fchown");
3819                 goto out;
3820         }
3821
3822         if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
3823                 log_stderr("failure: fchmod");
3824                 goto out;
3825         }
3826
3827         /* Verify that the sid bits got raised. */
3828         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3829                 log_stderr("failure: is_setid");
3830                 goto out;
3831         }
3832
3833         safe_close(file1_fd);
3834
3835         /* Verify that we can't assume a uid and gid of a setid binary for which
3836          * we have no mapping in our user namespace.
3837          */
3838         pid = fork();
3839         if (pid < 0) {
3840                 log_stderr("failure: fork");
3841                 goto out;
3842         }
3843         if (pid == 0) {
3844                 char expected_euid[100];
3845                 char expected_egid[100];
3846                 static char *envp[4] = {
3847                         NULL,
3848                         NULL,
3849                         NULL,
3850                         NULL,
3851                 };
3852                 static char *argv[] = {
3853                         NULL,
3854                 };
3855
3856                 if (!switch_userns(attr.userns_fd, 0, 0, false))
3857                         die("failure: switch_userns");
3858
3859                 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
3860                 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
3861                 envp[1] = expected_euid;
3862                 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
3863                 envp[2] = expected_egid;
3864
3865                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
3866                         die("failure: expected_uid_gid");
3867
3868                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3869                 die("failure: sys_execveat");
3870
3871                 exit(EXIT_FAILURE);
3872         }
3873
3874         if (wait_for_pid(pid)) {
3875                 log_stderr("failure: wait_for_pid");
3876                 goto out;
3877         }
3878
3879         fret = 0;
3880         log_debug("Ran test");
3881 out:
3882         safe_close(attr.userns_fd);
3883         safe_close(exec_fd);
3884         safe_close(file1_fd);
3885         safe_close(open_tree_fd);
3886
3887         snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3888         sys_umount2(t_buf, MNT_DETACH);
3889         rm_r(t_mnt_fd, DIR1);
3890
3891         return fret;
3892 }
3893
3894 /* Validate that setid transitions are handled correctly on idmapped mounts
3895  * running in a user namespace where the uid and gid of the setid binary have no
3896  * mapping.
3897  */
3898 static int setid_binaries_idmapped_mounts_in_userns_separate_userns(void)
3899 {
3900         int fret = -1;
3901         int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3902         struct mount_attr attr = {
3903                 .attr_set = MOUNT_ATTR_IDMAP,
3904         };
3905         pid_t pid;
3906
3907         if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3908                 log_stderr("failure: mkdirat");
3909                 goto out;
3910         }
3911
3912         /* create a file to be used as setuid binary */
3913         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3914         if (file1_fd < 0) {
3915                 log_stderr("failure: openat");
3916                 goto out;
3917         }
3918
3919         /* open our own executable */
3920         exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3921         if (exec_fd < 0) {
3922                 log_stderr("failure: openat");
3923                 goto out;
3924         }
3925
3926         /* copy our own executable into the file we created */
3927         if (fd_to_fd(exec_fd, file1_fd)) {
3928                 log_stderr("failure: fd_to_fd");
3929                 goto out;
3930         }
3931
3932         safe_close(exec_fd);
3933
3934         /* change ownership of all files to uid 0 */
3935         if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3936                 log_stderr("failure: chown_r");
3937                 goto out;
3938         }
3939
3940         /* chown the file to the uid and gid we want to assume */
3941         if (fchown(file1_fd, 25000, 25000)) {
3942                 log_stderr("failure: fchown");
3943                 goto out;
3944         }
3945
3946         /* set the setid bits and grant execute permissions to the group */
3947         if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3948                 log_stderr("failure: fchmod");
3949                 goto out;
3950         }
3951
3952         /* Verify that the sid bits got raised. */
3953         if (!is_setid(t_dir1_fd, FILE1, 0)) {
3954                 log_stderr("failure: is_setid");
3955                 goto out;
3956         }
3957
3958         safe_close(file1_fd);
3959
3960         /* Changing mount properties on a detached mount. */
3961         attr.userns_fd  = get_userns_fd(20000, 10000, 10000);
3962         if (attr.userns_fd < 0) {
3963                 log_stderr("failure: get_userns_fd");
3964                 goto out;
3965         }
3966
3967         open_tree_fd = sys_open_tree(t_dir1_fd, "",
3968                                      AT_EMPTY_PATH |
3969                                      AT_NO_AUTOMOUNT |
3970                                      AT_SYMLINK_NOFOLLOW |
3971                                      OPEN_TREE_CLOEXEC |
3972                                      OPEN_TREE_CLONE);
3973         if (open_tree_fd < 0) {
3974                 log_stderr("failure: sys_open_tree");
3975                 goto out;
3976         }
3977
3978         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3979                 log_stderr("failure: sys_mount_setattr");
3980                 goto out;
3981         }
3982
3983         /* A detached mount will have an anonymous mount namespace attached to
3984          * it. This means that we can't execute setid binaries on a detached
3985          * mount because the mnt_may_suid() helper will fail the check_mount()
3986          * part of its check which compares the caller's mount namespace to the
3987          * detached mount's mount namespace. Since by definition an anonymous
3988          * mount namespace is not equale to any mount namespace currently in
3989          * use this can't work. So attach the mount to the filesystem first
3990          * before performing this check.
3991          */
3992         if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3993                 log_stderr("failure: sys_move_mount");
3994                 goto out;
3995         }
3996
3997         pid = fork();
3998         if (pid < 0) {
3999                 log_stderr("failure: fork");
4000                 goto out;
4001         }
4002         if (pid == 0) {
4003                 int userns_fd;
4004                 static char *envp[] = {
4005                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
4006                         "EXPECTED_EUID=5000",
4007                         "EXPECTED_EGID=5000",
4008                         NULL,
4009                 };
4010                 static char *argv[] = {
4011                         NULL,
4012                 };
4013
4014                 userns_fd = get_userns_fd(0, 10000, 10000);
4015                 if (userns_fd < 0)
4016                         die("failure: get_userns_fd");
4017
4018                 if (!switch_userns(userns_fd, 0, 0, false))
4019                         die("failure: switch_userns");
4020
4021                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
4022                         die("failure: expected_uid_gid");
4023
4024                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4025                 die("failure: sys_execveat");
4026
4027                 exit(EXIT_FAILURE);
4028         }
4029
4030         if (wait_for_pid(pid)) {
4031                 log_stderr("failure: wait_for_pid");
4032                 goto out;
4033         }
4034
4035         file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4036         if (file1_fd < 0) {
4037                 log_stderr("failure: openat");
4038                 goto out;
4039         }
4040
4041         /* chown the file to the uid and gid we want to assume */
4042         if (fchown(file1_fd, 20000, 20000)) {
4043                 log_stderr("failure: fchown");
4044                 goto out;
4045         }
4046
4047         /* set the setid bits and grant execute permissions to the group */
4048         if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4049                 log_stderr("failure: fchmod");
4050                 goto out;
4051         }
4052
4053         /* Verify that the sid bits got raised. */
4054         if (!is_setid(t_dir1_fd, FILE1, 0)) {
4055                 log_stderr("failure: is_setid");
4056                 goto out;
4057         }
4058
4059         safe_close(file1_fd);
4060
4061         pid = fork();
4062         if (pid < 0) {
4063                 log_stderr("failure: fork");
4064                 goto out;
4065         }
4066         if (pid == 0) {
4067                 int userns_fd;
4068                 static char *envp[] = {
4069                         "IDMAP_MOUNT_TEST_RUN_SETID=1",
4070                         "EXPECTED_EUID=0",
4071                         "EXPECTED_EGID=0",
4072                         NULL,
4073                 };
4074                 static char *argv[] = {
4075                         NULL,
4076                 };
4077
4078                 userns_fd = get_userns_fd(0, 10000, 10000);
4079                 if (userns_fd < 0)
4080                         die("failure: get_userns_fd");
4081
4082                 if (!caps_supported()) {
4083                         log_debug("skip: capability library not installed");
4084                         exit(EXIT_SUCCESS);
4085                 }
4086
4087                 if (!switch_userns(userns_fd, 1000, 1000, true))
4088                         die("failure: switch_userns");
4089
4090                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
4091                         die("failure: expected_uid_gid");
4092
4093                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4094                 die("failure: sys_execveat");
4095
4096                 exit(EXIT_FAILURE);
4097         }
4098         if (wait_for_pid(pid)) {
4099                 log_stderr("failure: wait_for_pid");
4100                 goto out;
4101         }
4102
4103         file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4104         if (file1_fd < 0) {
4105                 log_stderr("failure: openat");
4106                 goto out;
4107         }
4108
4109         /* chown the file to the uid and gid we want to assume */
4110         if (fchown(file1_fd, 0, 0)) {
4111                 log_stderr("failure: fchown");
4112                 goto out;
4113         }
4114
4115         if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
4116                 log_stderr("failure: fchmod");
4117                 goto out;
4118         }
4119
4120         /* Verify that the sid bits got raised. */
4121         if (!is_setid(t_dir1_fd, FILE1, 0)) {
4122                 log_stderr("failure: is_setid");
4123                 goto out;
4124         }
4125
4126         safe_close(file1_fd);
4127
4128         /* Verify that we can't assume a uid and gid of a setid binary for
4129          * which we have no mapping in our user namespace.
4130          */
4131         pid = fork();
4132         if (pid < 0) {
4133                 log_stderr("failure: fork");
4134                 goto out;
4135         }
4136         if (pid == 0) {
4137                 int userns_fd;
4138                 char expected_euid[100];
4139                 char expected_egid[100];
4140                 static char *envp[4] = {
4141                         NULL,
4142                         NULL,
4143                         NULL,
4144                         NULL,
4145                 };
4146                 static char *argv[] = {
4147                         NULL,
4148                 };
4149
4150                 userns_fd = get_userns_fd(0, 10000, 10000);
4151                 if (userns_fd < 0)
4152                         die("failure: get_userns_fd");
4153
4154                 if (!switch_userns(userns_fd, 0, 0, false))
4155                         die("failure: switch_userns");
4156
4157                 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
4158                 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
4159                 envp[1] = expected_euid;
4160                 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
4161                 envp[2] = expected_egid;
4162
4163                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4164                         die("failure: expected_uid_gid");
4165
4166                 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4167                 die("failure: sys_execveat");
4168
4169                 exit(EXIT_FAILURE);
4170         }
4171         if (wait_for_pid(pid)) {
4172                 log_stderr("failure: wait_for_pid");
4173                 goto out;
4174         }
4175
4176         fret = 0;
4177         log_debug("Ran test");
4178 out:
4179         safe_close(attr.userns_fd);
4180         safe_close(exec_fd);
4181         safe_close(file1_fd);
4182         safe_close(open_tree_fd);
4183
4184         snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4185         sys_umount2(t_buf, MNT_DETACH);
4186         rm_r(t_mnt_fd, DIR1);
4187
4188         return fret;
4189 }
4190
4191 static int sticky_bit_unlink(void)
4192 {
4193         int fret = -1;
4194         int dir_fd = -EBADF;
4195         pid_t pid;
4196
4197         if (!caps_supported())
4198                 return 0;
4199
4200         /* create directory */
4201         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4202                 log_stderr("failure: mkdirat");
4203                 goto out;
4204         }
4205
4206         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4207         if (dir_fd < 0) {
4208                 log_stderr("failure: openat");
4209                 goto out;
4210         }
4211
4212         if (fchown(dir_fd, 0, 0)) {
4213                 log_stderr("failure: fchown");
4214                 goto out;
4215         }
4216
4217         if (fchmod(dir_fd, 0777)) {
4218                 log_stderr("failure: fchmod");
4219                 goto out;
4220         }
4221
4222         /* create regular file via mknod */
4223         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4224                 log_stderr("failure: mknodat");
4225                 goto out;
4226         }
4227         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4228                 log_stderr("failure: fchownat");
4229                 goto out;
4230         }
4231         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4232                 log_stderr("failure: fchmodat");
4233                 goto out;
4234         }
4235
4236         /* create regular file via mknod */
4237         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4238                 log_stderr("failure: mknodat");
4239                 goto out;
4240         }
4241         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4242                 log_stderr("failure: fchownat");
4243                 goto out;
4244         }
4245         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4246                 log_stderr("failure: fchmodat");
4247                 goto out;
4248         }
4249
4250         /* The sticky bit is not set so we must be able to delete files not
4251          * owned by us.
4252          */
4253         pid = fork();
4254         if (pid < 0) {
4255                 log_stderr("failure: fork");
4256                 goto out;
4257         }
4258         if (pid == 0) {
4259                 if (!switch_ids(1000, 1000))
4260                         die("failure: switch_ids");
4261
4262                 if (unlinkat(dir_fd, FILE1, 0))
4263                         die("failure: unlinkat");
4264
4265                 if (unlinkat(dir_fd, FILE2, 0))
4266                         die("failure: unlinkat");
4267
4268                 exit(EXIT_SUCCESS);
4269         }
4270         if (wait_for_pid(pid)) {
4271                 log_stderr("failure: wait_for_pid");
4272                 goto out;
4273         }
4274
4275         /* set sticky bit */
4276         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4277                 log_stderr("failure: fchmod");
4278                 goto out;
4279         }
4280
4281         /* validate sticky bit is set */
4282         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4283                 log_stderr("failure: is_sticky");
4284                 goto out;
4285         }
4286
4287         /* create regular file via mknod */
4288         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4289                 log_stderr("failure: mknodat");
4290                 goto out;
4291         }
4292         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4293                 log_stderr("failure: fchownat");
4294                 goto out;
4295         }
4296         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4297                 log_stderr("failure: fchmodat");
4298                 goto out;
4299         }
4300
4301         /* create regular file via mknod */
4302         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4303                 log_stderr("failure: mknodat");
4304                 goto out;
4305         }
4306         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4307                 log_stderr("failure: fchownat");
4308                 goto out;
4309         }
4310         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4311                 log_stderr("failure: fchmodat");
4312                 goto out;
4313         }
4314
4315         /* The sticky bit is set so we must not be able to delete files not
4316          * owned by us.
4317          */
4318         pid = fork();
4319         if (pid < 0) {
4320                 log_stderr("failure: fork");
4321                 goto out;
4322         }
4323         if (pid == 0) {
4324                 if (!switch_ids(1000, 1000))
4325                         die("failure: switch_ids");
4326
4327                 if (!unlinkat(dir_fd, FILE1, 0))
4328                         die("failure: unlinkat");
4329                 if (errno != EPERM)
4330                         die("failure: errno");
4331
4332                 if (!unlinkat(dir_fd, FILE2, 0))
4333                         die("failure: unlinkat");
4334                 if (errno != EPERM)
4335                         die("failure: errno");
4336
4337                 exit(EXIT_SUCCESS);
4338         }
4339         if (wait_for_pid(pid)) {
4340                 log_stderr("failure: wait_for_pid");
4341                 goto out;
4342         }
4343
4344         /* The sticky bit is set and we own the files so we must be able to
4345          * delete the files now.
4346          */
4347         pid = fork();
4348         if (pid < 0) {
4349                 log_stderr("failure: fork");
4350                 goto out;
4351         }
4352         if (pid == 0) {
4353                 /* change ownership */
4354                 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4355                         die("failure: fchownat");
4356                 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4357                         die("failure: expected_uid_gid");
4358                 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4359                         die("failure: fchownat");
4360                 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4361                         die("failure: expected_uid_gid");
4362
4363                 if (!switch_ids(1000, 1000))
4364                         die("failure: switch_ids");
4365
4366                 if (unlinkat(dir_fd, FILE1, 0))
4367                         die("failure: unlinkat");
4368
4369                 if (unlinkat(dir_fd, FILE2, 0))
4370                         die("failure: unlinkat");
4371
4372                 exit(EXIT_SUCCESS);
4373         }
4374         if (wait_for_pid(pid)) {
4375                 log_stderr("failure: wait_for_pid");
4376                 goto out;
4377         }
4378
4379         /* change uid to unprivileged user */
4380         if (fchown(dir_fd, 1000, -1)) {
4381                 log_stderr("failure: fchown");
4382                 goto out;
4383         }
4384         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4385                 log_stderr("failure: fchmod");
4386                 goto out;
4387         }
4388         /* validate sticky bit is set */
4389         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4390                 log_stderr("failure: is_sticky");
4391                 goto out;
4392         }
4393
4394         /* create regular file via mknod */
4395         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4396                 log_stderr("failure: mknodat");
4397                 goto out;
4398         }
4399         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4400                 log_stderr("failure: fchownat");
4401                 goto out;
4402         }
4403         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4404                 log_stderr("failure: fchmodat");
4405                 goto out;
4406         }
4407
4408         /* create regular file via mknod */
4409         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4410                 log_stderr("failure: mknodat");
4411                 goto out;
4412         }
4413         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4414                 log_stderr("failure: fchownat");
4415                 goto out;
4416         }
4417         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4418                 log_stderr("failure: fchmodat");
4419                 goto out;
4420         }
4421
4422         /* The sticky bit is set and we own the directory so we must be able to
4423          * delete the files now.
4424          */
4425         pid = fork();
4426         if (pid < 0) {
4427                 log_stderr("failure: fork");
4428                 goto out;
4429         }
4430         if (pid == 0) {
4431                 if (!switch_ids(1000, 1000))
4432                         die("failure: switch_ids");
4433
4434                 if (unlinkat(dir_fd, FILE1, 0))
4435                         die("failure: unlinkat");
4436
4437                 if (unlinkat(dir_fd, FILE2, 0))
4438                         die("failure: unlinkat");
4439
4440                 exit(EXIT_SUCCESS);
4441         }
4442         if (wait_for_pid(pid)) {
4443                 log_stderr("failure: wait_for_pid");
4444                 goto out;
4445         }
4446
4447         fret = 0;
4448         log_debug("Ran test");
4449 out:
4450         safe_close(dir_fd);
4451
4452         return fret;
4453 }
4454
4455 static int sticky_bit_unlink_idmapped_mounts(void)
4456 {
4457         int fret = -1;
4458         int dir_fd = -EBADF, open_tree_fd = -EBADF;
4459         struct mount_attr attr = {
4460                 .attr_set = MOUNT_ATTR_IDMAP,
4461         };
4462         pid_t pid;
4463
4464         if (!caps_supported())
4465                 return 0;
4466
4467         /* create directory */
4468         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4469                 log_stderr("failure: mkdirat");
4470                 goto out;
4471         }
4472
4473         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4474         if (dir_fd < 0) {
4475                 log_stderr("failure: openat");
4476                 goto out;
4477         }
4478         if (fchown(dir_fd, 10000, 10000)) {
4479                 log_stderr("failure: fchown");
4480                 goto out;
4481         }
4482         if (fchmod(dir_fd, 0777)) {
4483                 log_stderr("failure: fchmod");
4484                 goto out;
4485         }
4486
4487         /* create regular file via mknod */
4488         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4489                 log_stderr("failure: mknodat");
4490                 goto out;
4491         }
4492         if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4493                 log_stderr("failure: fchownat");
4494                 goto out;
4495         }
4496         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4497                 log_stderr("failure: fchmodat");
4498                 goto out;
4499         }
4500
4501         /* create regular file via mknod */
4502         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4503                 log_stderr("failure: mknodat");
4504                 goto out;
4505         }
4506         if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4507                 log_stderr("failure: fchownat");
4508                 goto out;
4509         }
4510         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4511                 log_stderr("failure: fchmodat");
4512                 goto out;
4513         }
4514
4515         /* Changing mount properties on a detached mount. */
4516         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
4517         if (attr.userns_fd < 0) {
4518                 log_stderr("failure: get_userns_fd");
4519                 goto out;
4520         }
4521
4522         open_tree_fd = sys_open_tree(dir_fd, "",
4523                                      AT_EMPTY_PATH |
4524                                      AT_NO_AUTOMOUNT |
4525                                      AT_SYMLINK_NOFOLLOW |
4526                                      OPEN_TREE_CLOEXEC |
4527                                      OPEN_TREE_CLONE);
4528         if (open_tree_fd < 0) {
4529                 log_stderr("failure: sys_open_tree");
4530                 goto out;
4531         }
4532
4533         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4534                 log_stderr("failure: sys_mount_setattr");
4535                 goto out;
4536         }
4537
4538         /* The sticky bit is not set so we must be able to delete files not
4539          * owned by us.
4540          */
4541         pid = fork();
4542         if (pid < 0) {
4543                 log_stderr("failure: fork");
4544                 goto out;
4545         }
4546         if (pid == 0) {
4547                 if (!switch_ids(1000, 1000))
4548                         die("failure: switch_ids");
4549
4550                 if (unlinkat(open_tree_fd, FILE1, 0))
4551                         die("failure: unlinkat");
4552
4553                 if (unlinkat(open_tree_fd, FILE2, 0))
4554                         die("failure: unlinkat");
4555
4556                 exit(EXIT_SUCCESS);
4557         }
4558         if (wait_for_pid(pid)) {
4559                 log_stderr("failure: wait_for_pid");
4560                 goto out;
4561         }
4562
4563         /* set sticky bit */
4564         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4565                 log_stderr("failure: fchmod");
4566                 goto out;
4567         }
4568
4569         /* validate sticky bit is set */
4570         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4571                 log_stderr("failure: is_sticky");
4572                 goto out;
4573         }
4574
4575         /* create regular file via mknod */
4576         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4577                 log_stderr("failure: mknodat");
4578                 goto out;
4579         }
4580         if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4581                 log_stderr("failure: fchownat");
4582                 goto out;
4583         }
4584         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4585                 log_stderr("failure: fchmodat");
4586                 goto out;
4587         }
4588
4589         /* create regular file via mknod */
4590         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4591                 log_stderr("failure: mknodat");
4592                 goto out;
4593         }
4594         if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4595                 log_stderr("failure: fchownat");
4596                 goto out;
4597         }
4598         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4599                 log_stderr("failure: fchmodat");
4600                 goto out;
4601         }
4602
4603         /* The sticky bit is set so we must not be able to delete files not
4604          * owned by us.
4605          */
4606         pid = fork();
4607         if (pid < 0) {
4608                 log_stderr("failure: fork");
4609                 goto out;
4610         }
4611         if (pid == 0) {
4612                 if (!switch_ids(1000, 1000))
4613                         die("failure: switch_ids");
4614
4615                 if (!unlinkat(open_tree_fd, FILE1, 0))
4616                         die("failure: unlinkat");
4617                 if (errno != EPERM)
4618                         die("failure: errno");
4619
4620                 if (!unlinkat(open_tree_fd, FILE2, 0))
4621                         die("failure: unlinkat");
4622                 if (errno != EPERM)
4623                         die("failure: errno");
4624
4625                 exit(EXIT_SUCCESS);
4626         }
4627         if (wait_for_pid(pid)) {
4628                 log_stderr("failure: wait_for_pid");
4629                 goto out;
4630         }
4631
4632         /* The sticky bit is set and we own the files so we must be able to
4633          * delete the files now.
4634          */
4635         pid = fork();
4636         if (pid < 0) {
4637                 log_stderr("failure: fork");
4638                 goto out;
4639         }
4640         if (pid == 0) {
4641                 /* change ownership */
4642                 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
4643                         die("failure: fchownat");
4644                 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
4645                         die("failure: expected_uid_gid");
4646                 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
4647                         die("failure: fchownat");
4648                 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
4649                         die("failure: expected_uid_gid");
4650
4651                 if (!switch_ids(1000, 1000))
4652                         die("failure: switch_ids");
4653
4654                 if (unlinkat(open_tree_fd, FILE1, 0))
4655                         die("failure: unlinkat");
4656
4657                 if (unlinkat(open_tree_fd, FILE2, 0))
4658                         die("failure: unlinkat");
4659
4660                 exit(EXIT_SUCCESS);
4661         }
4662         if (wait_for_pid(pid)) {
4663                 log_stderr("failure: wait_for_pid");
4664                 goto out;
4665         }
4666
4667         /* change uid to unprivileged user */
4668         if (fchown(dir_fd, 11000, -1)) {
4669                 log_stderr("failure: fchown");
4670                 goto out;
4671         }
4672         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4673                 log_stderr("failure: fchmod");
4674                 goto out;
4675         }
4676         /* validate sticky bit is set */
4677         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4678                 log_stderr("failure: is_sticky");
4679                 goto out;
4680         }
4681
4682         /* create regular file via mknod */
4683         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4684                 log_stderr("failure: mknodat");
4685                 goto out;
4686         }
4687         if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4688                 log_stderr("failure: fchownat");
4689                 goto out;
4690         }
4691         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4692                 log_stderr("failure: fchmodat");
4693                 goto out;
4694         }
4695
4696         /* create regular file via mknod */
4697         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4698                 log_stderr("failure: mknodat");
4699                 goto out;
4700         }
4701         if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4702                 log_stderr("failure: fchownat");
4703                 goto out;
4704         }
4705         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4706                 log_stderr("failure: fchmodat");
4707                 goto out;
4708         }
4709
4710         /* The sticky bit is set and we own the directory so we must be able to
4711          * delete the files now.
4712          */
4713         pid = fork();
4714         if (pid < 0) {
4715                 log_stderr("failure: fork");
4716                 goto out;
4717         }
4718         if (pid == 0) {
4719                 if (!switch_ids(1000, 1000))
4720                         die("failure: switch_ids");
4721
4722                 if (unlinkat(open_tree_fd, FILE1, 0))
4723                         die("failure: unlinkat");
4724
4725                 if (unlinkat(open_tree_fd, FILE2, 0))
4726                         die("failure: unlinkat");
4727
4728                 exit(EXIT_SUCCESS);
4729         }
4730         if (wait_for_pid(pid)) {
4731                 log_stderr("failure: wait_for_pid");
4732                 goto out;
4733         }
4734
4735         fret = 0;
4736         log_debug("Ran test");
4737 out:
4738         safe_close(attr.userns_fd);
4739         safe_close(dir_fd);
4740         safe_close(open_tree_fd);
4741
4742         return fret;
4743 }
4744
4745 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
4746  * operations in a user namespace.
4747  */
4748 static int sticky_bit_unlink_idmapped_mounts_in_userns(void)
4749 {
4750         int fret = -1;
4751         int dir_fd = -EBADF, open_tree_fd = -EBADF;
4752         struct mount_attr attr = {
4753                 .attr_set = MOUNT_ATTR_IDMAP,
4754         };
4755         pid_t pid;
4756
4757         if (!caps_supported())
4758                 return 0;
4759
4760         /* create directory */
4761         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4762                 log_stderr("failure: mkdirat");
4763                 goto out;
4764         }
4765
4766         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4767         if (dir_fd < 0) {
4768                 log_stderr("failure: openat");
4769                 goto out;
4770         }
4771         if (fchown(dir_fd, 0, 0)) {
4772                 log_stderr("failure: fchown");
4773                 goto out;
4774         }
4775         if (fchmod(dir_fd, 0777)) {
4776                 log_stderr("failure: fchmod");
4777                 goto out;
4778         }
4779
4780         /* create regular file via mknod */
4781         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4782                 log_stderr("failure: mknodat");
4783                 goto out;
4784         }
4785         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4786                 log_stderr("failure: fchownat");
4787                 goto out;
4788         }
4789         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4790                 log_stderr("failure: fchmodat");
4791                 goto out;
4792         }
4793
4794         /* create regular file via mknod */
4795         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4796                 log_stderr("failure: mknodat");
4797                 goto out;
4798         }
4799         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4800                 log_stderr("failure: fchownat");
4801                 goto out;
4802         }
4803         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4804                 log_stderr("failure: fchmodat");
4805                 goto out;
4806         }
4807
4808         /* Changing mount properties on a detached mount. */
4809         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
4810         if (attr.userns_fd < 0) {
4811                 log_stderr("failure: get_userns_fd");
4812                 goto out;
4813         }
4814
4815         open_tree_fd = sys_open_tree(dir_fd, "",
4816                                      AT_EMPTY_PATH |
4817                                      AT_NO_AUTOMOUNT |
4818                                      AT_SYMLINK_NOFOLLOW |
4819                                      OPEN_TREE_CLOEXEC |
4820                                      OPEN_TREE_CLONE);
4821         if (open_tree_fd < 0) {
4822                 log_stderr("failure: sys_open_tree");
4823                 goto out;
4824         }
4825
4826         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4827                 log_stderr("failure: sys_mount_setattr");
4828                 goto out;
4829         }
4830
4831         /* The sticky bit is not set so we must be able to delete files not
4832          * owned by us.
4833          */
4834         pid = fork();
4835         if (pid < 0) {
4836                 log_stderr("failure: fork");
4837                 goto out;
4838         }
4839         if (pid == 0) {
4840                 if (!caps_supported()) {
4841                         log_debug("skip: capability library not installed");
4842                         exit(EXIT_SUCCESS);
4843                 }
4844
4845                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4846                         die("failure: switch_userns");
4847
4848                 if (unlinkat(dir_fd, FILE1, 0))
4849                         die("failure: unlinkat");
4850
4851                 if (unlinkat(dir_fd, FILE2, 0))
4852                         die("failure: unlinkat");
4853
4854                 exit(EXIT_SUCCESS);
4855         }
4856         if (wait_for_pid(pid)) {
4857                 log_stderr("failure: wait_for_pid");
4858                 goto out;
4859         }
4860
4861         /* set sticky bit */
4862         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4863                 log_stderr("failure: fchmod");
4864                 goto out;
4865         }
4866
4867         /* validate sticky bit is set */
4868         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4869                 log_stderr("failure: is_sticky");
4870                 goto out;
4871         }
4872
4873         /* create regular file via mknod */
4874         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4875                 log_stderr("failure: mknodat");
4876                 goto out;
4877         }
4878         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4879                 log_stderr("failure: fchownat");
4880                 goto out;
4881         }
4882         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4883                 log_stderr("failure: fchmodat");
4884                 goto out;
4885         }
4886
4887         /* create regular file via mknod */
4888         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4889                 log_stderr("failure: mknodat");
4890                 goto out;
4891         }
4892         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4893                 log_stderr("failure: fchownat");
4894                 goto out;
4895         }
4896         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4897                 log_stderr("failure: fchmodat");
4898                 goto out;
4899         }
4900
4901         /* The sticky bit is set so we must not be able to delete files not
4902          * owned by us.
4903          */
4904         pid = fork();
4905         if (pid < 0) {
4906                 log_stderr("failure: fork");
4907                 goto out;
4908         }
4909         if (pid == 0) {
4910                 if (!caps_supported()) {
4911                         log_debug("skip: capability library not installed");
4912                         exit(EXIT_SUCCESS);
4913                 }
4914
4915                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4916                         die("failure: switch_userns");
4917
4918                 if (!unlinkat(dir_fd, FILE1, 0))
4919                         die("failure: unlinkat");
4920                 if (errno != EPERM)
4921                         die("failure: errno");
4922
4923                 if (!unlinkat(dir_fd, FILE2, 0))
4924                         die("failure: unlinkat");
4925                 if (errno != EPERM)
4926                         die("failure: errno");
4927
4928                 if (!unlinkat(open_tree_fd, FILE1, 0))
4929                         die("failure: unlinkat");
4930                 if (errno != EPERM)
4931                         die("failure: errno");
4932
4933                 if (!unlinkat(open_tree_fd, FILE2, 0))
4934                         die("failure: unlinkat");
4935                 if (errno != EPERM)
4936                         die("failure: errno");
4937
4938                 exit(EXIT_SUCCESS);
4939         }
4940         if (wait_for_pid(pid)) {
4941                 log_stderr("failure: wait_for_pid");
4942                 goto out;
4943         }
4944
4945         /* The sticky bit is set and we own the files so we must be able to
4946          * delete the files now.
4947          */
4948         pid = fork();
4949         if (pid < 0) {
4950                 log_stderr("failure: fork");
4951                 goto out;
4952         }
4953         if (pid == 0) {
4954                 /* change ownership */
4955                 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4956                         die("failure: fchownat");
4957                 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4958                         die("failure: expected_uid_gid");
4959                 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4960                         die("failure: fchownat");
4961                 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4962                         die("failure: expected_uid_gid");
4963
4964                 if (!caps_supported()) {
4965                         log_debug("skip: capability library not installed");
4966                         exit(EXIT_SUCCESS);
4967                 }
4968
4969                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4970                         die("failure: switch_userns");
4971
4972                 if (!unlinkat(dir_fd, FILE1, 0))
4973                         die("failure: unlinkat");
4974                 if (errno != EPERM)
4975                         die("failure: errno");
4976
4977                 if (!unlinkat(dir_fd, FILE2, 0))
4978                         die("failure: unlinkat");
4979                 if (errno != EPERM)
4980                         die("failure: errno");
4981
4982                 if (unlinkat(open_tree_fd, FILE1, 0))
4983                         die("failure: unlinkat");
4984
4985                 if (unlinkat(open_tree_fd, FILE2, 0))
4986                         die("failure: unlinkat");
4987
4988                 exit(EXIT_SUCCESS);
4989         }
4990         if (wait_for_pid(pid)) {
4991                 log_stderr("failure: wait_for_pid");
4992                 goto out;
4993         }
4994
4995         /* change uid to unprivileged user */
4996         if (fchown(dir_fd, 1000, -1)) {
4997                 log_stderr("failure: fchown");
4998                 goto out;
4999         }
5000         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5001                 log_stderr("failure: fchmod");
5002                 goto out;
5003         }
5004         /* validate sticky bit is set */
5005         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5006                 log_stderr("failure: is_sticky");
5007                 goto out;
5008         }
5009
5010         /* create regular file via mknod */
5011         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5012                 log_stderr("failure: mknodat");
5013                 goto out;
5014         }
5015         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5016                 log_stderr("failure: fchownat");
5017                 goto out;
5018         }
5019         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5020                 log_stderr("failure: fchmodat");
5021                 goto out;
5022         }
5023
5024         /* create regular file via mknod */
5025         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5026                 log_stderr("failure: mknodat");
5027                 goto out;
5028         }
5029         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5030                 log_stderr("failure: fchownat");
5031                 goto out;
5032         }
5033         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5034                 log_stderr("failure: fchmodat");
5035                 goto out;
5036         }
5037
5038         /* The sticky bit is set and we own the directory so we must be able to
5039          * delete the files now.
5040          */
5041         pid = fork();
5042         if (pid < 0) {
5043                 log_stderr("failure: fork");
5044                 goto out;
5045         }
5046         if (pid == 0) {
5047                 if (!caps_supported()) {
5048                         log_debug("skip: capability library not installed");
5049                         exit(EXIT_SUCCESS);
5050                 }
5051
5052                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5053                         die("failure: switch_userns");
5054
5055                 /* we don't own the directory from the original mount */
5056                 if (!unlinkat(dir_fd, FILE1, 0))
5057                         die("failure: unlinkat");
5058                 if (errno != EPERM)
5059                         die("failure: errno");
5060
5061                 if (!unlinkat(dir_fd, FILE2, 0))
5062                         die("failure: unlinkat");
5063                 if (errno != EPERM)
5064                         die("failure: errno");
5065
5066                 /* we own the file from the idmapped mount */
5067                 if (unlinkat(open_tree_fd, FILE1, 0))
5068                         die("failure: unlinkat");
5069                 if (unlinkat(open_tree_fd, FILE2, 0))
5070                         die("failure: unlinkat");
5071
5072                 exit(EXIT_SUCCESS);
5073         }
5074         if (wait_for_pid(pid)) {
5075                 log_stderr("failure: wait_for_pid");
5076                 goto out;
5077         }
5078
5079         fret = 0;
5080         log_debug("Ran test");
5081 out:
5082         safe_close(attr.userns_fd);
5083         safe_close(dir_fd);
5084         safe_close(open_tree_fd);
5085
5086         return fret;
5087 }
5088
5089 static int sticky_bit_rename(void)
5090 {
5091         int fret = -1;
5092         int dir_fd = -EBADF;
5093         pid_t pid;
5094
5095         if (!caps_supported())
5096                 return 0;
5097
5098         /* create directory */
5099         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5100                 log_stderr("failure: mkdirat");
5101                 goto out;
5102         }
5103
5104         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5105         if (dir_fd < 0) {
5106                 log_stderr("failure: openat");
5107                 goto out;
5108         }
5109         if (fchown(dir_fd, 0, 0)) {
5110                 log_stderr("failure: fchown");
5111                 goto out;
5112         }
5113         if (fchmod(dir_fd, 0777)) {
5114                 log_stderr("failure: fchmod");
5115                 goto out;
5116         }
5117
5118         /* create regular file via mknod */
5119         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5120                 log_stderr("failure: mknodat");
5121                 goto out;
5122         }
5123         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5124                 log_stderr("failure: fchownat");
5125                 goto out;
5126         }
5127         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5128                 log_stderr("failure: fchmodat");
5129                 goto out;
5130         }
5131
5132         /* create regular file via mknod */
5133         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5134                 log_stderr("failure: mknodat");
5135                 goto out;
5136         }
5137         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5138                 log_stderr("failure: fchownat");
5139                 goto out;
5140         }
5141         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5142                 log_stderr("failure: fchmodat");
5143                 goto out;
5144         }
5145
5146         /* The sticky bit is not set so we must be able to delete files not
5147          * owned by us.
5148          */
5149         pid = fork();
5150         if (pid < 0) {
5151                 log_stderr("failure: fork");
5152                 goto out;
5153         }
5154         if (pid == 0) {
5155                 if (!switch_ids(1000, 1000))
5156                         die("failure: switch_ids");
5157
5158                 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5159                         die("failure: renameat");
5160
5161                 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5162                         die("failure: renameat");
5163
5164                 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5165                         die("failure: renameat");
5166
5167                 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5168                         die("failure: renameat");
5169
5170                 exit(EXIT_SUCCESS);
5171         }
5172         if (wait_for_pid(pid)) {
5173                 log_stderr("failure: wait_for_pid");
5174                 goto out;
5175         }
5176
5177         /* set sticky bit */
5178         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5179                 log_stderr("failure: fchmod");
5180                 goto out;
5181         }
5182
5183         /* validate sticky bit is set */
5184         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5185                 log_stderr("failure: is_sticky");
5186                 goto out;
5187         }
5188
5189         /* The sticky bit is set so we must not be able to delete files not
5190          * owned by us.
5191          */
5192         pid = fork();
5193         if (pid < 0) {
5194                 log_stderr("failure: fork");
5195                 goto out;
5196         }
5197         if (pid == 0) {
5198                 if (!switch_ids(1000, 1000))
5199                         die("failure: switch_ids");
5200
5201                 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5202                         die("failure: renameat");
5203                 if (errno != EPERM)
5204                         die("failure: errno");
5205
5206                 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5207                         die("failure: renameat");
5208                 if (errno != EPERM)
5209                         die("failure: errno");
5210
5211                 exit(EXIT_SUCCESS);
5212         }
5213         if (wait_for_pid(pid)) {
5214                 log_stderr("failure: wait_for_pid");
5215                 goto out;
5216         }
5217
5218         /* The sticky bit is set and we own the files so we must be able to
5219          * delete the files now.
5220          */
5221         pid = fork();
5222         if (pid < 0) {
5223                 log_stderr("failure: fork");
5224                 goto out;
5225         }
5226         if (pid == 0) {
5227                 /* change ownership */
5228                 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5229                         die("failure: fchownat");
5230                 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5231                         die("failure: expected_uid_gid");
5232                 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5233                         die("failure: fchownat");
5234                 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5235                         die("failure: expected_uid_gid");
5236
5237                 if (!switch_ids(1000, 1000))
5238                         die("failure: switch_ids");
5239
5240                 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5241                         die("failure: renameat");
5242
5243                 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5244                         die("failure: renameat");
5245
5246                 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5247                         die("failure: renameat");
5248
5249                 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5250                         die("failure: renameat");
5251
5252                 exit(EXIT_SUCCESS);
5253         }
5254         if (wait_for_pid(pid)) {
5255                 log_stderr("failure: wait_for_pid");
5256                 goto out;
5257         }
5258
5259         /* change uid to unprivileged user */
5260         if (fchown(dir_fd, 1000, -1)) {
5261                 log_stderr("failure: fchown");
5262                 goto out;
5263         }
5264         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5265                 log_stderr("failure: fchmod");
5266                 goto out;
5267         }
5268         /* validate sticky bit is set */
5269         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5270                 log_stderr("failure: is_sticky");
5271                 goto out;
5272         }
5273
5274
5275         /* The sticky bit is set and we own the directory so we must be able to
5276          * delete the files now.
5277          */
5278         pid = fork();
5279         if (pid < 0) {
5280                 log_stderr("failure: fork");
5281                 goto out;
5282         }
5283         if (pid == 0) {
5284                 if (!switch_ids(1000, 1000))
5285                         die("failure: switch_ids");
5286
5287                 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5288                         die("failure: renameat");
5289
5290                 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5291                         die("failure: renameat");
5292
5293                 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5294                         die("failure: renameat");
5295
5296                 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5297                         die("failure: renameat");
5298
5299                 exit(EXIT_SUCCESS);
5300         }
5301         if (wait_for_pid(pid)) {
5302                 log_stderr("failure: wait_for_pid");
5303                 goto out;
5304         }
5305
5306         fret = 0;
5307         log_debug("Ran test");
5308 out:
5309         safe_close(dir_fd);
5310
5311         return fret;
5312 }
5313
5314 static int sticky_bit_rename_idmapped_mounts(void)
5315 {
5316         int fret = -1;
5317         int dir_fd = -EBADF, open_tree_fd = -EBADF;
5318         struct mount_attr attr = {
5319                 .attr_set = MOUNT_ATTR_IDMAP,
5320         };
5321         pid_t pid;
5322
5323         if (!caps_supported())
5324                 return 0;
5325
5326         /* create directory */
5327         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5328                 log_stderr("failure: mkdirat");
5329                 goto out;
5330         }
5331
5332         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5333         if (dir_fd < 0) {
5334                 log_stderr("failure: openat");
5335                 goto out;
5336         }
5337
5338         if (fchown(dir_fd, 10000, 10000)) {
5339                 log_stderr("failure: fchown");
5340                 goto out;
5341         }
5342
5343         if (fchmod(dir_fd, 0777)) {
5344                 log_stderr("failure: fchmod");
5345                 goto out;
5346         }
5347
5348         /* create regular file via mknod */
5349         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5350                 log_stderr("failure: mknodat");
5351                 goto out;
5352         }
5353         if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
5354                 log_stderr("failure: fchownat");
5355                 goto out;
5356         }
5357         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5358                 log_stderr("failure: fchmodat");
5359                 goto out;
5360         }
5361
5362         /* create regular file via mknod */
5363         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5364                 log_stderr("failure: mknodat");
5365                 goto out;
5366         }
5367         if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
5368                 log_stderr("failure: fchownat");
5369                 goto out;
5370         }
5371         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5372                 log_stderr("failure: fchmodat");
5373                 goto out;
5374         }
5375
5376         /* Changing mount properties on a detached mount. */
5377         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
5378         if (attr.userns_fd < 0) {
5379                 log_stderr("failure: get_userns_fd");
5380                 goto out;
5381         }
5382
5383         open_tree_fd = sys_open_tree(dir_fd, "",
5384                                      AT_EMPTY_PATH |
5385                                      AT_NO_AUTOMOUNT |
5386                                      AT_SYMLINK_NOFOLLOW |
5387                                      OPEN_TREE_CLOEXEC |
5388                                      OPEN_TREE_CLONE);
5389         if (open_tree_fd < 0) {
5390                 log_stderr("failure: sys_open_tree");
5391                 goto out;
5392         }
5393
5394         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5395                 log_stderr("failure: sys_mount_setattr");
5396                 goto out;
5397         }
5398
5399         /* The sticky bit is not set so we must be able to delete files not
5400          * owned by us.
5401          */
5402         pid = fork();
5403         if (pid < 0) {
5404                 log_stderr("failure: fork");
5405                 goto out;
5406         }
5407         if (pid == 0) {
5408                 if (!switch_ids(1000, 1000))
5409                         die("failure: switch_ids");
5410
5411                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5412                         die("failure: renameat");
5413
5414                 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5415                         die("failure: renameat");
5416
5417                 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5418                         die("failure: renameat");
5419
5420                 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5421                         die("failure: renameat");
5422
5423                 exit(EXIT_SUCCESS);
5424         }
5425         if (wait_for_pid(pid)) {
5426                 log_stderr("failure: wait_for_pid");
5427                 goto out;
5428         }
5429
5430         /* set sticky bit */
5431         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5432                 log_stderr("failure: fchmod");
5433                 goto out;
5434         }
5435
5436         /* validate sticky bit is set */
5437         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5438                 log_stderr("failure: is_sticky");
5439                 goto out;
5440         }
5441
5442         /* The sticky bit is set so we must not be able to delete files not
5443          * owned by us.
5444          */
5445         pid = fork();
5446         if (pid < 0) {
5447                 log_stderr("failure: fork");
5448                 goto out;
5449         }
5450         if (pid == 0) {
5451                 if (!switch_ids(1000, 1000))
5452                         die("failure: switch_ids");
5453
5454                 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5455                         die("failure: renameat");
5456                 if (errno != EPERM)
5457                         die("failure: errno");
5458
5459                 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5460                         die("failure: renameat");
5461                 if (errno != EPERM)
5462                         die("failure: errno");
5463
5464                 exit(EXIT_SUCCESS);
5465         }
5466         if (wait_for_pid(pid)) {
5467                 log_stderr("failure: wait_for_pid");
5468                 goto out;
5469         }
5470
5471         /* The sticky bit is set and we own the files so we must be able to
5472          * delete the files now.
5473          */
5474         pid = fork();
5475         if (pid < 0) {
5476                 log_stderr("failure: fork");
5477                 goto out;
5478         }
5479         if (pid == 0) {
5480                 /* change ownership */
5481                 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
5482                         die("failure: fchownat");
5483                 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
5484                         die("failure: expected_uid_gid");
5485                 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
5486                         die("failure: fchownat");
5487                 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
5488                         die("failure: expected_uid_gid");
5489
5490                 if (!switch_ids(1000, 1000))
5491                         die("failure: switch_ids");
5492
5493                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5494                         die("failure: renameat");
5495
5496                 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5497                         die("failure: renameat");
5498
5499                 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5500                         die("failure: renameat");
5501
5502                 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5503                         die("failure: renameat");
5504
5505                 exit(EXIT_SUCCESS);
5506         }
5507         if (wait_for_pid(pid)) {
5508                 log_stderr("failure: wait_for_pid");
5509                 goto out;
5510         }
5511
5512         /* change uid to unprivileged user */
5513         if (fchown(dir_fd, 11000, -1)) {
5514                 log_stderr("failure: fchown");
5515                 goto out;
5516         }
5517         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5518                 log_stderr("failure: fchmod");
5519                 goto out;
5520         }
5521         /* validate sticky bit is set */
5522         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5523                 log_stderr("failure: is_sticky");
5524                 goto out;
5525         }
5526
5527         /* The sticky bit is set and we own the directory so we must be able to
5528          * delete the files now.
5529          */
5530         pid = fork();
5531         if (pid < 0) {
5532                 log_stderr("failure: fork");
5533                 goto out;
5534         }
5535         if (pid == 0) {
5536                 if (!switch_ids(1000, 1000))
5537                         die("failure: switch_ids");
5538
5539                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5540                         die("failure: renameat");
5541
5542                 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5543                         die("failure: renameat");
5544
5545                 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5546                         die("failure: renameat");
5547
5548                 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5549                         die("failure: renameat");
5550
5551                 exit(EXIT_SUCCESS);
5552         }
5553         if (wait_for_pid(pid)) {
5554                 log_stderr("failure: wait_for_pid");
5555                 goto out;
5556         }
5557
5558         fret = 0;
5559         log_debug("Ran test");
5560 out:
5561         safe_close(attr.userns_fd);
5562         safe_close(dir_fd);
5563         safe_close(open_tree_fd);
5564
5565         return fret;
5566 }
5567
5568 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
5569  * operations in a user namespace.
5570  */
5571 static int sticky_bit_rename_idmapped_mounts_in_userns(void)
5572 {
5573         int fret = -1;
5574         int dir_fd = -EBADF, open_tree_fd = -EBADF;
5575         struct mount_attr attr = {
5576                 .attr_set = MOUNT_ATTR_IDMAP,
5577         };
5578         pid_t pid;
5579
5580         if (!caps_supported())
5581                 return 0;
5582
5583         /* create directory */
5584         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5585                 log_stderr("failure: mkdirat");
5586                 goto out;
5587         }
5588
5589         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5590         if (dir_fd < 0) {
5591                 log_stderr("failure: openat");
5592                 goto out;
5593         }
5594         if (fchown(dir_fd, 0, 0)) {
5595                 log_stderr("failure: fchown");
5596                 goto out;
5597         }
5598         if (fchmod(dir_fd, 0777)) {
5599                 log_stderr("failure: fchmod");
5600                 goto out;
5601         }
5602
5603         /* create regular file via mknod */
5604         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5605                 log_stderr("failure: mknodat");
5606                 goto out;
5607         }
5608         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5609                 log_stderr("failure: fchownat");
5610                 goto out;
5611         }
5612         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5613                 log_stderr("failure: fchmodat");
5614                 goto out;
5615         }
5616
5617         /* create regular file via mknod */
5618         if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5619                 log_stderr("failure: mknodat");
5620                 goto out;
5621         }
5622         if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5623                 log_stderr("failure: fchownat");
5624                 goto out;
5625         }
5626         if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5627                 log_stderr("failure: fchmodat");
5628                 goto out;
5629         }
5630
5631         /* Changing mount properties on a detached mount. */
5632         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
5633         if (attr.userns_fd < 0) {
5634                 log_stderr("failure: get_userns_fd");
5635                 goto out;
5636         }
5637
5638         open_tree_fd = sys_open_tree(dir_fd, "",
5639                                      AT_EMPTY_PATH |
5640                                      AT_NO_AUTOMOUNT |
5641                                      AT_SYMLINK_NOFOLLOW |
5642                                      OPEN_TREE_CLOEXEC |
5643                                      OPEN_TREE_CLONE);
5644         if (open_tree_fd < 0) {
5645                 log_stderr("failure: sys_open_tree");
5646                 goto out;
5647         }
5648
5649         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5650                 log_stderr("failure: sys_mount_setattr");
5651                 goto out;
5652         }
5653
5654         /* The sticky bit is not set so we must be able to delete files not
5655          * owned by us.
5656          */
5657         pid = fork();
5658         if (pid < 0) {
5659                 log_stderr("failure: fork");
5660                 goto out;
5661         }
5662         if (pid == 0) {
5663                 if (!caps_supported()) {
5664                         log_debug("skip: capability library not installed");
5665                         exit(EXIT_SUCCESS);
5666                 }
5667
5668                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5669                         die("failure: switch_userns");
5670
5671                 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5672                         die("failure: renameat");
5673
5674                 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5675                         die("failure: renameat");
5676
5677                 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5678                         die("failure: renameat");
5679
5680                 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5681                         die("failure: renameat");
5682
5683                 exit(EXIT_SUCCESS);
5684         }
5685         if (wait_for_pid(pid)) {
5686                 log_stderr("failure: wait_for_pid");
5687                 goto out;
5688         }
5689
5690         /* set sticky bit */
5691         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5692                 log_stderr("failure: fchmod");
5693                 goto out;
5694         }
5695
5696         /* validate sticky bit is set */
5697         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5698                 log_stderr("failure: is_sticky");
5699                 goto out;
5700         }
5701
5702         /* The sticky bit is set so we must not be able to delete files not
5703          * owned by us.
5704          */
5705         pid = fork();
5706         if (pid < 0) {
5707                 log_stderr("failure: fork");
5708                 goto out;
5709         }
5710         if (pid == 0) {
5711                 if (!caps_supported()) {
5712                         log_debug("skip: capability library not installed");
5713                         exit(EXIT_SUCCESS);
5714                 }
5715
5716                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5717                         die("failure: switch_userns");
5718
5719                 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5720                         die("failure: renameat");
5721                 if (errno != EPERM)
5722                         die("failure: errno");
5723
5724                 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5725                         die("failure: renameat");
5726                 if (errno != EPERM)
5727                         die("failure: errno");
5728
5729                 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5730                         die("failure: renameat");
5731                 if (errno != EPERM)
5732                         die("failure: errno");
5733
5734                 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5735                         die("failure: renameat");
5736                 if (errno != EPERM)
5737                         die("failure: errno");
5738
5739                 exit(EXIT_SUCCESS);
5740         }
5741         if (wait_for_pid(pid)) {
5742                 log_stderr("failure: wait_for_pid");
5743                 goto out;
5744         }
5745
5746         /* The sticky bit is set and we own the files so we must be able to
5747          * delete the files now.
5748          */
5749         pid = fork();
5750         if (pid < 0) {
5751                 log_stderr("failure: fork");
5752                 goto out;
5753         }
5754         if (pid == 0) {
5755                 /* change ownership */
5756                 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5757                         die("failure: fchownat");
5758                 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5759                         die("failure: expected_uid_gid");
5760                 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5761                         die("failure: fchownat");
5762                 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5763                         die("failure: expected_uid_gid");
5764
5765                 if (!caps_supported()) {
5766                         log_debug("skip: capability library not installed");
5767                         exit(EXIT_SUCCESS);
5768                 }
5769
5770                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5771                         die("failure: switch_userns");
5772
5773                 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5774                         die("failure: renameat");
5775                 if (errno != EPERM)
5776                         die("failure: errno");
5777
5778                 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5779                         die("failure: renameat");
5780                 if (errno != EPERM)
5781                         die("failure: errno");
5782
5783                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5784                         die("failure: renameat");
5785
5786                 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5787                         die("failure: renameat");
5788
5789                 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5790                         die("failure: renameat");
5791
5792                 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5793                         die("failure: renameat");
5794
5795                 exit(EXIT_SUCCESS);
5796         }
5797         if (wait_for_pid(pid)) {
5798                 log_stderr("failure: wait_for_pid");
5799                 goto out;
5800         }
5801
5802         /* change uid to unprivileged user */
5803         if (fchown(dir_fd, 1000, -1)) {
5804                 log_stderr("failure: fchown");
5805                 goto out;
5806         }
5807         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5808                 log_stderr("failure: fchmod");
5809                 goto out;
5810         }
5811         /* validate sticky bit is set */
5812         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5813                 log_stderr("failure: is_sticky");
5814                 goto out;
5815         }
5816
5817         /* The sticky bit is set and we own the directory so we must be able to
5818          * delete the files now.
5819          */
5820         pid = fork();
5821         if (pid < 0) {
5822                 log_stderr("failure: fork");
5823                 goto out;
5824         }
5825         if (pid == 0) {
5826                 if (!caps_supported()) {
5827                         log_debug("skip: capability library not installed");
5828                         exit(EXIT_SUCCESS);
5829                 }
5830
5831                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5832                         die("failure: switch_userns");
5833
5834                 /* we don't own the directory from the original mount */
5835                 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5836                         die("failure: renameat");
5837                 if (errno != EPERM)
5838                         die("failure: errno");
5839
5840                 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5841                         die("failure: renameat");
5842                 if (errno != EPERM)
5843                         die("failure: errno");
5844
5845                 /* we own the file from the idmapped mount */
5846                 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5847                         die("failure: renameat");
5848
5849                 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5850                         die("failure: renameat");
5851
5852                 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5853                         die("failure: renameat");
5854
5855                 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5856                         die("failure: renameat");
5857
5858                 exit(EXIT_SUCCESS);
5859         }
5860         if (wait_for_pid(pid)) {
5861                 log_stderr("failure: wait_for_pid");
5862                 goto out;
5863         }
5864
5865         fret = 0;
5866         log_debug("Ran test");
5867 out:
5868         safe_close(open_tree_fd);
5869         safe_close(attr.userns_fd);
5870         safe_close(dir_fd);
5871
5872         return fret;
5873 }
5874
5875 /* Validate that protected symlinks work correctly. */
5876 static int protected_symlinks(void)
5877 {
5878         int fret = -1;
5879         int dir_fd = -EBADF, fd = -EBADF;
5880         pid_t pid;
5881
5882         if (!protected_symlinks_enabled())
5883                 return 0;
5884
5885         if (!caps_supported())
5886                 return 0;
5887
5888         /* create directory */
5889         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5890                 log_stderr("failure: mkdirat");
5891                 goto out;
5892         }
5893
5894         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5895         if (dir_fd < 0) {
5896                 log_stderr("failure: openat");
5897                 goto out;
5898         }
5899         if (fchown(dir_fd, 0, 0)) {
5900                 log_stderr("failure: fchown");
5901                 goto out;
5902         }
5903         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5904                 log_stderr("failure: fchmod");
5905                 goto out;
5906         }
5907         /* validate sticky bit is set */
5908         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5909                 log_stderr("failure: is_sticky");
5910                 goto out;
5911         }
5912
5913         /* create regular file via mknod */
5914         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5915                 log_stderr("failure: mknodat");
5916                 goto out;
5917         }
5918         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5919                 log_stderr("failure: fchownat");
5920                 goto out;
5921         }
5922         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5923                 log_stderr("failure: fchmodat");
5924                 goto out;
5925         }
5926
5927         /* create symlinks */
5928         if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
5929                 log_stderr("failure: symlinkat");
5930                 goto out;
5931         }
5932         if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
5933                 log_stderr("failure: fchownat");
5934                 goto out;
5935         }
5936         if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
5937                 log_stderr("failure: expected_uid_gid");
5938                 goto out;
5939         }
5940         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5941                 log_stderr("failure: expected_uid_gid");
5942                 goto out;
5943         }
5944
5945         if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
5946                 log_stderr("failure: symlinkat");
5947                 goto out;
5948         }
5949         if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
5950                 log_stderr("failure: fchownat");
5951                 goto out;
5952         }
5953         if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
5954                 log_stderr("failure: expected_uid_gid");
5955                 goto out;
5956         }
5957         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5958                 log_stderr("failure: expected_uid_gid");
5959                 goto out;
5960         }
5961
5962         if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
5963                 log_stderr("failure: symlinkat");
5964                 goto out;
5965         }
5966         if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
5967                 log_stderr("failure: fchownat");
5968                 goto out;
5969         }
5970         if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
5971                 log_stderr("failure: expected_uid_gid");
5972                 goto out;
5973         }
5974         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5975                 log_stderr("failure: expected_uid_gid");
5976                 goto out;
5977         }
5978
5979         /* validate file can be directly read */
5980         fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
5981         if (fd < 0) {
5982                 log_stderr("failure: openat");
5983                 goto out;
5984         }
5985         safe_close(fd);
5986
5987         /* validate file can be read through own symlink */
5988         fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
5989         if (fd < 0) {
5990                 log_stderr("failure: openat");
5991                 goto out;
5992         }
5993         safe_close(fd);
5994
5995         pid = fork();
5996         if (pid < 0) {
5997                 log_stderr("failure: fork");
5998                 goto out;
5999         }
6000         if (pid == 0) {
6001                 if (!switch_ids(1000, 1000))
6002                         die("failure: switch_ids");
6003
6004                 /* validate file can be directly read */
6005                 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6006                 if (fd < 0)
6007                         die("failure: openat");
6008                 safe_close(fd);
6009
6010                 /* validate file can be read through own symlink */
6011                 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6012                 if (fd < 0)
6013                         die("failure: openat");
6014                 safe_close(fd);
6015
6016                 /* validate file can be read through root symlink */
6017                 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6018                 if (fd < 0)
6019                         die("failure: openat");
6020                 safe_close(fd);
6021
6022                 /* validate file can't be read through other users symlink */
6023                 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6024                 if (fd >= 0)
6025                         die("failure: openat");
6026                 if (errno != EACCES)
6027                         die("failure: errno");
6028
6029                 exit(EXIT_SUCCESS);
6030         }
6031         if (wait_for_pid(pid)) {
6032                 log_stderr("failure: wait_for_pid");
6033                 goto out;
6034         }
6035
6036         pid = fork();
6037         if (pid < 0) {
6038                 log_stderr("failure: fork");
6039                 goto out;
6040         }
6041         if (pid == 0) {
6042                 if (!switch_ids(2000, 2000))
6043                         die("failure: switch_ids");
6044
6045                 /* validate file can be directly read */
6046                 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6047                 if (fd < 0)
6048                         die("failure: openat");
6049                 safe_close(fd);
6050
6051                 /* validate file can be read through own symlink */
6052                 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6053                 if (fd < 0)
6054                         die("failure: openat");
6055                 safe_close(fd);
6056
6057                 /* validate file can be read through root symlink */
6058                 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6059                 if (fd < 0)
6060                         die("failure: openat");
6061                 safe_close(fd);
6062
6063                 /* validate file can't be read through other users symlink */
6064                 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6065                 if (fd >= 0)
6066                         die("failure: openat");
6067                 if (errno != EACCES)
6068                         die("failure: errno");
6069
6070                 exit(EXIT_SUCCESS);
6071         }
6072         if (wait_for_pid(pid)) {
6073                 log_stderr("failure: wait_for_pid");
6074                 goto out;
6075         }
6076
6077         fret = 0;
6078         log_debug("Ran test");
6079 out:
6080         safe_close(fd);
6081         safe_close(dir_fd);
6082
6083         return fret;
6084 }
6085
6086 /* Validate that protected symlinks work correctly on idmapped mounts. */
6087 static int protected_symlinks_idmapped_mounts(void)
6088 {
6089         int fret = -1;
6090         int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6091         struct mount_attr attr = {
6092                 .attr_set = MOUNT_ATTR_IDMAP,
6093         };
6094         pid_t pid;
6095
6096         if (!protected_symlinks_enabled())
6097                 return 0;
6098
6099         if (!caps_supported())
6100                 return 0;
6101
6102         /* create directory */
6103         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6104                 log_stderr("failure: mkdirat");
6105                 goto out;
6106         }
6107
6108         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6109         if (dir_fd < 0) {
6110                 log_stderr("failure: openat");
6111                 goto out;
6112         }
6113         if (fchown(dir_fd, 10000, 10000)) {
6114                 log_stderr("failure: fchown");
6115                 goto out;
6116         }
6117         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6118                 log_stderr("failure: fchmod");
6119                 goto out;
6120         }
6121         /* validate sticky bit is set */
6122         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6123                 log_stderr("failure: is_sticky");
6124                 goto out;
6125         }
6126
6127         /* create regular file via mknod */
6128         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6129                 log_stderr("failure: mknodat");
6130                 goto out;
6131         }
6132         if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
6133                 log_stderr("failure: fchownat");
6134                 goto out;
6135         }
6136         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6137                 log_stderr("failure: fchmodat");
6138                 goto out;
6139         }
6140
6141         /* create symlinks */
6142         if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6143                 log_stderr("failure: symlinkat");
6144                 goto out;
6145         }
6146         if (fchownat(dir_fd, SYMLINK_USER1, 10000, 10000, AT_SYMLINK_NOFOLLOW)) {
6147                 log_stderr("failure: fchownat");
6148                 goto out;
6149         }
6150         if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
6151                 log_stderr("failure: expected_uid_gid");
6152                 goto out;
6153         }
6154         if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6155                 log_stderr("failure: expected_uid_gid");
6156                 goto out;
6157         }
6158
6159         if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6160                 log_stderr("failure: symlinkat");
6161                 goto out;
6162         }
6163         if (fchownat(dir_fd, SYMLINK_USER2, 11000, 11000, AT_SYMLINK_NOFOLLOW)) {
6164                 log_stderr("failure: fchownat");
6165                 goto out;
6166         }
6167         if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 11000, 11000)) {
6168                 log_stderr("failure: expected_uid_gid");
6169                 goto out;
6170         }
6171         if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6172                 log_stderr("failure: expected_uid_gid");
6173                 goto out;
6174         }
6175
6176         if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6177                 log_stderr("failure: symlinkat");
6178                 goto out;
6179         }
6180         if (fchownat(dir_fd, SYMLINK_USER3, 12000, 12000, AT_SYMLINK_NOFOLLOW)) {
6181                 log_stderr("failure: fchownat");
6182                 goto out;
6183         }
6184         if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
6185                 log_stderr("failure: expected_uid_gid");
6186                 goto out;
6187         }
6188         if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6189                 log_stderr("failure: expected_uid_gid");
6190                 goto out;
6191         }
6192
6193         /* Changing mount properties on a detached mount. */
6194         attr.userns_fd  = get_userns_fd(10000, 0, 10000);
6195         if (attr.userns_fd < 0) {
6196                 log_stderr("failure: get_userns_fd");
6197                 goto out;
6198         }
6199
6200         open_tree_fd = sys_open_tree(t_dir1_fd, "",
6201                                      AT_EMPTY_PATH |
6202                                      AT_NO_AUTOMOUNT |
6203                                      AT_SYMLINK_NOFOLLOW |
6204                                      OPEN_TREE_CLOEXEC |
6205                                      OPEN_TREE_CLONE);
6206         if (open_tree_fd < 0) {
6207                 log_stderr("failure: open_tree_fd");
6208                 goto out;
6209         }
6210
6211         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6212                 log_stderr("failure: sys_mount_setattr");
6213                 goto out;
6214         }
6215
6216         /* validate file can be directly read */
6217         fd = openat(open_tree_fd, DIR1 "/"  FILE1, O_RDONLY | O_CLOEXEC, 0);
6218         if (fd < 0) {
6219                 log_stderr("failure: openat");
6220                 goto out;
6221         }
6222         safe_close(fd);
6223
6224         /* validate file can be read through own symlink */
6225         fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6226         if (fd < 0) {
6227                 log_stderr("failure: openat");
6228                 goto out;
6229         }
6230         safe_close(fd);
6231
6232         pid = fork();
6233         if (pid < 0) {
6234                 log_stderr("failure: fork");
6235                 goto out;
6236         }
6237         if (pid == 0) {
6238                 if (!switch_ids(1000, 1000))
6239                         die("failure: switch_ids");
6240
6241                 /* validate file can be directly read */
6242                 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6243                 if (fd < 0)
6244                         die("failure: openat");
6245                 safe_close(fd);
6246
6247                 /* validate file can be read through own symlink */
6248                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6249                 if (fd < 0)
6250                         die("failure: openat");
6251                 safe_close(fd);
6252
6253                 /* validate file can be read through root symlink */
6254                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6255                 if (fd < 0)
6256                         die("failure: openat");
6257                 safe_close(fd);
6258
6259                 /* validate file can't be read through other users symlink */
6260                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6261                 if (fd >= 0)
6262                         die("failure: openat");
6263                 if (errno != EACCES)
6264                         die("failure: errno");
6265
6266                 exit(EXIT_SUCCESS);
6267         }
6268         if (wait_for_pid(pid)) {
6269                 log_stderr("failure: wait_for_pid");
6270                 goto out;
6271         }
6272
6273         pid = fork();
6274         if (pid < 0) {
6275                 log_stderr("failure: fork");
6276                 goto out;
6277         }
6278         if (pid == 0) {
6279                 if (!switch_ids(2000, 2000))
6280                         die("failure: switch_ids");
6281
6282                 /* validate file can be directly read */
6283                 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6284                 if (fd < 0)
6285                         die("failure: openat");
6286                 safe_close(fd);
6287
6288                 /* validate file can be read through own symlink */
6289                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6290                 if (fd < 0)
6291                         die("failure: openat");
6292                 safe_close(fd);
6293
6294                 /* validate file can be read through root symlink */
6295                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6296                 if (fd < 0)
6297                         die("failure: openat");
6298                 safe_close(fd);
6299
6300                 /* validate file can't be read through other users symlink */
6301                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6302                 if (fd >= 0)
6303                         die("failure: openat");
6304                 if (errno != EACCES)
6305                         die("failure: errno");
6306
6307                 exit(EXIT_SUCCESS);
6308         }
6309         if (wait_for_pid(pid)) {
6310                 log_stderr("failure: wait_for_pid");
6311                 goto out;
6312         }
6313
6314         fret = 0;
6315         log_debug("Ran test");
6316 out:
6317         safe_close(attr.userns_fd);
6318         safe_close(fd);
6319         safe_close(dir_fd);
6320         safe_close(open_tree_fd);
6321
6322         return fret;
6323 }
6324
6325 /* Validate that protected symlinks work correctly on idmapped mounts inside a
6326  * user namespace.
6327  */
6328 static int protected_symlinks_idmapped_mounts_in_userns(void)
6329 {
6330         int fret = -1;
6331         int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6332         struct mount_attr attr = {
6333                 .attr_set = MOUNT_ATTR_IDMAP,
6334         };
6335         pid_t pid;
6336
6337         if (!protected_symlinks_enabled())
6338                 return 0;
6339
6340         if (!caps_supported())
6341                 return 0;
6342
6343         /* create directory */
6344         if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6345                 log_stderr("failure: mkdirat");
6346                 goto out;
6347         }
6348
6349         dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6350         if (dir_fd < 0) {
6351                 log_stderr("failure: openat");
6352                 goto out;
6353         }
6354         if (fchown(dir_fd, 0, 0)) {
6355                 log_stderr("failure: fchown");
6356                 goto out;
6357         }
6358         if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6359                 log_stderr("failure: fchmod");
6360                 goto out;
6361         }
6362         /* validate sticky bit is set */
6363         if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6364                 log_stderr("failure: is_sticky");
6365                 goto out;
6366         }
6367
6368         /* create regular file via mknod */
6369         if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6370                 log_stderr("failure: mknodat");
6371                 goto out;
6372         }
6373         if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6374                 log_stderr("failure: fchownat");
6375                 goto out;
6376         }
6377         if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6378                 log_stderr("failure: fchmodat");
6379                 goto out;
6380         }
6381
6382         /* create symlinks */
6383         if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6384                 log_stderr("failure: symlinkat");
6385                 goto out;
6386         }
6387         if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6388                 log_stderr("failure: fchownat");
6389                 goto out;
6390         }
6391         if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6392                 log_stderr("failure: expected_uid_gid");
6393                 goto out;
6394         }
6395         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6396                 log_stderr("failure: expected_uid_gid");
6397                 goto out;
6398         }
6399
6400         if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6401                 log_stderr("failure: symlinkat");
6402                 goto out;
6403         }
6404         if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6405                 log_stderr("failure: fchownat");
6406                 goto out;
6407         }
6408         if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6409                 log_stderr("failure: expected_uid_gid");
6410                 goto out;
6411         }
6412         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6413                 log_stderr("failure: expected_uid_gid");
6414                 goto out;
6415         }
6416
6417         if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6418                 log_stderr("failure: symlinkat");
6419                 goto out;
6420         }
6421         if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6422                 log_stderr("failure: fchownat");
6423                 goto out;
6424         }
6425         if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6426                 log_stderr("failure: expected_uid_gid");
6427                 goto out;
6428         }
6429         if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6430                 log_stderr("failure: expected_uid_gid");
6431                 goto out;
6432         }
6433
6434         /* Changing mount properties on a detached mount. */
6435         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
6436         if (attr.userns_fd < 0) {
6437                 log_stderr("failure: get_userns_fd");
6438                 goto out;
6439         }
6440
6441         open_tree_fd = sys_open_tree(t_dir1_fd, "",
6442                                      AT_EMPTY_PATH |
6443                                      AT_NO_AUTOMOUNT |
6444                                      AT_SYMLINK_NOFOLLOW |
6445                                      OPEN_TREE_CLOEXEC |
6446                                      OPEN_TREE_CLONE);
6447         if (open_tree_fd < 0) {
6448                 log_stderr("failure: sys_open_tree");
6449                 goto out;
6450         }
6451
6452         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6453                 log_stderr("failure: sys_mount_setattr");
6454                 goto out;
6455         }
6456
6457         /* validate file can be directly read */
6458         fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6459         if (fd < 0) {
6460                 log_stderr("failure: openat");
6461                 goto out;
6462         }
6463         safe_close(fd);
6464
6465         /* validate file can be read through own symlink */
6466         fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6467         if (fd < 0) {
6468                 log_stderr("failure: openat");
6469                 goto out;
6470         }
6471         safe_close(fd);
6472
6473         pid = fork();
6474         if (pid < 0) {
6475                 log_stderr("failure: fork");
6476                 goto out;
6477         }
6478         if (pid == 0) {
6479                 if (!caps_supported()) {
6480                         log_debug("skip: capability library not installed");
6481                         exit(EXIT_SUCCESS);
6482                 }
6483
6484                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
6485                         die("failure: switch_userns");
6486
6487                 /* validate file can be directly read */
6488                 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6489                 if (fd < 0)
6490                         die("failure: openat");
6491                 safe_close(fd);
6492
6493                 /* validate file can be read through own symlink */
6494                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6495                 if (fd < 0)
6496                         die("failure: openat");
6497                 safe_close(fd);
6498
6499                 /* validate file can be read through root symlink */
6500                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6501                 if (fd < 0)
6502                         die("failure: openat");
6503                 safe_close(fd);
6504
6505                 /* validate file can't be read through other users symlink */
6506                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6507                 if (fd >= 0)
6508                         die("failure: openat");
6509                 if (errno != EACCES)
6510                         die("failure: errno");
6511
6512                 exit(EXIT_SUCCESS);
6513         }
6514         if (wait_for_pid(pid)) {
6515                 log_stderr("failure: wait_for_pid");
6516                 goto out;
6517         }
6518
6519         pid = fork();
6520         if (pid < 0) {
6521                 log_stderr("failure: fork");
6522                 goto out;
6523         }
6524         if (pid == 0) {
6525                 if (!caps_supported()) {
6526                         log_debug("skip: capability library not installed");
6527                         exit(EXIT_SUCCESS);
6528                 }
6529
6530                 if (!switch_userns(attr.userns_fd, 2000, 2000, true))
6531                         die("failure: switch_userns");
6532
6533                 /* validate file can be directly read */
6534                 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6535                 if (fd < 0)
6536                         die("failure: openat");
6537                 safe_close(fd);
6538
6539                 /* validate file can be read through own symlink */
6540                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6541                 if (fd < 0)
6542                         die("failure: openat");
6543                 safe_close(fd);
6544
6545                 /* validate file can be read through root symlink */
6546                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6547                 if (fd < 0)
6548                         die("failure: openat");
6549                 safe_close(fd);
6550
6551                 /* validate file can't be read through other users symlink */
6552                 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6553                 if (fd >= 0)
6554                         die("failure: openat");
6555                 if (errno != EACCES)
6556                         die("failure: errno");
6557
6558                 exit(EXIT_SUCCESS);
6559         }
6560         if (wait_for_pid(pid)) {
6561                 log_stderr("failure: wait_for_pid");
6562                 goto out;
6563         }
6564
6565         fret = 0;
6566         log_debug("Ran test");
6567 out:
6568         safe_close(dir_fd);
6569         safe_close(open_tree_fd);
6570         safe_close(attr.userns_fd);
6571
6572         return fret;
6573 }
6574
6575 static int acls(void)
6576 {
6577         int fret = -1;
6578         int dir1_fd = -EBADF, open_tree_fd = -EBADF;
6579         struct mount_attr attr = {
6580                 .attr_set = MOUNT_ATTR_IDMAP,
6581         };
6582         pid_t pid;
6583
6584         if (mkdirat(t_dir1_fd, DIR1, 0777)) {
6585                 log_stderr("failure: mkdirat");
6586                 goto out;
6587         }
6588         if (fchmodat(t_dir1_fd, DIR1, 0777, 0)) {
6589                 log_stderr("failure: fchmodat");
6590                 goto out;
6591         }
6592
6593         if (mkdirat(t_dir1_fd, DIR2, 0777)) {
6594                 log_stderr("failure: mkdirat");
6595                 goto out;
6596         }
6597         if (fchmodat(t_dir1_fd, DIR2, 0777, 0)) {
6598                 log_stderr("failure: fchmodat");
6599                 goto out;
6600         }
6601
6602         /* Changing mount properties on a detached mount. */
6603         attr.userns_fd = get_userns_fd(100010, 100020, 5);
6604         if (attr.userns_fd < 0) {
6605                 log_stderr("failure: get_userns_fd");
6606                 goto out;
6607         }
6608
6609         open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
6610                                      AT_NO_AUTOMOUNT |
6611                                      AT_SYMLINK_NOFOLLOW |
6612                                      OPEN_TREE_CLOEXEC |
6613                                      OPEN_TREE_CLONE);
6614         if (open_tree_fd < 0) {
6615                 log_stderr("failure: sys_open_tree");
6616                 goto out;
6617         }
6618
6619         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6620                 log_stderr("failure: sys_mount_setattr");
6621                 goto out;
6622         }
6623
6624         if (sys_move_mount(open_tree_fd, "", t_dir1_fd, DIR2, MOVE_MOUNT_F_EMPTY_PATH)) {
6625                 log_stderr("failure: sys_move_mount");
6626                 goto out;
6627         }
6628
6629         dir1_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6630         if (dir1_fd < 0) {
6631                 log_stderr("failure: openat");
6632                 goto out;
6633         }
6634
6635         if (mkdirat(dir1_fd, DIR3, 0000)) {
6636                 log_stderr("failure: mkdirat");
6637                 goto out;
6638         }
6639         if (fchown(dir1_fd, 100010, 100010)) {
6640                 log_stderr("failure: fchown");
6641                 goto out;
6642         }
6643         if (fchmod(dir1_fd, 0777)) {
6644                 log_stderr("failure: fchmod");
6645                 goto out;
6646         }
6647
6648         snprintf(t_buf, sizeof(t_buf), "setfacl -m u:100010:rwx %s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6649         if (system(t_buf)) {
6650                 log_stderr("failure: system");
6651                 goto out;
6652         }
6653
6654         snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100010:rwx", t_mountpoint, T_DIR1, DIR1, DIR3);
6655         if (system(t_buf)) {
6656                 log_stderr("failure: system");
6657                 goto out;
6658         }
6659
6660         snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100020:rwx", t_mountpoint, T_DIR1, DIR2, DIR3);
6661         if (system(t_buf)) {
6662                 log_stderr("failure: system");
6663                 goto out;
6664         }
6665
6666         pid = fork();
6667         if (pid < 0) {
6668                 log_stderr("failure: fork");
6669                 goto out;
6670         }
6671         if (pid == 0) {
6672                 if (!caps_supported()) {
6673                         log_debug("skip: capability library not installed");
6674                         exit(EXIT_SUCCESS);
6675                 }
6676
6677                 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6678                         die("failure: switch_userns");
6679
6680                 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6681                          t_mountpoint, T_DIR1, DIR1, DIR3, 4294967295LU);
6682                 if (system(t_buf))
6683                         die("failure: system");
6684
6685                 exit(EXIT_SUCCESS);
6686         }
6687         if (wait_for_pid(pid)) {
6688                 log_stderr("failure: wait_for_pid");
6689                 goto out;
6690         }
6691
6692         pid = fork();
6693         if (pid < 0) {
6694                 log_stderr("failure: fork");
6695                 goto out;
6696         }
6697         if (pid == 0) {
6698                 if (!caps_supported()) {
6699                         log_debug("skip: capability library not installed");
6700                         exit(EXIT_SUCCESS);
6701                 }
6702
6703                 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6704                         die("failure: switch_userns");
6705
6706                 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6707                          t_mountpoint, T_DIR1, DIR2, DIR3, 100010LU);
6708                 if (system(t_buf))
6709                         die("failure: system");
6710
6711                 exit(EXIT_SUCCESS);
6712         }
6713         if (wait_for_pid(pid)) {
6714                 log_stderr("failure: wait_for_pid");
6715                 goto out;
6716         }
6717
6718         /* Now, dir is owned by someone else in the user namespace, but we can
6719          * still read it because of acls.
6720          */
6721         if (fchown(dir1_fd, 100012, 100012)) {
6722                 log_stderr("failure: fchown");
6723                 goto out;
6724         }
6725
6726         pid = fork();
6727         if (pid < 0) {
6728                 log_stderr("failure: fork");
6729                 goto out;
6730         }
6731         if (pid == 0) {
6732                 int fd;
6733
6734                 if (!caps_supported()) {
6735                         log_debug("skip: capability library not installed");
6736                         exit(EXIT_SUCCESS);
6737                 }
6738
6739                 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6740                         die("failure: switch_userns");
6741
6742                 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6743                 if (fd < 0)
6744                         die("failure: openat");
6745
6746                 exit(EXIT_SUCCESS);
6747         }
6748         if (wait_for_pid(pid)) {
6749                 log_stderr("failure: wait_for_pid");
6750                 goto out;
6751         }
6752
6753         /* if we delete the acls, the ls should fail because it's 700. */
6754         snprintf(t_buf, sizeof(t_buf), "%s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6755         if (removexattr(t_buf, "system.posix_acl_access")) {
6756                 log_stderr("failure: removexattr");
6757                 goto out;
6758         }
6759
6760         pid = fork();
6761         if (pid < 0) {
6762                 log_stderr("failure: fork");
6763                 goto out;
6764         }
6765         if (pid == 0) {
6766                 int fd;
6767
6768                 if (!caps_supported()) {
6769                         log_debug("skip: capability library not installed");
6770                         exit(EXIT_SUCCESS);
6771                 }
6772
6773                 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6774                         die("failure: switch_userns");
6775
6776                 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6777                 if (fd >= 0)
6778                         die("failure: openat");
6779
6780                 exit(EXIT_SUCCESS);
6781         }
6782         if (wait_for_pid(pid)) {
6783                 log_stderr("failure: wait_for_pid");
6784                 goto out;
6785         }
6786
6787         snprintf(t_buf, sizeof(t_buf), "%s/" T_DIR1 "/" DIR2, t_mountpoint);
6788         sys_umount2(t_buf, MNT_DETACH);
6789
6790         fret = 0;
6791         log_debug("Ran test");
6792 out:
6793         safe_close(attr.userns_fd);
6794         safe_close(dir1_fd);
6795         safe_close(open_tree_fd);
6796
6797         return fret;
6798 }
6799
6800 #ifdef HAVE_LIBURING_H
6801 static int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, int cred_id,
6802                                       bool with_link, int *ret_cqe)
6803 {
6804         struct io_uring_cqe *cqe;
6805         struct io_uring_sqe *sqe;
6806         int ret, i, to_submit = 1;
6807
6808         if (with_link) {
6809                 sqe = io_uring_get_sqe(ring);
6810                 if (!sqe)
6811                         return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6812                 io_uring_prep_nop(sqe);
6813                 sqe->flags |= IOSQE_IO_LINK;
6814                 sqe->user_data = 1;
6815                 to_submit++;
6816         }
6817
6818         sqe = io_uring_get_sqe(ring);
6819         if (!sqe)
6820                 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6821         io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0);
6822         sqe->user_data = 2;
6823
6824         if (cred_id != -1)
6825                 sqe->personality = cred_id;
6826
6827         ret = io_uring_submit(ring);
6828         if (ret != to_submit) {
6829                 log_stderr("failure: io_uring_submit");
6830                 goto out;
6831         }
6832
6833         for (i = 0; i < to_submit; i++) {
6834                 ret = io_uring_wait_cqe(ring, &cqe);
6835                 if (ret < 0) {
6836                         log_stderr("failure: io_uring_wait_cqe");
6837                         goto out;
6838                 }
6839
6840                 ret = cqe->res;
6841                 /*
6842                  * Make sure caller can identify that this is a proper io_uring
6843                  * failure and not some earlier error.
6844                  */
6845                 if (ret_cqe)
6846                         *ret_cqe = ret;
6847                 io_uring_cqe_seen(ring, cqe);
6848         }
6849         log_debug("Ran test");
6850 out:
6851         return ret;
6852 }
6853
6854 static int io_uring(void)
6855 {
6856         int fret = -1;
6857         int file1_fd = -EBADF;
6858         struct io_uring *ring;
6859         int cred_id, ret, ret_cqe;
6860         pid_t pid;
6861
6862         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6863                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6864         if (!ring)
6865                 return log_errno(-1, "failure: io_uring_queue_init");
6866
6867         ret = io_uring_queue_init(8, ring, 0);
6868         if (ret) {
6869                 log_stderr("failure: io_uring_queue_init");
6870                 goto out_unmap;
6871         }
6872
6873         ret = io_uring_register_personality(ring);
6874         if (ret < 0) {
6875                 fret = 0;
6876                 goto out_unmap; /* personalities not supported */
6877         }
6878         cred_id = ret;
6879
6880         /* create file only owner can open */
6881         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
6882         if (file1_fd < 0) {
6883                 log_stderr("failure: openat");
6884                 goto out;
6885         }
6886         if (fchown(file1_fd, 0, 0)) {
6887                 log_stderr("failure: fchown");
6888                 goto out;
6889         }
6890         if (fchmod(file1_fd, 0600)) {
6891                 log_stderr("failure: fchmod");
6892                 goto out;
6893         }
6894         safe_close(file1_fd);
6895
6896         pid = fork();
6897         if (pid < 0) {
6898                 log_stderr("failure: fork");
6899                 goto out;
6900         }
6901         if (pid == 0) {
6902                 /* Verify we can open it with our current credentials. */
6903                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6904                                                       -1, false, NULL);
6905                 if (file1_fd < 0)
6906                         die("failure: io_uring_open_file");
6907
6908                 exit(EXIT_SUCCESS);
6909         }
6910         if (wait_for_pid(pid)) {
6911                 log_stderr("failure: wait_for_pid");
6912                 goto out;
6913         }
6914
6915         pid = fork();
6916         if (pid < 0) {
6917                 log_stderr("failure: fork");
6918                 goto out;
6919         }
6920         if (pid == 0) {
6921                 if (!switch_ids(1000, 1000))
6922                         die("failure: switch_ids");
6923
6924                 /* Verify we can't open it with our current credentials. */
6925                 ret_cqe = 0;
6926                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6927                                                       -1, false, &ret_cqe);
6928                 if (file1_fd >= 0)
6929                         die("failure: io_uring_open_file");
6930                 if (ret_cqe == 0)
6931                         die("failure: non-open() related io_uring_open_file failure %d", ret_cqe);
6932                 if (ret_cqe != -EACCES)
6933                         die("failure: errno(%d)", abs(ret_cqe));
6934
6935                 exit(EXIT_SUCCESS);
6936         }
6937         if (wait_for_pid(pid)) {
6938                 log_stderr("failure: wait_for_pid");
6939                 goto out;
6940         }
6941
6942         pid = fork();
6943         if (pid < 0) {
6944                 log_stderr("failure: fork");
6945                 goto out;
6946         }
6947         if (pid == 0) {
6948                 if (!switch_ids(1000, 1000))
6949                         die("failure: switch_ids");
6950
6951                 /* Verify we can open it with the registered credentials. */
6952                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6953                                                       cred_id, false, NULL);
6954                 if (file1_fd < 0)
6955                         die("failure: io_uring_open_file");
6956
6957                 /* Verify we can open it with the registered credentials and as
6958                  * a link.
6959                  */
6960                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6961                                                       cred_id, true, NULL);
6962                 if (file1_fd < 0)
6963                         die("failure: io_uring_open_file");
6964
6965                 exit(EXIT_SUCCESS);
6966         }
6967         if (wait_for_pid(pid)) {
6968                 log_stderr("failure: wait_for_pid");
6969                 goto out;
6970         }
6971
6972         fret = 0;
6973         log_debug("Ran test");
6974 out:
6975         ret = io_uring_unregister_personality(ring, cred_id);
6976         if (ret)
6977                 log_stderr("failure: io_uring_unregister_personality");
6978
6979 out_unmap:
6980         munmap(ring, sizeof(struct io_uring));
6981
6982         safe_close(file1_fd);
6983
6984         return fret;
6985 }
6986
6987 static int io_uring_userns(void)
6988 {
6989         int fret = -1;
6990         int file1_fd = -EBADF, userns_fd = -EBADF;
6991         struct io_uring *ring;
6992         int cred_id, ret, ret_cqe;
6993         pid_t pid;
6994
6995         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6996                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6997         if (!ring)
6998                 return log_errno(-1, "failure: io_uring_queue_init");
6999
7000         ret = io_uring_queue_init(8, ring, 0);
7001         if (ret) {
7002                 log_stderr("failure: io_uring_queue_init");
7003                 goto out_unmap;
7004         }
7005
7006         ret = io_uring_register_personality(ring);
7007         if (ret < 0) {
7008                 fret = 0;
7009                 goto out_unmap; /* personalities not supported */
7010         }
7011         cred_id = ret;
7012
7013         /* create file only owner can open */
7014         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7015         if (file1_fd < 0) {
7016                 log_stderr("failure: openat");
7017                 goto out;
7018         }
7019         if (fchown(file1_fd, 0, 0)) {
7020                 log_stderr("failure: fchown");
7021                 goto out;
7022         }
7023         if (fchmod(file1_fd, 0600)) {
7024                 log_stderr("failure: fchmod");
7025                 goto out;
7026         }
7027         safe_close(file1_fd);
7028
7029         userns_fd = get_userns_fd(0, 10000, 10000);
7030         if (userns_fd < 0) {
7031                 log_stderr("failure: get_userns_fd");
7032                 goto out;
7033         }
7034
7035         pid = fork();
7036         if (pid < 0) {
7037                 log_stderr("failure: fork");
7038                 goto out;
7039         }
7040         if (pid == 0) {
7041                 /* Verify we can open it with our current credentials. */
7042                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7043                                                       -1, false, NULL);
7044                 if (file1_fd < 0)
7045                         die("failure: io_uring_open_file");
7046
7047                 exit(EXIT_SUCCESS);
7048         }
7049         if (wait_for_pid(pid)) {
7050                 log_stderr("failure: wait_for_pid");
7051                 goto out;
7052         }
7053
7054         pid = fork();
7055         if (pid < 0) {
7056                 log_stderr("failure: fork");
7057                 goto out;
7058         }
7059         if (pid == 0) {
7060                 if (!switch_userns(userns_fd, 0, 0, false))
7061                         die("failure: switch_userns");
7062
7063                 /* Verify we can't open it with our current credentials. */
7064                 ret_cqe = 0;
7065                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7066                                                       -1, false, &ret_cqe);
7067                 if (file1_fd >= 0)
7068                         die("failure: io_uring_open_file");
7069                 if (ret_cqe == 0)
7070                         die("failure: non-open() related io_uring_open_file failure");
7071                 if (ret_cqe != -EACCES)
7072                         die("failure: errno(%d)", abs(ret_cqe));
7073
7074                 exit(EXIT_SUCCESS);
7075         }
7076         if (wait_for_pid(pid)) {
7077                 log_stderr("failure: wait_for_pid");
7078                 goto out;
7079         }
7080
7081         pid = fork();
7082         if (pid < 0) {
7083                 log_stderr("failure: fork");
7084                 goto out;
7085         }
7086         if (pid == 0) {
7087                 if (!switch_userns(userns_fd, 0, 0, false))
7088                         die("failure: switch_userns");
7089
7090                 /* Verify we can open it with the registered credentials. */
7091                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7092                                                       cred_id, false, NULL);
7093                 if (file1_fd < 0)
7094                         die("failure: io_uring_open_file");
7095
7096                 /* Verify we can open it with the registered credentials and as
7097                  * a link.
7098                  */
7099                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7100                                                       cred_id, true, NULL);
7101                 if (file1_fd < 0)
7102                         die("failure: io_uring_open_file");
7103
7104                 exit(EXIT_SUCCESS);
7105         }
7106         if (wait_for_pid(pid)) {
7107                 log_stderr("failure: wait_for_pid");
7108                 goto out;
7109         }
7110
7111         fret = 0;
7112         log_debug("Ran test");
7113 out:
7114         ret = io_uring_unregister_personality(ring, cred_id);
7115         if (ret)
7116                 log_stderr("failure: io_uring_unregister_personality");
7117
7118 out_unmap:
7119         munmap(ring, sizeof(struct io_uring));
7120
7121         safe_close(file1_fd);
7122         safe_close(userns_fd);
7123
7124         return fret;
7125 }
7126
7127 static int io_uring_idmapped(void)
7128 {
7129         int fret = -1;
7130         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7131         struct io_uring *ring;
7132         struct mount_attr attr = {
7133                 .attr_set = MOUNT_ATTR_IDMAP,
7134         };
7135         int cred_id, ret;
7136         pid_t pid;
7137
7138         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7139                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7140         if (!ring)
7141                 return log_errno(-1, "failure: io_uring_queue_init");
7142
7143         ret = io_uring_queue_init(8, ring, 0);
7144         if (ret) {
7145                 log_stderr("failure: io_uring_queue_init");
7146                 goto out_unmap;
7147         }
7148
7149         ret = io_uring_register_personality(ring);
7150         if (ret < 0) {
7151                 fret = 0;
7152                 goto out_unmap; /* personalities not supported */
7153         }
7154         cred_id = ret;
7155
7156         /* create file only owner can open */
7157         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7158         if (file1_fd < 0) {
7159                 log_stderr("failure: openat");
7160                 goto out;
7161         }
7162         if (fchown(file1_fd, 0, 0)) {
7163                 log_stderr("failure: fchown");
7164                 goto out;
7165         }
7166         if (fchmod(file1_fd, 0600)) {
7167                 log_stderr("failure: fchmod");
7168                 goto out;
7169         }
7170         safe_close(file1_fd);
7171
7172         /* Changing mount properties on a detached mount. */
7173         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
7174         if (attr.userns_fd < 0)
7175                 return log_errno(-1, "failure: create user namespace");
7176
7177         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7178                                      AT_EMPTY_PATH |
7179                                      AT_NO_AUTOMOUNT |
7180                                      AT_SYMLINK_NOFOLLOW |
7181                                      OPEN_TREE_CLOEXEC |
7182                                      OPEN_TREE_CLONE);
7183         if (open_tree_fd < 0)
7184                 return log_errno(-1, "failure: create detached mount");
7185
7186         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7187                 return log_errno(-1, "failure: set mount attributes");
7188
7189         pid = fork();
7190         if (pid < 0) {
7191                 log_stderr("failure: fork");
7192                 goto out;
7193         }
7194         if (pid == 0) {
7195                 if (!switch_ids(10000, 10000))
7196                         die("failure: switch_ids");
7197
7198                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7199                                                       -1, false, NULL);
7200                 if (file1_fd < 0)
7201                         die("failure: io_uring_open_file");
7202
7203                 exit(EXIT_SUCCESS);
7204         }
7205         if (wait_for_pid(pid)) {
7206                 log_stderr("failure: wait_for_pid");
7207                 goto out;
7208         }
7209
7210         pid = fork();
7211         if (pid < 0) {
7212                 log_stderr("failure: fork");
7213                 goto out;
7214         }
7215         if (pid == 0) {
7216                 if (!switch_ids(10001, 10001))
7217                         die("failure: switch_ids");
7218
7219                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7220                                                       cred_id, false, NULL);
7221                 if (file1_fd < 0)
7222                         die("failure: io_uring_open_file");
7223
7224                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7225                                                       cred_id, true, NULL);
7226                 if (file1_fd < 0)
7227                         die("failure: io_uring_open_file");
7228
7229                 exit(EXIT_SUCCESS);
7230         }
7231         if (wait_for_pid(pid)) {
7232                 log_stderr("failure: wait_for_pid");
7233                 goto out;
7234         }
7235
7236         fret = 0;
7237         log_debug("Ran test");
7238 out:
7239         ret = io_uring_unregister_personality(ring, cred_id);
7240         if (ret)
7241                 log_stderr("failure: io_uring_unregister_personality");
7242
7243 out_unmap:
7244         munmap(ring, sizeof(struct io_uring));
7245
7246         safe_close(attr.userns_fd);
7247         safe_close(file1_fd);
7248         safe_close(open_tree_fd);
7249
7250         return fret;
7251 }
7252
7253 /*
7254  * Create an idmapped mount where the we leave the owner of the file unmapped.
7255  * In no circumstances, even with recorded credentials can it be allowed to
7256  * open the file.
7257  */
7258 static int io_uring_idmapped_unmapped(void)
7259 {
7260         int fret = -1;
7261         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7262         struct io_uring *ring;
7263         struct mount_attr attr = {
7264                 .attr_set = MOUNT_ATTR_IDMAP,
7265         };
7266         int cred_id, ret, ret_cqe;
7267         pid_t pid;
7268
7269         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7270                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7271         if (!ring)
7272                 return log_errno(-1, "failure: io_uring_queue_init");
7273
7274         ret = io_uring_queue_init(8, ring, 0);
7275         if (ret) {
7276                 log_stderr("failure: io_uring_queue_init");
7277                 goto out_unmap;
7278         }
7279
7280         ret = io_uring_register_personality(ring);
7281         if (ret < 0) {
7282                 fret = 0;
7283                 goto out_unmap; /* personalities not supported */
7284         }
7285         cred_id = ret;
7286
7287         /* create file only owner can open */
7288         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7289         if (file1_fd < 0) {
7290                 log_stderr("failure: openat");
7291                 goto out;
7292         }
7293         if (fchown(file1_fd, 0, 0)) {
7294                 log_stderr("failure: fchown");
7295                 goto out;
7296         }
7297         if (fchmod(file1_fd, 0600)) {
7298                 log_stderr("failure: fchmod");
7299                 goto out;
7300         }
7301         safe_close(file1_fd);
7302
7303         /* Changing mount properties on a detached mount. */
7304         attr.userns_fd  = get_userns_fd(1, 10000, 10000);
7305         if (attr.userns_fd < 0)
7306                 return log_errno(-1, "failure: create user namespace");
7307
7308         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7309                                      AT_EMPTY_PATH |
7310                                      AT_NO_AUTOMOUNT |
7311                                      AT_SYMLINK_NOFOLLOW |
7312                                      OPEN_TREE_CLOEXEC |
7313                                      OPEN_TREE_CLONE);
7314         if (open_tree_fd < 0)
7315                 return log_errno(-1, "failure: create detached mount");
7316
7317         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7318                 return log_errno(-1, "failure: set mount attributes");
7319
7320         pid = fork();
7321         if (pid < 0) {
7322                 log_stderr("failure: fork");
7323                 goto out;
7324         }
7325         if (pid == 0) {
7326                 if (!switch_ids(10000, 10000))
7327                         die("failure: switch_ids");
7328
7329                 ret_cqe = 0;
7330                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7331                                                       cred_id, false, &ret_cqe);
7332                 if (file1_fd >= 0)
7333                         die("failure: io_uring_open_file");
7334                 if (ret_cqe == 0)
7335                         die("failure: non-open() related io_uring_open_file failure");
7336                 if (ret_cqe != -EACCES)
7337                         die("failure: errno(%d)", abs(ret_cqe));
7338
7339                 ret_cqe = 0;
7340                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7341                                                       cred_id, true, &ret_cqe);
7342                 if (file1_fd >= 0)
7343                         die("failure: io_uring_open_file");
7344                 if (ret_cqe == 0)
7345                         die("failure: non-open() related io_uring_open_file failure");
7346                 if (ret_cqe != -EACCES)
7347                         die("failure: errno(%d)", abs(ret_cqe));
7348
7349                 exit(EXIT_SUCCESS);
7350         }
7351         if (wait_for_pid(pid)) {
7352                 log_stderr("failure: wait_for_pid");
7353                 goto out;
7354         }
7355
7356         fret = 0;
7357         log_debug("Ran test");
7358 out:
7359         ret = io_uring_unregister_personality(ring, cred_id);
7360         if (ret)
7361                 log_stderr("failure: io_uring_unregister_personality");
7362
7363 out_unmap:
7364         munmap(ring, sizeof(struct io_uring));
7365
7366         safe_close(attr.userns_fd);
7367         safe_close(file1_fd);
7368         safe_close(open_tree_fd);
7369
7370         return fret;
7371 }
7372
7373 static int io_uring_idmapped_userns(void)
7374 {
7375         int fret = -1;
7376         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7377         struct io_uring *ring;
7378         struct mount_attr attr = {
7379                 .attr_set = MOUNT_ATTR_IDMAP,
7380         };
7381         int cred_id, ret, ret_cqe;
7382         pid_t pid;
7383
7384         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7385                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7386         if (!ring)
7387                 return log_errno(-1, "failure: io_uring_queue_init");
7388
7389         ret = io_uring_queue_init(8, ring, 0);
7390         if (ret) {
7391                 log_stderr("failure: io_uring_queue_init");
7392                 goto out_unmap;
7393         }
7394
7395         ret = io_uring_register_personality(ring);
7396         if (ret < 0) {
7397                 fret = 0;
7398                 goto out_unmap; /* personalities not supported */
7399         }
7400         cred_id = ret;
7401
7402         /* create file only owner can open */
7403         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7404         if (file1_fd < 0) {
7405                 log_stderr("failure: openat");
7406                 goto out;
7407         }
7408         if (fchown(file1_fd, 0, 0)) {
7409                 log_stderr("failure: fchown");
7410                 goto out;
7411         }
7412         if (fchmod(file1_fd, 0600)) {
7413                 log_stderr("failure: fchmod");
7414                 goto out;
7415         }
7416         safe_close(file1_fd);
7417
7418         /* Changing mount properties on a detached mount. */
7419         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
7420         if (attr.userns_fd < 0)
7421                 return log_errno(-1, "failure: create user namespace");
7422
7423         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7424                                      AT_EMPTY_PATH |
7425                                      AT_NO_AUTOMOUNT |
7426                                      AT_SYMLINK_NOFOLLOW |
7427                                      OPEN_TREE_CLOEXEC |
7428                                      OPEN_TREE_CLONE);
7429         if (open_tree_fd < 0)
7430                 return log_errno(-1, "failure: create detached mount");
7431
7432         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7433                 return log_errno(-1, "failure: set mount attributes");
7434
7435         pid = fork();
7436         if (pid < 0) {
7437                 log_stderr("failure: fork");
7438                 goto out;
7439         }
7440         if (pid == 0) {
7441                 if (!switch_userns(attr.userns_fd, 0, 0, false))
7442                         die("failure: switch_userns");
7443
7444                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7445                                                       -1, false, NULL);
7446                 if (file1_fd < 0)
7447                         die("failure: io_uring_open_file");
7448
7449                 exit(EXIT_SUCCESS);
7450         }
7451         if (wait_for_pid(pid)) {
7452                 log_stderr("failure: wait_for_pid");
7453                 goto out;
7454         }
7455
7456         pid = fork();
7457         if (pid < 0) {
7458                 log_stderr("failure: fork");
7459                 goto out;
7460         }
7461         if (pid == 0) {
7462                 if (!caps_supported()) {
7463                         log_debug("skip: capability library not installed");
7464                         exit(EXIT_SUCCESS);
7465                 }
7466
7467                 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
7468                         die("failure: switch_userns");
7469
7470                 ret_cqe = 0;
7471                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7472                                                       -1, false, &ret_cqe);
7473                 if (file1_fd >= 0)
7474                         die("failure: io_uring_open_file");
7475                 if (ret_cqe == 0)
7476                         die("failure: non-open() related io_uring_open_file failure");
7477                 if (ret_cqe != -EACCES)
7478                         die("failure: errno(%d)", abs(ret_cqe));
7479
7480                 ret_cqe = 0;
7481                 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7482                                                       -1, true, &ret_cqe);
7483                 if (file1_fd >= 0)
7484                         die("failure: io_uring_open_file");
7485                 if (ret_cqe == 0)
7486                         die("failure: non-open() related io_uring_open_file failure");
7487                 if (ret_cqe != -EACCES)
7488                         die("failure: errno(%d)", abs(ret_cqe));
7489
7490                 ret_cqe = 0;
7491                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7492                                                       -1, false, &ret_cqe);
7493                 if (file1_fd >= 0)
7494                         die("failure: io_uring_open_file");
7495                 if (ret_cqe == 0)
7496                         die("failure: non-open() related io_uring_open_file failure");
7497                 if (ret_cqe != -EACCES)
7498                         die("failure: errno(%d)", abs(ret_cqe));
7499
7500                 ret_cqe = 0;
7501                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7502                                                       -1, true, &ret_cqe);
7503                 if (file1_fd >= 0)
7504                         die("failure: io_uring_open_file");
7505                 if (ret_cqe == 0)
7506                         die("failure: non-open() related io_uring_open_file failure");
7507                 if (ret_cqe != -EACCES)
7508                         die("failure: errno(%d)", abs(ret_cqe));
7509
7510                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7511                                                       cred_id, false, NULL);
7512                 if (file1_fd < 0)
7513                         die("failure: io_uring_open_file");
7514
7515                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7516                                                       cred_id, true, NULL);
7517                 if (file1_fd < 0)
7518                         die("failure: io_uring_open_file");
7519
7520                 exit(EXIT_SUCCESS);
7521         }
7522         if (wait_for_pid(pid)) {
7523                 log_stderr("failure: wait_for_pid");
7524                 goto out;
7525         }
7526
7527         fret = 0;
7528         log_debug("Ran test");
7529 out:
7530         ret = io_uring_unregister_personality(ring, cred_id);
7531         if (ret)
7532                 log_stderr("failure: io_uring_unregister_personality");
7533
7534 out_unmap:
7535         munmap(ring, sizeof(struct io_uring));
7536
7537         safe_close(attr.userns_fd);
7538         safe_close(file1_fd);
7539         safe_close(open_tree_fd);
7540
7541         return fret;
7542 }
7543
7544 static int io_uring_idmapped_unmapped_userns(void)
7545 {
7546         int fret = -1;
7547         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7548         struct io_uring *ring;
7549         struct mount_attr attr = {
7550                 .attr_set = MOUNT_ATTR_IDMAP,
7551         };
7552         int cred_id, ret, ret_cqe;
7553         pid_t pid;
7554
7555         ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7556                    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7557         if (!ring)
7558                 return log_errno(-1, "failure: io_uring_queue_init");
7559
7560         ret = io_uring_queue_init(8, ring, 0);
7561         if (ret) {
7562                 log_stderr("failure: io_uring_queue_init");
7563                 goto out_unmap;
7564         }
7565
7566         ret = io_uring_register_personality(ring);
7567         if (ret < 0) {
7568                 fret = 0;
7569                 goto out_unmap; /* personalities not supported */
7570         }
7571         cred_id = ret;
7572
7573         /* create file only owner can open */
7574         file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7575         if (file1_fd < 0) {
7576                 log_stderr("failure: openat");
7577                 goto out;
7578         }
7579         if (fchown(file1_fd, 0, 0)) {
7580                 log_stderr("failure: fchown");
7581                 goto out;
7582         }
7583         if (fchmod(file1_fd, 0600)) {
7584                 log_stderr("failure: fchmod");
7585                 goto out;
7586         }
7587         safe_close(file1_fd);
7588
7589         /* Changing mount properties on a detached mount. */
7590         attr.userns_fd  = get_userns_fd(1, 10000, 10000);
7591         if (attr.userns_fd < 0)
7592                 return log_errno(-1, "failure: create user namespace");
7593
7594         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7595                                      AT_EMPTY_PATH |
7596                                      AT_NO_AUTOMOUNT |
7597                                      AT_SYMLINK_NOFOLLOW |
7598                                      OPEN_TREE_CLOEXEC |
7599                                      OPEN_TREE_CLONE);
7600         if (open_tree_fd < 0)
7601                 return log_errno(-1, "failure: create detached mount");
7602
7603         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7604                 return log_errno(-1, "failure: set mount attributes");
7605
7606         pid = fork();
7607         if (pid < 0) {
7608                 log_stderr("failure: fork");
7609                 goto out;
7610         }
7611         if (pid == 0) {
7612                 if (!caps_supported()) {
7613                         log_debug("skip: capability library not installed");
7614                         exit(EXIT_SUCCESS);
7615                 }
7616
7617                 if (!switch_userns(attr.userns_fd, 10000, 10000, true))
7618                         die("failure: switch_ids");
7619
7620                 ret_cqe = 0;
7621                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7622                                                       cred_id, false, &ret_cqe);
7623                 if (file1_fd >= 0)
7624                         die("failure: io_uring_open_file");
7625                 if (ret_cqe == 0)
7626                         die("failure: non-open() related io_uring_open_file failure");
7627                 if (ret_cqe != -EACCES)
7628                         die("failure: errno(%d)", abs(ret_cqe));
7629
7630                 ret_cqe = 0;
7631                 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7632                                                       cred_id, true, &ret_cqe);
7633                 if (file1_fd >= 0)
7634                         die("failure: io_uring_open_file");
7635                 if (ret_cqe == 0)
7636                         die("failure: non-open() related io_uring_open_file failure");
7637                 if (ret_cqe != -EACCES)
7638                         die("failure: errno(%d)", abs(ret_cqe));
7639
7640                 exit(EXIT_SUCCESS);
7641         }
7642         if (wait_for_pid(pid)) {
7643                 log_stderr("failure: wait_for_pid");
7644                 goto out;
7645         }
7646
7647         fret = 0;
7648         log_debug("Ran test");
7649 out:
7650         ret = io_uring_unregister_personality(ring, cred_id);
7651         if (ret)
7652                 log_stderr("failure: io_uring_unregister_personality");
7653
7654 out_unmap:
7655         munmap(ring, sizeof(struct io_uring));
7656
7657         safe_close(attr.userns_fd);
7658         safe_close(file1_fd);
7659         safe_close(open_tree_fd);
7660
7661         return fret;
7662 }
7663 #endif /* HAVE_LIBURING_H */
7664
7665 /* The following tests are concerned with setgid inheritance. These can be
7666  * filesystem type specific. For xfs, if a new file or directory is created
7667  * within a setgid directory and irix_sgid_inhiert is set then inherit the
7668  * setgid bit if the caller is in the group of the directory.
7669  */
7670 static int setgid_create(void)
7671 {
7672         int fret = -1;
7673         int file1_fd = -EBADF;
7674         pid_t pid;
7675
7676         if (!caps_supported())
7677                 return 0;
7678
7679         if (fchmod(t_dir1_fd, S_IRUSR |
7680                               S_IWUSR |
7681                               S_IRGRP |
7682                               S_IWGRP |
7683                               S_IROTH |
7684                               S_IWOTH |
7685                               S_IXUSR |
7686                               S_IXGRP |
7687                               S_IXOTH |
7688                               S_ISGID), 0) {
7689                 log_stderr("failure: fchmod");
7690                 goto out;
7691         }
7692
7693         /* Verify that the setgid bit got raised. */
7694         if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7695                 log_stderr("failure: is_setgid");
7696                 goto out;
7697         }
7698
7699         pid = fork();
7700         if (pid < 0) {
7701                 log_stderr("failure: fork");
7702                 goto out;
7703         }
7704         if (pid == 0) {
7705                 /* create regular file via open() */
7706                 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7707                 if (file1_fd < 0)
7708                         die("failure: create");
7709
7710                 /* We're capable_wrt_inode_uidgid() and also our fsgid matches
7711                  * the directories gid.
7712                  */
7713                 if (!is_setgid(t_dir1_fd, FILE1, 0))
7714                         die("failure: is_setgid");
7715
7716                 /* create directory */
7717                 if (mkdirat(t_dir1_fd, DIR1, 0000))
7718                         die("failure: create");
7719
7720                 /* Directories always inherit the setgid bit. */
7721                 if (!is_setgid(t_dir1_fd, DIR1, 0))
7722                         die("failure: is_setgid");
7723
7724                 if (unlinkat(t_dir1_fd, FILE1, 0))
7725                         die("failure: delete");
7726
7727                 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7728                         die("failure: delete");
7729
7730                 exit(EXIT_SUCCESS);
7731         }
7732         if (wait_for_pid(pid))
7733                 goto out;
7734
7735         pid = fork();
7736         if (pid < 0) {
7737                 log_stderr("failure: fork");
7738                 goto out;
7739         }
7740         if (pid == 0) {
7741                 if (!switch_ids(0, 10000))
7742                         die("failure: switch_ids");
7743
7744                 if (!caps_down())
7745                         die("failure: caps_down");
7746
7747                 /* create regular file via open() */
7748                 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7749                 if (file1_fd < 0)
7750                         die("failure: create");
7751
7752                 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7753                  * bit needs to be stripped.
7754                  */
7755                 if (is_setgid(t_dir1_fd, FILE1, 0))
7756                         die("failure: is_setgid");
7757
7758                 /* create directory */
7759                 if (mkdirat(t_dir1_fd, DIR1, 0000))
7760                         die("failure: create");
7761
7762                 if (xfs_irix_sgid_inherit_enabled()) {
7763                         /* We're not in_group_p(). */
7764                         if (is_setgid(t_dir1_fd, DIR1, 0))
7765                                 die("failure: is_setgid");
7766                 } else {
7767                         /* Directories always inherit the setgid bit. */
7768                         if (!is_setgid(t_dir1_fd, DIR1, 0))
7769                                 die("failure: is_setgid");
7770                 }
7771
7772                 exit(EXIT_SUCCESS);
7773         }
7774         if (wait_for_pid(pid))
7775                 goto out;
7776
7777         fret = 0;
7778         log_debug("Ran test");
7779 out:
7780         safe_close(file1_fd);
7781
7782         return fret;
7783 }
7784
7785 static int setgid_create_idmapped(void)
7786 {
7787         int fret = -1;
7788         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7789         struct mount_attr attr = {
7790                 .attr_set = MOUNT_ATTR_IDMAP,
7791         };
7792         pid_t pid;
7793
7794         if (!caps_supported())
7795                 return 0;
7796
7797         if (fchmod(t_dir1_fd, S_IRUSR |
7798                               S_IWUSR |
7799                               S_IRGRP |
7800                               S_IWGRP |
7801                               S_IROTH |
7802                               S_IWOTH |
7803                               S_IXUSR |
7804                               S_IXGRP |
7805                               S_IXOTH |
7806                               S_ISGID), 0) {
7807                 log_stderr("failure: fchmod");
7808                 goto out;
7809         }
7810
7811         /* Verify that the sid bits got raised. */
7812         if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7813                 log_stderr("failure: is_setgid");
7814                 goto out;
7815         }
7816
7817         /* Changing mount properties on a detached mount. */
7818         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
7819         if (attr.userns_fd < 0) {
7820                 log_stderr("failure: get_userns_fd");
7821                 goto out;
7822         }
7823
7824         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7825                                      AT_EMPTY_PATH |
7826                                      AT_NO_AUTOMOUNT |
7827                                      AT_SYMLINK_NOFOLLOW |
7828                                      OPEN_TREE_CLOEXEC |
7829                                      OPEN_TREE_CLONE);
7830         if (open_tree_fd < 0) {
7831                 log_stderr("failure: sys_open_tree");
7832                 goto out;
7833         }
7834
7835         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7836                 log_stderr("failure: sys_mount_setattr");
7837                 goto out;
7838         }
7839
7840         pid = fork();
7841         if (pid < 0) {
7842                 log_stderr("failure: fork");
7843                 goto out;
7844         }
7845         if (pid == 0) {
7846                 if (!switch_ids(10000, 11000))
7847                         die("failure: switch fsids");
7848
7849                 /* create regular file via open() */
7850                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7851                 if (file1_fd < 0)
7852                         die("failure: create");
7853
7854                 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7855                  * bit needs to be stripped.
7856                  */
7857                 if (is_setgid(open_tree_fd, FILE1, 0))
7858                         die("failure: is_setgid");
7859
7860                 /* create directory */
7861                 if (mkdirat(open_tree_fd, DIR1, 0000))
7862                         die("failure: create");
7863
7864                 if (xfs_irix_sgid_inherit_enabled()) {
7865                         /* We're not in_group_p(). */
7866                         if (is_setgid(open_tree_fd, DIR1, 0))
7867                                 die("failure: is_setgid");
7868                 } else {
7869                         /* Directories always inherit the setgid bit. */
7870                         if (!is_setgid(open_tree_fd, DIR1, 0))
7871                                 die("failure: is_setgid");
7872                 }
7873
7874                 exit(EXIT_SUCCESS);
7875         }
7876         if (wait_for_pid(pid))
7877                 goto out;
7878
7879         fret = 0;
7880         log_debug("Ran test");
7881 out:
7882         safe_close(attr.userns_fd);
7883         safe_close(file1_fd);
7884         safe_close(open_tree_fd);
7885
7886         return fret;
7887 }
7888
7889 static int setgid_create_idmapped_in_userns(void)
7890 {
7891         int fret = -1;
7892         int file1_fd = -EBADF, open_tree_fd = -EBADF;
7893         struct mount_attr attr = {
7894                 .attr_set = MOUNT_ATTR_IDMAP,
7895         };
7896         pid_t pid;
7897
7898         if (!caps_supported())
7899                 return 0;
7900
7901         if (fchmod(t_dir1_fd, S_IRUSR |
7902                               S_IWUSR |
7903                               S_IRGRP |
7904                               S_IWGRP |
7905                               S_IROTH |
7906                               S_IWOTH |
7907                               S_IXUSR |
7908                               S_IXGRP |
7909                               S_IXOTH |
7910                               S_ISGID), 0) {
7911                 log_stderr("failure: fchmod");
7912                 goto out;
7913         }
7914
7915         /* Verify that the sid bits got raised. */
7916         if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7917                 log_stderr("failure: is_setgid");
7918                 goto out;
7919         }
7920
7921         /* Changing mount properties on a detached mount. */
7922         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
7923         if (attr.userns_fd < 0) {
7924                 log_stderr("failure: get_userns_fd");
7925                 goto out;
7926         }
7927
7928         open_tree_fd = sys_open_tree(t_dir1_fd, "",
7929                                      AT_EMPTY_PATH |
7930                                      AT_NO_AUTOMOUNT |
7931                                      AT_SYMLINK_NOFOLLOW |
7932                                      OPEN_TREE_CLOEXEC |
7933                                      OPEN_TREE_CLONE);
7934         if (open_tree_fd < 0) {
7935                 log_stderr("failure: sys_open_tree");
7936                 goto out;
7937         }
7938
7939         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7940                 log_stderr("failure: sys_mount_setattr");
7941                 goto out;
7942         }
7943
7944         pid = fork();
7945         if (pid < 0) {
7946                 log_stderr("failure: fork");
7947                 goto out;
7948         }
7949         if (pid == 0) {
7950                 if (!switch_userns(attr.userns_fd, 0, 0, false))
7951                         die("failure: switch_userns");
7952
7953                 /* create regular file via open() */
7954                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7955                 if (file1_fd < 0)
7956                         die("failure: create");
7957
7958                 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
7959                  * bit needs to be set.
7960                  */
7961                 if (!is_setgid(open_tree_fd, FILE1, 0))
7962                         die("failure: is_setgid");
7963
7964                 /* create directory */
7965                 if (mkdirat(open_tree_fd, DIR1, 0000))
7966                         die("failure: create");
7967
7968                 /* Directories always inherit the setgid bit. */
7969                 if (!is_setgid(open_tree_fd, DIR1, 0))
7970                         die("failure: is_setgid");
7971
7972                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
7973                         die("failure: check ownership");
7974
7975                 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
7976                         die("failure: check ownership");
7977
7978                 if (unlinkat(open_tree_fd, FILE1, 0))
7979                         die("failure: delete");
7980
7981                 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
7982                         die("failure: delete");
7983
7984                 exit(EXIT_SUCCESS);
7985         }
7986         if (wait_for_pid(pid))
7987                 goto out;
7988
7989         if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7990                 log_stderr("failure: fchownat");
7991                 goto out;
7992         }
7993
7994         if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7995                 log_stderr("failure: fchownat");
7996                 goto out;
7997         }
7998
7999         pid = fork();
8000         if (pid < 0) {
8001                 log_stderr("failure: fork");
8002                 goto out;
8003         }
8004         if (pid == 0) {
8005                 if (!caps_supported()) {
8006                         log_debug("skip: capability library not installed");
8007                         exit(EXIT_SUCCESS);
8008                 }
8009
8010                 if (!switch_userns(attr.userns_fd, 0, 0, true))
8011                         die("failure: switch_userns");
8012
8013                 /* create regular file via open() */
8014                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8015                 if (file1_fd < 0)
8016                         die("failure: create");
8017
8018                 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8019                  * bit needs to be stripped.
8020                  */
8021                 if (is_setgid(open_tree_fd, FILE1, 0))
8022                         die("failure: is_setgid");
8023
8024                 /* create directory */
8025                 if (mkdirat(open_tree_fd, DIR1, 0000))
8026                         die("failure: create");
8027
8028                 if (xfs_irix_sgid_inherit_enabled()) {
8029                         /* We're not in_group_p(). */
8030                         if (is_setgid(open_tree_fd, DIR1, 0))
8031                                 die("failure: is_setgid");
8032                 } else {
8033                         /* Directories always inherit the setgid bit. */
8034                         if (!is_setgid(open_tree_fd, DIR1, 0))
8035                                 die("failure: is_setgid");
8036                 }
8037
8038                 /* Files and directories created in setgid directories inherit
8039                  * the i_gid of the parent directory.
8040                  */
8041                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8042                         die("failure: check ownership");
8043
8044                 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8045                         die("failure: check ownership");
8046
8047                 if (unlinkat(open_tree_fd, FILE1, 0))
8048                         die("failure: delete");
8049
8050                 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8051                         die("failure: delete");
8052
8053                 exit(EXIT_SUCCESS);
8054         }
8055         if (wait_for_pid(pid))
8056                 goto out;
8057
8058         if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8059                 log_stderr("failure: fchownat");
8060                 goto out;
8061         }
8062
8063         if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8064                 log_stderr("failure: fchownat");
8065                 goto out;
8066         }
8067
8068         pid = fork();
8069         if (pid < 0) {
8070                 log_stderr("failure: fork");
8071                 goto out;
8072         }
8073         if (pid == 0) {
8074                 if (!caps_supported()) {
8075                         log_debug("skip: capability library not installed");
8076                         exit(EXIT_SUCCESS);
8077                 }
8078
8079                 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8080                         die("failure: switch_userns");
8081
8082                 /* create regular file via open() */
8083                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8084                 if (file1_fd < 0)
8085                         die("failure: create");
8086
8087                 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8088                  * bit needs to be stripped.
8089                  */
8090                 if (is_setgid(open_tree_fd, FILE1, 0))
8091                         die("failure: is_setgid");
8092
8093                 /* create directory */
8094                 if (mkdirat(open_tree_fd, DIR1, 0000))
8095                         die("failure: create");
8096
8097                 /* Directories always inherit the setgid bit. */
8098                 if (xfs_irix_sgid_inherit_enabled()) {
8099                         /* We're not in_group_p(). */
8100                         if (is_setgid(open_tree_fd, DIR1, 0))
8101                                 die("failure: is_setgid");
8102                 } else {
8103                         /* Directories always inherit the setgid bit. */
8104                         if (!is_setgid(open_tree_fd, DIR1, 0))
8105                                 die("failure: is_setgid");
8106                 }
8107
8108                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8109                         die("failure: check ownership");
8110
8111                 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8112                         die("failure: check ownership");
8113
8114                 exit(EXIT_SUCCESS);
8115         }
8116         if (wait_for_pid(pid))
8117                 goto out;
8118
8119         fret = 0;
8120         log_debug("Ran test");
8121 out:
8122         safe_close(attr.userns_fd);
8123         safe_close(file1_fd);
8124         safe_close(open_tree_fd);
8125
8126         return fret;
8127 }
8128
8129 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8130 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8131
8132 static void *idmapped_mount_create_cb(void *data)
8133 {
8134         int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8135         struct mount_attr attr = {
8136                 .attr_set = MOUNT_ATTR_IDMAP,
8137         };
8138
8139         /* Changing mount properties on a detached mount. */
8140         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
8141         if (attr.userns_fd < 0) {
8142                 log_stderr("failure: get_userns_fd");
8143                 goto out;
8144         }
8145
8146         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8147                 log_stderr("failure: sys_mount_setattr");
8148                 goto out;
8149         }
8150
8151         fret = EXIT_SUCCESS;
8152
8153 out:
8154         safe_close(attr.userns_fd);
8155         pthread_exit(INT_TO_PTR(fret));
8156 }
8157
8158 /* This tries to verify that we never see an inconistent ownership on-disk and
8159  * can't write invalid ids to disk. To do this we create a race between
8160  * idmapping a mount and creating files on it.
8161  * Note, while it is perfectly fine to see overflowuid and overflowgid as owner
8162  * if we create files through the open_tree_fd before the mount is idmapped but
8163  * look at the files after the mount has been idmapped in this test it can never
8164  * be the case that we see overflowuid and overflowgid when we access the file
8165  * through a non-idmapped mount (in the initial user namespace).
8166  */
8167 static void *idmapped_mount_operations_cb(void *data)
8168 {
8169         int file1_fd = -EBADF, file2_fd = -EBADF, dir1_fd = -EBADF,
8170             dir1_fd2 = -EBADF, fret = EXIT_FAILURE,
8171             open_tree_fd = PTR_TO_INT(data);
8172
8173         if (!switch_fsids(10000, 10000)) {
8174                 log_stderr("failure: switch fsids");
8175                 goto out;
8176         }
8177
8178         file1_fd = openat(open_tree_fd, FILE1,
8179                           O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8180         if (file1_fd < 0) {
8181                 log_stderr("failure: openat");
8182                 goto out;
8183         }
8184
8185         file2_fd = openat(open_tree_fd, FILE2,
8186                           O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8187         if (file2_fd < 0) {
8188                 log_stderr("failure: openat");
8189                 goto out;
8190         }
8191
8192         if (mkdirat(open_tree_fd, DIR1, 0777)) {
8193                 log_stderr("failure: mkdirat");
8194                 goto out;
8195         }
8196
8197         dir1_fd = openat(open_tree_fd, DIR1,
8198                          O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8199         if (dir1_fd < 0) {
8200                 log_stderr("failure: openat");
8201                 goto out;
8202         }
8203
8204         if (!__expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0, false) &&
8205             !__expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000, false) &&
8206             !__expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid, false)) {
8207                 log_stderr("failure: expected_uid_gid");
8208                 goto out;
8209         }
8210
8211         if (!__expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0, false) &&
8212             !__expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000, false) &&
8213             !__expected_uid_gid(open_tree_fd, FILE2, 0, t_overflowuid, t_overflowgid, false)) {
8214                 log_stderr("failure: expected_uid_gid");
8215                 goto out;
8216         }
8217
8218         if (!__expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0, false) &&
8219             !__expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000, false) &&
8220             !__expected_uid_gid(open_tree_fd, DIR1, 0, t_overflowuid, t_overflowgid, false)) {
8221                 log_stderr("failure: expected_uid_gid");
8222                 goto out;
8223         }
8224
8225         if (!__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 0, 0, false) &&
8226             !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 10000, 10000, false) &&
8227             !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, t_overflowuid, t_overflowgid, false)) {
8228                 log_stderr("failure: expected_uid_gid");
8229                 goto out;
8230         }
8231
8232         dir1_fd2 = openat(t_dir1_fd, DIR1,
8233                          O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8234         if (dir1_fd2 < 0) {
8235                 log_stderr("failure: openat");
8236                 goto out;
8237         }
8238
8239         if (!__expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0, false) &&
8240             !__expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000, false)) {
8241                 log_stderr("failure: expected_uid_gid");
8242                 goto out;
8243         }
8244
8245         if (!__expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0, false) &&
8246             !__expected_uid_gid(t_dir1_fd, FILE2, 0, 10000, 10000, false)) {
8247                 log_stderr("failure: expected_uid_gid");
8248                 goto out;
8249         }
8250
8251         if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8252             !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8253                 log_stderr("failure: expected_uid_gid");
8254                 goto out;
8255         }
8256
8257         if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8258             !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8259                 log_stderr("failure: expected_uid_gid");
8260                 goto out;
8261         }
8262
8263         if (!__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 0, 0, false) &&
8264             !__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 10000, 10000, false)) {
8265                 log_stderr("failure: expected_uid_gid");
8266                 goto out;
8267         }
8268
8269         fret = EXIT_SUCCESS;
8270
8271 out:
8272         safe_close(file1_fd);
8273         safe_close(file2_fd);
8274         safe_close(dir1_fd);
8275         safe_close(dir1_fd2);
8276
8277         pthread_exit(INT_TO_PTR(fret));
8278 }
8279
8280 static int threaded_idmapped_mount_interactions(void)
8281 {
8282         int i;
8283         int fret = -1;
8284         pid_t pid;
8285         pthread_attr_t thread_attr;
8286         pthread_t threads[2];
8287
8288         pthread_attr_init(&thread_attr);
8289
8290         for (i = 0; i < 1000; i++) {
8291                 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8292
8293                 pid = fork();
8294                 if (pid < 0) {
8295                         log_stderr("failure: fork");
8296                         goto out;
8297                 }
8298                 if (pid == 0) {
8299                         int open_tree_fd = -EBADF;
8300
8301                         open_tree_fd = sys_open_tree(t_dir1_fd, "",
8302                                                      AT_EMPTY_PATH |
8303                                                      AT_NO_AUTOMOUNT |
8304                                                      AT_SYMLINK_NOFOLLOW |
8305                                                      OPEN_TREE_CLOEXEC |
8306                                                      OPEN_TREE_CLONE);
8307                         if (open_tree_fd < 0)
8308                                 die("failure: sys_open_tree");
8309
8310                         if (pthread_create(&threads[0], &thread_attr,
8311                                            idmapped_mount_create_cb,
8312                                            INT_TO_PTR(open_tree_fd)))
8313                                 die("failure: pthread_create");
8314
8315                         if (pthread_create(&threads[1], &thread_attr,
8316                                            idmapped_mount_operations_cb,
8317                                            INT_TO_PTR(open_tree_fd)))
8318                                 die("failure: pthread_create");
8319
8320                         ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8321                         ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8322
8323                         if (ret1) {
8324                                 errno = ret1;
8325                                 die("failure: pthread_join");
8326                         }
8327
8328                         if (ret2) {
8329                                 errno = ret2;
8330                                 die("failure: pthread_join");
8331                         }
8332
8333                         if (tret1 || tret2)
8334                                 exit(EXIT_FAILURE);
8335
8336                         exit(EXIT_SUCCESS);
8337
8338                 }
8339
8340                 if (wait_for_pid(pid)) {
8341                         log_stderr("failure: iteration %d", i);
8342                         goto out;
8343                 }
8344
8345                 rm_r(t_dir1_fd, ".");
8346
8347         }
8348
8349         fret = 0;
8350         log_debug("Ran test");
8351
8352 out:
8353         return fret;
8354 }
8355
8356 static int setattr_truncate(void)
8357 {
8358         int fret = -1;
8359         int file1_fd = -EBADF;
8360
8361         /* create regular file via open() */
8362         file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8363         if (file1_fd < 0) {
8364                 log_stderr("failure: create");
8365                 goto out;
8366         }
8367
8368         if (ftruncate(file1_fd, 10000)) {
8369                 log_stderr("failure: ftruncate");
8370                 goto out;
8371         }
8372
8373         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8374                 log_stderr("failure: check ownership");
8375                 goto out;
8376         }
8377
8378         if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8379                 log_stderr("failure: expected_file_size");
8380                 goto out;
8381         }
8382
8383         if (ftruncate(file1_fd, 0)) {
8384                 log_stderr("failure: ftruncate");
8385                 goto out;
8386         }
8387
8388         if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8389                 log_stderr("failure: check ownership");
8390                 goto out;
8391         }
8392
8393         if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8394                 log_stderr("failure: expected_file_size");
8395                 goto out;
8396         }
8397
8398         if (unlinkat(t_dir1_fd, FILE1, 0)) {
8399                 log_stderr("failure: remove");
8400                 goto out;
8401         }
8402
8403         fret = 0;
8404         log_debug("Ran test");
8405 out:
8406         safe_close(file1_fd);
8407
8408         return fret;
8409 }
8410
8411 static int setattr_truncate_idmapped(void)
8412 {
8413         int fret = -1;
8414         int file1_fd = -EBADF, open_tree_fd = -EBADF;
8415         pid_t pid;
8416         struct mount_attr attr = {
8417                 .attr_set = MOUNT_ATTR_IDMAP,
8418         };
8419
8420         /* Changing mount properties on a detached mount. */
8421         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
8422         if (attr.userns_fd < 0) {
8423                 log_stderr("failure: get_userns_fd");
8424                 goto out;
8425         }
8426
8427         open_tree_fd = sys_open_tree(t_dir1_fd, "",
8428                                      AT_EMPTY_PATH |
8429                                      AT_NO_AUTOMOUNT |
8430                                      AT_SYMLINK_NOFOLLOW |
8431                                      OPEN_TREE_CLOEXEC |
8432                                      OPEN_TREE_CLONE);
8433         if (open_tree_fd < 0) {
8434                 log_stderr("failure: sys_open_tree");
8435                 goto out;
8436         }
8437
8438         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8439                 log_stderr("failure: sys_mount_setattr");
8440                 goto out;
8441         }
8442
8443         pid = fork();
8444         if (pid < 0) {
8445                 log_stderr("failure: fork");
8446                 goto out;
8447         }
8448         if (pid == 0) {
8449                 if (!switch_ids(10000, 10000))
8450                         die("failure: switch_ids");
8451
8452                 /* create regular file via open() */
8453                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8454                 if (file1_fd < 0)
8455                         die("failure: create");
8456
8457                 if (ftruncate(file1_fd, 10000))
8458                         die("failure: ftruncate");
8459
8460                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8461                         die("failure: check ownership");
8462
8463                 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8464                         die("failure: expected_file_size");
8465
8466                 if (ftruncate(file1_fd, 0))
8467                         die("failure: ftruncate");
8468
8469                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8470                         die("failure: check ownership");
8471
8472                 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8473                         die("failure: expected_file_size");
8474
8475                 exit(EXIT_SUCCESS);
8476         }
8477         if (wait_for_pid(pid))
8478                 goto out;
8479
8480         pid = fork();
8481         if (pid < 0) {
8482                 log_stderr("failure: fork");
8483                 goto out;
8484         }
8485         if (pid == 0) {
8486                 int file1_fd2 = -EBADF;
8487
8488                 /* create regular file via open() */
8489                 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8490                 if (file1_fd2 < 0)
8491                         die("failure: create");
8492
8493                 if (ftruncate(file1_fd2, 10000))
8494                         die("failure: ftruncate");
8495
8496                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8497                         die("failure: check ownership");
8498
8499                 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8500                         die("failure: expected_file_size");
8501
8502                 if (ftruncate(file1_fd2, 0))
8503                         die("failure: ftruncate");
8504
8505                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8506                         die("failure: check ownership");
8507
8508                 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8509                         die("failure: expected_file_size");
8510
8511                 exit(EXIT_SUCCESS);
8512         }
8513         if (wait_for_pid(pid))
8514                 goto out;
8515
8516         fret = 0;
8517         log_debug("Ran test");
8518 out:
8519         safe_close(file1_fd);
8520         safe_close(open_tree_fd);
8521
8522         return fret;
8523 }
8524
8525 static int setattr_truncate_idmapped_in_userns(void)
8526 {
8527         int fret = -1;
8528         int file1_fd = -EBADF, open_tree_fd = -EBADF;
8529         struct mount_attr attr = {
8530                 .attr_set = MOUNT_ATTR_IDMAP,
8531         };
8532         pid_t pid;
8533
8534         /* Changing mount properties on a detached mount. */
8535         attr.userns_fd  = get_userns_fd(0, 10000, 10000);
8536         if (attr.userns_fd < 0) {
8537                 log_stderr("failure: get_userns_fd");
8538                 goto out;
8539         }
8540
8541         open_tree_fd = sys_open_tree(t_dir1_fd, "",
8542                                      AT_EMPTY_PATH |
8543                                      AT_NO_AUTOMOUNT |
8544                                      AT_SYMLINK_NOFOLLOW |
8545                                      OPEN_TREE_CLOEXEC |
8546                                      OPEN_TREE_CLONE);
8547         if (open_tree_fd < 0) {
8548                 log_stderr("failure: sys_open_tree");
8549                 goto out;
8550         }
8551
8552         if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8553                 log_stderr("failure: sys_mount_setattr");
8554                 goto out;
8555         }
8556
8557         pid = fork();
8558         if (pid < 0) {
8559                 log_stderr("failure: fork");
8560                 goto out;
8561         }
8562         if (pid == 0) {
8563                 if (!switch_userns(attr.userns_fd, 0, 0, false))
8564                         die("failure: switch_userns");
8565
8566                 /* create regular file via open() */
8567                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8568                 if (file1_fd < 0)
8569                         die("failure: create");
8570
8571                 if (ftruncate(file1_fd, 10000))
8572                         die("failure: ftruncate");
8573
8574                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8575                         die("failure: check ownership");
8576
8577                 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8578                         die("failure: expected_file_size");
8579
8580                 if (ftruncate(file1_fd, 0))
8581                         die("failure: ftruncate");
8582
8583                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8584                         die("failure: check ownership");
8585
8586                 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8587                         die("failure: expected_file_size");
8588
8589                 if (unlinkat(open_tree_fd, FILE1, 0))
8590                         die("failure: delete");
8591
8592                 exit(EXIT_SUCCESS);
8593         }
8594         if (wait_for_pid(pid))
8595                 goto out;
8596
8597         if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8598                 log_stderr("failure: fchownat");
8599                 goto out;
8600         }
8601
8602         if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8603                 log_stderr("failure: fchownat");
8604                 goto out;
8605         }
8606
8607         pid = fork();
8608         if (pid < 0) {
8609                 log_stderr("failure: fork");
8610                 goto out;
8611         }
8612         if (pid == 0) {
8613                 if (!caps_supported()) {
8614                         log_debug("skip: capability library not installed");
8615                         exit(EXIT_SUCCESS);
8616                 }
8617
8618                 if (!switch_userns(attr.userns_fd, 0, 0, true))
8619                         die("failure: switch_userns");
8620
8621                 /* create regular file via open() */
8622                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8623                 if (file1_fd < 0)
8624                         die("failure: create");
8625
8626                 if (ftruncate(file1_fd, 10000))
8627                         die("failure: ftruncate");
8628
8629                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8630                         die("failure: check ownership");
8631
8632                 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8633                         die("failure: expected_file_size");
8634
8635                 if (ftruncate(file1_fd, 0))
8636                         die("failure: ftruncate");
8637
8638                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8639                         die("failure: check ownership");
8640
8641                 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8642                         die("failure: expected_file_size");
8643
8644                 if (unlinkat(open_tree_fd, FILE1, 0))
8645                         die("failure: delete");
8646
8647                 exit(EXIT_SUCCESS);
8648         }
8649         if (wait_for_pid(pid))
8650                 goto out;
8651
8652         if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8653                 log_stderr("failure: fchownat");
8654                 goto out;
8655         }
8656
8657         if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8658                 log_stderr("failure: fchownat");
8659                 goto out;
8660         }
8661
8662         pid = fork();
8663         if (pid < 0) {
8664                 log_stderr("failure: fork");
8665                 goto out;
8666         }
8667         if (pid == 0) {
8668                 if (!caps_supported()) {
8669                         log_debug("skip: capability library not installed");
8670                         exit(EXIT_SUCCESS);
8671                 }
8672
8673                 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8674                         die("failure: switch_userns");
8675
8676                 /* create regular file via open() */
8677                 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8678                 if (file1_fd < 0)
8679                         die("failure: create");
8680
8681                 if (ftruncate(file1_fd, 10000))
8682                         die("failure: ftruncate");
8683
8684                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8685                         die("failure: check ownership");
8686
8687                 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8688                         die("failure: expected_file_size");
8689
8690                 if (ftruncate(file1_fd, 0))
8691                         die("failure: ftruncate");
8692
8693                 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8694                         die("failure: check ownership");
8695
8696                 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8697                         die("failure: expected_file_size");
8698
8699                 if (unlinkat(open_tree_fd, FILE1, 0))
8700                         die("failure: delete");
8701
8702                 exit(EXIT_SUCCESS);
8703         }
8704         if (wait_for_pid(pid))
8705                 goto out;
8706
8707         fret = 0;
8708         log_debug("Ran test");
8709 out:
8710         safe_close(attr.userns_fd);
8711         safe_close(file1_fd);
8712         safe_close(open_tree_fd);
8713
8714         return fret;
8715 }
8716
8717 static void usage(void)
8718 {
8719         fprintf(stderr, "Description:\n");
8720         fprintf(stderr, "    Run idmapped mount tests\n\n");
8721
8722         fprintf(stderr, "Arguments:\n");
8723         fprintf(stderr, "-d --device        Device used in the tests\n");
8724         fprintf(stderr, "-m --mountpoint    Mountpoint of device\n");
8725
8726         _exit(EXIT_SUCCESS);
8727 }
8728
8729 static const struct option longopts[] = {
8730         {"device",      required_argument,      0,      'd'},
8731         {"fstype",      required_argument,      0,      'f'},
8732         {"mountpoint",  required_argument,      0,      'm'},
8733         {"supported",   no_argument,            0,      's'},
8734         {"help",        no_argument,            0,      'h'},
8735         {NULL,          0,                      0,      0  },
8736 };
8737
8738 struct t_idmapped_mounts {
8739         int (*test)(void);
8740         const char *description;
8741 } t_idmapped_mounts[] = {
8742         { acls,                                                         "posix acls on regular mounts",                                                                 },
8743         { create_in_userns,                                             "create operations in user namespace",                                                          },
8744         { device_node_in_userns,                                        "device node in user namespace",                                                                },
8745         { expected_uid_gid_idmapped_mounts,                             "expected ownership on idmapped mounts",                                                        },
8746         { fscaps,                                                       "fscaps on regular mounts",                                                                     },
8747         { fscaps_idmapped_mounts,                                       "fscaps on idmapped mounts",                                                                    },
8748         { fscaps_idmapped_mounts_in_userns,                             "fscaps on idmapped mounts in user namespace",                                                  },
8749         { fscaps_idmapped_mounts_in_userns_separate_userns,             "fscaps on idmapped mounts in user namespace with different id mappings ",                      },
8750         { fsids_mapped,                                                 "mapped fsids",                                                                                 },
8751         { fsids_unmapped,                                               "unmapped fsids",                                                                               },
8752         { hardlink_crossing_mounts,                                     "cross mount hardlink",                                                                         },
8753         { hardlink_crossing_idmapped_mounts,                            "cross idmapped mount hardlink",                                                                },
8754         { hardlink_from_idmapped_mount,                                 "hardlinks from idmapped mounts",                                                               },
8755         { hardlink_from_idmapped_mount_in_userns,                       "hardlinks from idmapped mounts in user namespace",                                             },
8756 #ifdef HAVE_LIBURING_H
8757         { io_uring,                                                     "io_uring",                                                                                     },
8758         { io_uring_userns,                                              "io_uring in user namespace",                                                                   },
8759         { io_uring_idmapped,                                            "io_uring from idmapped mounts",                                                                },
8760         { io_uring_idmapped_userns,                                     "io_uring from idmapped mounts in user namespace",                                              },
8761         { io_uring_idmapped_unmapped,                                   "io_uring from idmapped mounts with unmapped ids",                                              },
8762         { io_uring_idmapped_unmapped_userns,                            "io_uring from idmapped mounts with unmapped ids in user namespace",                            },
8763 #endif
8764         { protected_symlinks,                                           "following protected symlinks on regular mounts",                                               },
8765         { protected_symlinks_idmapped_mounts,                           "following protected symlinks on idmapped mounts",                                              },
8766         { protected_symlinks_idmapped_mounts_in_userns,                 "following protected symlinks on idmapped mounts in user namespace",                            },
8767         { rename_crossing_mounts,                                       "cross mount rename",                                                                           },
8768         { rename_crossing_idmapped_mounts,                              "cross idmapped mount rename",                                                                  },
8769         { rename_from_idmapped_mount,                                   "rename from idmapped mounts",                                                                  },
8770         { rename_from_idmapped_mount_in_userns,                         "rename from idmapped mounts in user namespace",                                                },
8771         { setattr_truncate,                                             "setattr truncate",                                                                             },
8772         { setattr_truncate_idmapped,                                    "setattr truncate on idmapped mounts",                                                          },
8773         { setattr_truncate_idmapped_in_userns,                          "setattr truncate on idmapped mounts in user namespace",                                        },
8774         { setgid_create,                                                "create operations in directories with setgid bit set",                                         },
8775         { setgid_create_idmapped,                                       "create operations in directories with setgid bit set on idmapped mounts",                      },
8776         { setgid_create_idmapped_in_userns,                             "create operations in directories with setgid bit set on idmapped mounts in user namespace",    },
8777         { setid_binaries,                                               "setid binaries on regular mounts",                                                             },
8778         { setid_binaries_idmapped_mounts,                               "setid binaries on idmapped mounts",                                                            },
8779         { setid_binaries_idmapped_mounts_in_userns,                     "setid binaries on idmapped mounts in user namespace",                                          },
8780         { setid_binaries_idmapped_mounts_in_userns_separate_userns,     "setid binaries on idmapped mounts in user namespace with different id mappings",               },
8781         { sticky_bit_unlink,                                            "sticky bit unlink operations on regular mounts",                                               },
8782         { sticky_bit_unlink_idmapped_mounts,                            "sticky bit unlink operations on idmapped mounts",                                              },
8783         { sticky_bit_unlink_idmapped_mounts_in_userns,                  "sticky bit unlink operations on idmapped mounts in user namespace",                            },
8784         { sticky_bit_rename,                                            "sticky bit rename operations on regular mounts",                                               },
8785         { sticky_bit_rename_idmapped_mounts,                            "sticky bit rename operations on idmapped mounts",                                              },
8786         { sticky_bit_rename_idmapped_mounts_in_userns,                  "sticky bit rename operations on idmapped mounts in user namespace",                            },
8787         { symlink_regular_mounts,                                       "symlink from regular mounts",                                                                  },
8788         { symlink_idmapped_mounts,                                      "symlink from idmapped mounts",                                                                 },
8789         { symlink_idmapped_mounts_in_userns,                            "symlink from idmapped mounts in user namespace",                                               },
8790         { threaded_idmapped_mount_interactions,                         "threaded operations on idmapped mounts",                                                       },
8791 };
8792
8793 int main(int argc, char *argv[])
8794 {
8795         int i, fret, ret;
8796         int index = 0;
8797         bool supported = false;
8798
8799         while ((ret = getopt_long(argc, argv, "", longopts, &index)) != -1) {
8800                 switch (ret) {
8801                 case 'd':
8802                         t_device = optarg;
8803                         break;
8804                 case 'f':
8805                         t_fstype = optarg;
8806                         break;
8807                 case 'm':
8808                         t_mountpoint = optarg;
8809                         break;
8810                 case 's':
8811                         supported = true;
8812                         break;
8813                 case 'h':
8814                         /* fallthrough */
8815                 default:
8816                         usage();
8817                 }
8818         }
8819
8820         if (!t_device)
8821                 die_errno(EINVAL, "test device missing");
8822
8823         if (!t_fstype)
8824                 die_errno(EINVAL, "test filesystem type missing");
8825
8826         if (!t_mountpoint)
8827                 die_errno(EINVAL, "mountpoint of test device missing");
8828
8829         /* create separate mount namespace */
8830         if (unshare(CLONE_NEWNS))
8831                 die("failure: create new mount namespace");
8832
8833         /* turn off mount propagation */
8834         if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
8835                 die("failure: turn mount propagation off");
8836
8837         t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
8838         if (t_mnt_fd < 0)
8839                 die("failed to open %s", t_mountpoint);
8840
8841         /*
8842          * Caller just wants to know whether the filesystem we're on supports
8843          * idmapped mounts.
8844          */
8845         if (supported) {
8846                 int open_tree_fd = -EBADF;
8847                 struct mount_attr attr = {
8848                         .attr_set       = MOUNT_ATTR_IDMAP,
8849                         .userns_fd      = -EBADF,
8850                 };
8851
8852                 /* Changing mount properties on a detached mount. */
8853                 attr.userns_fd  = get_userns_fd(0, 1000, 1);
8854                 if (attr.userns_fd < 0)
8855                         exit(EXIT_FAILURE);
8856
8857                 open_tree_fd = sys_open_tree(t_mnt_fd, "",
8858                                              AT_EMPTY_PATH |
8859                                              AT_NO_AUTOMOUNT |
8860                                              AT_SYMLINK_NOFOLLOW |
8861                                              OPEN_TREE_CLOEXEC |
8862                                              OPEN_TREE_CLONE);
8863                 if (open_tree_fd < 0)
8864                         ret = -1;
8865                 else
8866                         ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr));
8867
8868                 close(open_tree_fd);
8869                 close(attr.userns_fd);
8870
8871                 if (ret)
8872                         exit(EXIT_FAILURE);
8873
8874                 exit(EXIT_SUCCESS);
8875         }
8876
8877         stash_overflowuid();
8878         stash_overflowgid();
8879
8880         fret = EXIT_FAILURE;
8881
8882         /* Proper test suite run. */
8883         for (i = 0; i < (sizeof(t_idmapped_mounts) / sizeof(t_idmapped_mounts[0])); i++) {
8884                 struct t_idmapped_mounts *t = &t_idmapped_mounts[i];
8885                 pid_t pid;
8886
8887                 test_setup();
8888
8889                 pid = fork();
8890                 if (pid < 0)
8891                         goto out;
8892
8893                 if (pid == 0) {
8894                         ret = t->test();
8895                         if (ret) {
8896                                 fprintf(stderr, "failure: %s\n", t->description);
8897                                 exit(EXIT_FAILURE);
8898                         }
8899
8900                         exit(EXIT_SUCCESS);
8901                 }
8902
8903                 ret = wait_for_pid(pid);
8904                 test_cleanup();
8905
8906                 if (ret)
8907                         goto out;
8908         }
8909
8910         fret = EXIT_SUCCESS;
8911
8912 out:
8913         exit(fret);
8914 }