1 // SPDX-License-Identifier: GPL-2.0
14 #include <linux/limits.h>
15 #include <linux/types.h>
19 #include <sys/fsuid.h>
21 #include <sys/types.h>
22 #include <sys/xattr.h>
25 #ifdef HAVE_SYS_CAPABILITY_H
26 #include <sys/capability.h>
29 #ifdef HAVE_LIBURING_H
36 #define T_DIR1 "idmapped_mounts_1"
38 #define FILE1_RENAME "file1_rename"
40 #define FILE2_RENAME "file2_rename"
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"
52 #define log_stderr(format, ...) \
53 fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \
57 #define log_debug(format, ...) \
58 fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \
59 __func__, ##__VA_ARGS__)
61 #define log_debug(format, ...)
64 #define log_error_errno(__ret__, __errno__, format, ...) \
66 typeof(__ret__) __internal_ret__ = (__ret__); \
67 errno = (__errno__); \
68 log_stderr(format, ##__VA_ARGS__); \
72 #define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__)
74 #define die_errno(__errno__, format, ...) \
76 errno = (__errno__); \
77 log_stderr(format, ##__VA_ARGS__); \
81 #define die(format, ...) die_errno(errno, format, ##__VA_ARGS__)
83 uid_t t_overflowuid = 65534;
84 gid_t t_overflowgid = 65534;
86 /* path of the test device */
89 /* path of the test device */
92 /* mountpoint of the test device */
93 const char *t_mountpoint;
95 /* fd for @t_mountpoint */
101 /* temporary buffer */
102 char t_buf[PATH_MAX];
104 static void stash_overflowuid(void)
110 fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
114 ret = read(fd, buf, sizeof(buf));
119 t_overflowuid = atoi(buf);
122 static void stash_overflowgid(void)
128 fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
132 ret = read(fd, buf, sizeof(buf));
137 t_overflowgid = atoi(buf);
140 static bool is_xfs(void)
142 static int enabled = -1;
145 enabled = !strcmp(t_fstype, "xfs");
150 static bool protected_symlinks_enabled(void)
152 static int enabled = -1;
161 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
165 ret = read(fd, buf, sizeof(buf));
177 static bool xfs_irix_sgid_inherit_enabled(void)
179 static int enabled = -1;
189 fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
193 ret = read(fd, buf, sizeof(buf));
206 static inline bool caps_supported(void)
210 #ifdef HAVE_SYS_CAPABILITY_H
217 /* caps_down - lower all effective caps */
218 static int caps_down(void)
221 #ifdef HAVE_SYS_CAPABILITY_H
225 caps = cap_get_proc();
229 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
233 ret = cap_set_proc(caps);
245 /* caps_up - raise all permitted caps */
246 static int caps_up(void)
249 #ifdef HAVE_SYS_CAPABILITY_H
254 caps = cap_get_proc();
258 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
259 cap_flag_value_t flag;
261 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
269 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
274 ret = cap_set_proc(caps);
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)
292 ret = fstatat(dfd, path, &st, flags);
294 return log_errno(false, "failure: fstatat");
296 if (log && st.st_uid != expected_uid)
297 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
299 if (log && st.st_gid != expected_gid)
300 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
302 errno = 0; /* Don't report misleading errno. */
303 return st.st_uid == expected_uid && st.st_gid == expected_gid;
306 static bool expected_uid_gid(int dfd, const char *path, int flags,
307 uid_t expected_uid, gid_t expected_gid)
309 return __expected_uid_gid(dfd, path, flags,
310 expected_uid, expected_gid, true);
313 static bool expected_file_size(int dfd, const char *path,
314 int flags, off_t expected_size)
319 ret = fstatat(dfd, path, &st, flags);
321 return log_errno(false, "failure: fstatat");
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);
330 /* is_setid - check whether file is S_ISUID and S_ISGID */
331 static bool is_setid(int dfd, const char *path, int flags)
336 ret = fstatat(dfd, path, &st, flags);
340 errno = 0; /* Don't report misleading errno. */
341 return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
344 /* is_setgid - check whether file or directory is S_ISGID */
345 static bool is_setgid(int dfd, const char *path, int flags)
350 ret = fstatat(dfd, path, &st, flags);
354 errno = 0; /* Don't report misleading errno. */
355 return (st.st_mode & S_ISGID);
358 /* is_sticky - check whether file is S_ISVTX */
359 static bool is_sticky(int dfd, const char *path, int flags)
364 ret = fstatat(dfd, path, &st, flags);
368 errno = 0; /* Don't report misleading errno. */
369 return (st.st_mode & S_ISVTX) > 0;
372 static inline int set_cloexec(int fd)
374 return fcntl(fd, F_SETFD, FD_CLOEXEC);
377 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
380 return log_errno(false, "failure: setfsgid");
382 if (setfsgid(-1) != fsgid)
383 return log_errno(false, "failure: setfsgid(-1)");
386 return log_errno(false, "failure: setfsuid");
388 if (setfsuid(-1) != fsuid)
389 return log_errno(false, "failure: setfsuid(-1)");
394 static inline bool switch_ids(uid_t uid, gid_t gid)
396 if (setgroups(0, NULL))
397 return log_errno(false, "failure: setgroups");
399 if (setresgid(gid, gid, gid))
400 return log_errno(false, "failure: setresgid");
402 if (setresuid(uid, uid, uid))
403 return log_errno(false, "failure: setresuid");
408 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
410 if (setns(fd, CLONE_NEWUSER))
411 return log_errno(false, "failure: setns");
413 if (!switch_ids(uid, gid))
414 return log_errno(false, "failure: switch_ids");
416 if (drop_caps && !caps_down())
417 return log_errno(false, "failure: caps_down");
422 /* rm_r - recursively remove all files */
423 static int rm_r(int fd, const char *path)
427 struct dirent *direntp;
429 if (!path || strcmp(path, "") == 0)
432 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
436 dir = fdopendir(dfd);
442 while ((direntp = readdir(dir))) {
445 if (!strcmp(direntp->d_name, ".") ||
446 !strcmp(direntp->d_name, ".."))
449 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
450 if (ret < 0 && errno != ENOENT)
453 if (S_ISDIR(st.st_mode))
454 ret = rm_r(dfd, direntp->d_name);
456 ret = unlinkat(dfd, direntp->d_name, 0);
457 if (ret < 0 && errno != ENOENT)
461 ret = unlinkat(fd, path, AT_REMOVEDIR);
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)
471 struct dirent *direntp;
473 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
477 dir = fdopendir(dfd);
483 while ((direntp = readdir(dir))) {
486 if (!strcmp(direntp->d_name, ".") ||
487 !strcmp(direntp->d_name, ".."))
490 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
491 if (ret < 0 && errno != ENOENT)
494 if (S_ISDIR(st.st_mode))
495 ret = chown_r(dfd, direntp->d_name, uid, gid);
497 ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
498 if (ret < 0 && errno != ENOENT)
502 ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
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.
513 static int fd_cloexec(int fd, bool cloexec)
517 oflags = fcntl(fd, F_GETFD, 0);
522 nflags = oflags | FD_CLOEXEC;
524 nflags = oflags & ~FD_CLOEXEC;
526 if (nflags == oflags)
529 if (fcntl(fd, F_SETFD, nflags) < 0)
535 static inline int dup_cloexec(int fd)
543 if (fd_cloexec(fd_dup, true)) {
551 __attribute__((unused)) static int print_r(int fd, const char *path)
556 struct dirent *direntp;
559 if (!path || *path == '\0') {
560 char buf[sizeof("/proc/self/fd/") + 30];
562 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
563 if (ret < 0 || (size_t)ret >= sizeof(buf))
567 * O_PATH file descriptors can't be used so we need to re-open
570 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
572 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
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
583 dfd_dup = dup_cloexec(dfd);
589 dir = fdopendir(dfd);
595 /* Transfer ownership to fdopendir(). */
598 while ((direntp = readdir(dir))) {
599 if (!strcmp(direntp->d_name, ".") ||
600 !strcmp(direntp->d_name, ".."))
603 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
604 if (ret < 0 && errno != ENOENT)
608 if (S_ISDIR(st.st_mode))
609 ret = print_r(dfd_dup, direntp->d_name);
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)
618 if (!path || *path == '\0')
619 ret = fstatat(fd, "", &st,
620 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
623 ret = fstatat(fd, path, &st,
624 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
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)");
637 /* fd_to_fd - transfer data from one fd to another */
638 static int fd_to_fd(int from, int to)
641 uint8_t buf[PATH_MAX];
643 ssize_t bytes_to_write;
646 bytes_read = read_nointr(from, buf, sizeof buf);
652 bytes_to_write = (size_t)bytes_read;
654 ssize_t bytes_written;
656 bytes_written = write_nointr(to, p, bytes_to_write);
657 if (bytes_written < 0)
660 bytes_to_write -= bytes_written;
662 } while (bytes_to_write > 0);
668 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
672 return syscall(__NR_execveat, fd, path, argv, envp, flags);
680 #define CAP_NET_RAW 13
683 #ifndef VFS_CAP_FLAGS_EFFECTIVE
684 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
687 #ifndef VFS_CAP_U32_3
688 #define VFS_CAP_U32_3 2
692 #define VFS_CAP_U32 VFS_CAP_U32_3
695 #ifndef VFS_CAP_REVISION_1
696 #define VFS_CAP_REVISION_1 0x01000000
699 #ifndef VFS_CAP_REVISION_2
700 #define VFS_CAP_REVISION_2 0x02000000
703 #ifndef VFS_CAP_REVISION_3
704 #define VFS_CAP_REVISION_3 0x03000000
705 struct vfs_ns_cap_data {
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))
728 #error Expected endianess macro to be set
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)
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 = {};
739 ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
740 if (ret < 0 || ret == 0)
743 if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
745 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
747 log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
750 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
751 (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
753 log_stderr("failure: fscaps version");
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)
762 #define __raise_cap_permitted(x, ns_cap_data) \
763 ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
765 struct vfs_ns_cap_data ns_xattr;
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);
772 return fsetxattr(fd, "security.capability",
773 &ns_xattr, sizeof(ns_xattr), flags);
776 #define safe_close(fd) \
784 static void test_setup(void)
786 if (mkdirat(t_mnt_fd, T_DIR1, 0777))
787 die("failure: mkdirat");
789 t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
791 die("failure: openat");
793 if (fchmod(t_dir1_fd, 0777))
794 die("failure: fchmod");
797 static void test_cleanup(void)
799 safe_close(t_dir1_fd);
800 if (rm_r(t_mnt_fd, T_DIR1))
801 die("failure: rm_r");
804 /* Validate that basic file operations on idmapped mounts. */
805 static int fsids_unmapped(void)
808 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
809 struct mount_attr attr = {
810 .attr_set = MOUNT_ATTR_IDMAP,
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");
820 /* create directory for rename test */
821 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
822 log_stderr("failure: mkdirat");
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");
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");
839 open_tree_fd = sys_open_tree(t_dir1_fd, "",
842 AT_SYMLINK_NOFOLLOW |
845 if (open_tree_fd < 0) {
846 log_stderr("failure: sys_open_tree");
850 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
851 log_stderr("failure: sys_mount_setattr");
855 if (!switch_fsids(0, 0)) {
856 log_stderr("failure: switch_fsids");
860 /* The caller's fsids don't have a mappings in the idmapped mount so any
861 * file creation must fail.
864 /* create hardlink */
865 if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
866 log_stderr("failure: linkat");
869 if (errno != EOVERFLOW) {
870 log_stderr("failure: errno");
874 /* try to rename a file */
875 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
876 log_stderr("failure: renameat");
879 if (errno != EOVERFLOW) {
880 log_stderr("failure: errno");
884 /* try to rename a directory */
885 if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
886 log_stderr("failure: renameat");
889 if (errno != EOVERFLOW) {
890 log_stderr("failure: errno");
894 /* The caller is privileged over the inode so file deletion must work. */
897 if (unlinkat(open_tree_fd, FILE1, 0)) {
898 log_stderr("failure: unlinkat");
902 /* remove directory */
903 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
904 log_stderr("failure: unlinkat");
908 /* The caller's fsids don't have a mappings in the idmapped mount so
909 * any file creation must fail.
912 /* create regular file via open() */
913 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
915 log_stderr("failure: create");
918 if (errno != EOVERFLOW) {
919 log_stderr("failure: errno");
923 /* create regular file via mknod */
924 if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
925 log_stderr("failure: mknodat");
928 if (errno != EOVERFLOW) {
929 log_stderr("failure: errno");
933 /* create character device */
934 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
935 log_stderr("failure: mknodat");
938 if (errno != EOVERFLOW) {
939 log_stderr("failure: errno");
944 if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
945 log_stderr("failure: symlinkat");
948 if (errno != EOVERFLOW) {
949 log_stderr("failure: errno");
953 /* create directory */
954 if (!mkdirat(open_tree_fd, DIR1, 0700)) {
955 log_stderr("failure: mkdirat");
958 if (errno != EOVERFLOW) {
959 log_stderr("failure: errno");
964 log_debug("Ran test");
966 safe_close(attr.userns_fd);
967 safe_close(hardlink_target_fd);
968 safe_close(file1_fd);
969 safe_close(open_tree_fd);
974 static int fsids_mapped(void)
977 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
978 struct mount_attr attr = {
979 .attr_set = MOUNT_ATTR_IDMAP,
983 if (!caps_supported())
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");
993 /* create directory for rename test */
994 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
995 log_stderr("failure: mkdirat");
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");
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");
1012 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1015 AT_SYMLINK_NOFOLLOW |
1018 if (open_tree_fd < 0) {
1019 log_stderr("failure: sys_open_tree");
1023 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1024 log_stderr("failure: sys_mount_setattr");
1030 log_stderr("failure: fork");
1034 if (!switch_fsids(10000, 10000))
1035 die("failure: switch fsids");
1038 die("failure: raise caps");
1040 /* The caller's fsids now have mappings in the idmapped mount so
1041 * any file creation must fail.
1044 /* create hardlink */
1045 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1046 die("failure: create hardlink");
1048 /* try to rename a file */
1049 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1050 die("failure: rename");
1052 /* try to rename a directory */
1053 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1054 die("failure: rename");
1057 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1058 die("failure: delete");
1060 /* remove directory */
1061 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1062 die("failure: delete");
1064 /* The caller's fsids have mappings in the idmapped mount so any
1065 * file creation must fail.
1068 /* create regular file via open() */
1069 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1071 die("failure: create");
1073 /* create regular file via mknod */
1074 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1075 die("failure: create");
1077 /* create character device */
1078 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1079 die("failure: create");
1081 /* create symlink */
1082 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1083 die("failure: create");
1085 /* create directory */
1086 if (mkdirat(open_tree_fd, DIR1, 0700))
1087 die("failure: create");
1091 if (wait_for_pid(pid))
1095 log_debug("Ran test");
1097 safe_close(attr.userns_fd);
1098 safe_close(file1_fd);
1099 safe_close(hardlink_target_fd);
1100 safe_close(open_tree_fd);
1105 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1106 static int create_in_userns(void)
1109 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1110 struct mount_attr attr = {
1111 .attr_set = MOUNT_ATTR_IDMAP,
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");
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");
1128 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1131 AT_SYMLINK_NOFOLLOW |
1134 if (open_tree_fd < 0) {
1135 log_stderr("failure: sys_open_tree");
1139 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1140 log_stderr("failure: sys_mount_setattr");
1146 log_stderr("failure: fork");
1150 if (!switch_userns(attr.userns_fd, 0, 0, false))
1151 die("failure: switch_userns");
1153 /* create regular file via open() */
1154 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1156 die("failure: open file");
1157 safe_close(file1_fd);
1159 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1160 die("failure: check ownership");
1162 /* create regular file via mknod */
1163 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1164 die("failure: create");
1166 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1167 die("failure: check ownership");
1169 /* create symlink */
1170 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1171 die("failure: create");
1173 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1174 die("failure: check ownership");
1176 /* create directory */
1177 if (mkdirat(open_tree_fd, DIR1, 0700))
1178 die("failure: create");
1180 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1181 die("failure: check ownership");
1183 /* try to rename a file */
1184 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1185 die("failure: create");
1187 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1188 die("failure: check ownership");
1190 /* try to rename a file */
1191 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1192 die("failure: create");
1194 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1195 die("failure: check ownership");
1198 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1199 die("failure: remove");
1201 /* remove directory */
1202 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1203 die("failure: remove");
1208 if (wait_for_pid(pid))
1212 log_debug("Ran test");
1214 safe_close(attr.userns_fd);
1215 safe_close(file1_fd);
1216 safe_close(open_tree_fd);
1221 static int hardlink_crossing_mounts(void)
1224 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1226 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1227 log_stderr("failure: chown_r");
1231 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1234 AT_SYMLINK_NOFOLLOW |
1237 if (open_tree_fd < 0) {
1238 log_stderr("failure: sys_open_tree");
1242 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1244 log_stderr("failure: openat");
1248 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1249 log_stderr("failure: mkdirat");
1253 /* We're crossing a mountpoint so this must fail.
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.
1259 if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1260 log_stderr("failure: linkat");
1263 if (errno != EXDEV) {
1264 log_stderr("failure: errno");
1269 log_debug("Ran test");
1271 safe_close(file1_fd);
1272 safe_close(open_tree_fd);
1277 static int hardlink_crossing_idmapped_mounts(void)
1280 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1281 struct mount_attr attr = {
1282 .attr_set = MOUNT_ATTR_IDMAP,
1285 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1286 log_stderr("failure: chown_r");
1290 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1291 if (attr.userns_fd < 0) {
1292 log_stderr("failure: get_userns_fd");
1296 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1299 AT_SYMLINK_NOFOLLOW |
1302 if (open_tree_fd1 < 0) {
1303 log_stderr("failure: sys_open_tree");
1307 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1308 log_stderr("failure: sys_mount_setattr");
1312 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1314 log_stderr("failure: openat");
1318 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1319 log_stderr("failure: expected_uid_gid");
1323 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1324 log_stderr("failure: expected_uid_gid");
1328 safe_close(file1_fd);
1330 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1331 log_stderr("failure: mkdirat");
1335 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1337 AT_SYMLINK_NOFOLLOW |
1341 if (open_tree_fd2 < 0) {
1342 log_stderr("failure: sys_open_tree");
1346 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1347 log_stderr("failure: sys_mount_setattr");
1351 /* We're crossing a mountpoint so this must fail.
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.
1357 if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1358 log_stderr("failure: linkat");
1361 if (errno != EXDEV) {
1362 log_stderr("failure: errno");
1367 log_debug("Ran test");
1369 safe_close(attr.userns_fd);
1370 safe_close(file1_fd);
1371 safe_close(open_tree_fd1);
1372 safe_close(open_tree_fd2);
1377 static int hardlink_from_idmapped_mount(void)
1380 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1381 struct mount_attr attr = {
1382 .attr_set = MOUNT_ATTR_IDMAP,
1385 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1386 log_stderr("failure: chown_r");
1390 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1391 if (attr.userns_fd < 0) {
1392 log_stderr("failure: get_userns_fd");
1396 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1399 AT_SYMLINK_NOFOLLOW |
1402 if (open_tree_fd < 0) {
1403 log_stderr("failure: sys_open_tree");
1407 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1408 log_stderr("failure: sys_mount_setattr");
1412 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1414 log_stderr("failure: openat");
1417 safe_close(file1_fd);
1419 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1420 log_stderr("failure: expected_uid_gid");
1424 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1425 log_stderr("failure: expected_uid_gid");
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");
1437 log_debug("Ran test");
1439 safe_close(attr.userns_fd);
1440 safe_close(file1_fd);
1441 safe_close(open_tree_fd);
1446 static int hardlink_from_idmapped_mount_in_userns(void)
1449 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1450 struct mount_attr attr = {
1451 .attr_set = MOUNT_ATTR_IDMAP,
1455 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1456 log_stderr("failure: chown_r");
1460 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1461 if (attr.userns_fd < 0) {
1462 log_stderr("failure: get_userns_fd");
1466 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1469 AT_SYMLINK_NOFOLLOW |
1472 if (open_tree_fd < 0) {
1473 log_stderr("failure: sys_open_tree");
1477 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1478 log_stderr("failure: sys_mount_setattr");
1484 log_stderr("failure: fork");
1488 if (!switch_userns(attr.userns_fd, 0, 0, false))
1489 die("failure: switch_userns");
1491 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1493 die("failure: create");
1495 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1496 die("failure: check ownership");
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");
1502 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1503 die("failure: check ownership");
1508 if (wait_for_pid(pid))
1512 log_debug("Ran test");
1514 safe_close(attr.userns_fd);
1515 safe_close(file1_fd);
1516 safe_close(open_tree_fd);
1521 static int rename_crossing_mounts(void)
1524 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1526 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1527 log_stderr("failure: chown_r");
1531 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1534 AT_SYMLINK_NOFOLLOW |
1537 if (open_tree_fd < 0) {
1538 log_stderr("failure: sys_open_tree");
1542 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1544 log_stderr("failure: openat");
1548 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1549 log_stderr("failure: mkdirat");
1553 /* We're crossing a mountpoint so this must fail.
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.
1559 if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1560 log_stderr("failure: renameat");
1563 if (errno != EXDEV) {
1564 log_stderr("failure: errno");
1569 log_debug("Ran test");
1571 safe_close(file1_fd);
1572 safe_close(open_tree_fd);
1577 static int rename_crossing_idmapped_mounts(void)
1580 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1581 struct mount_attr attr = {
1582 .attr_set = MOUNT_ATTR_IDMAP,
1585 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1586 log_stderr("failure: chown_r");
1590 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1591 if (attr.userns_fd < 0) {
1592 log_stderr("failure: get_userns_fd");
1596 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1599 AT_SYMLINK_NOFOLLOW |
1602 if (open_tree_fd1 < 0) {
1603 log_stderr("failure: sys_open_tree");
1607 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1608 log_stderr("failure: sys_mount_setattr");
1612 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1614 log_stderr("failure: openat");
1618 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1619 log_stderr("failure: expected_uid_gid");
1623 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1624 log_stderr("failure: expected_uid_gid");
1628 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1629 log_stderr("failure: mkdirat");
1633 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1635 AT_SYMLINK_NOFOLLOW |
1639 if (open_tree_fd2 < 0) {
1640 log_stderr("failure: sys_open_tree");
1644 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1645 log_stderr("failure: sys_mount_setattr");
1649 /* We're crossing a mountpoint so this must fail.
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.
1655 if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1656 log_stderr("failure: renameat");
1659 if (errno != EXDEV) {
1660 log_stderr("failure: errno");
1665 log_debug("Ran test");
1667 safe_close(attr.userns_fd);
1668 safe_close(file1_fd);
1669 safe_close(open_tree_fd1);
1670 safe_close(open_tree_fd2);
1675 static int rename_from_idmapped_mount(void)
1678 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1679 struct mount_attr attr = {
1680 .attr_set = MOUNT_ATTR_IDMAP,
1683 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1684 log_stderr("failure: chown_r");
1688 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1689 if (attr.userns_fd < 0) {
1690 log_stderr("failure: get_userns_fd");
1694 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1697 AT_SYMLINK_NOFOLLOW |
1700 if (open_tree_fd < 0) {
1701 log_stderr("failure: sys_open_tree");
1705 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1706 log_stderr("failure: sys_mount_setattr");
1710 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1712 log_stderr("failure: openat");
1716 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1717 log_stderr("failure: expected_uid_gid");
1721 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1722 log_stderr("failure: expected_uid_gid");
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");
1733 log_debug("Ran test");
1735 safe_close(attr.userns_fd);
1736 safe_close(file1_fd);
1737 safe_close(open_tree_fd);
1742 static int rename_from_idmapped_mount_in_userns(void)
1745 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1747 struct mount_attr attr = {
1748 .attr_set = MOUNT_ATTR_IDMAP,
1751 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1752 log_stderr("failure: chown_r");
1756 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1757 if (attr.userns_fd < 0) {
1758 log_stderr("failure: get_userns_fd");
1762 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1765 AT_SYMLINK_NOFOLLOW |
1768 if (open_tree_fd < 0) {
1769 log_stderr("failure: sys_open_tree");
1773 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1774 log_stderr("failure: sys_mount_setattr");
1780 log_stderr("failure: fork");
1784 if (!switch_userns(attr.userns_fd, 0, 0, false))
1785 die("failure: switch_userns");
1787 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1789 die("failure: create");
1791 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1792 die("failure: check ownership");
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");
1798 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1799 die("failure: check ownership");
1804 if (wait_for_pid(pid))
1808 log_debug("Ran test");
1810 safe_close(attr.userns_fd);
1811 safe_close(file1_fd);
1812 safe_close(open_tree_fd);
1817 static int symlink_regular_mounts(void)
1820 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1823 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1825 log_stderr("failure: openat");
1829 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1830 log_stderr("failure: chown_r");
1834 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1837 AT_SYMLINK_NOFOLLOW |
1840 if (open_tree_fd < 0) {
1841 log_stderr("failure: sys_open_tree");
1845 if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1846 log_stderr("failure: symlinkat");
1850 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1851 log_stderr("failure: fchownat");
1855 if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1856 log_stderr("failure: fstatat");
1860 if (st.st_uid != 15000 || st.st_gid != 15000) {
1861 log_stderr("failure: compare ids");
1865 if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1866 log_stderr("failure: fstatat");
1870 if (st.st_uid != 10000 || st.st_gid != 10000) {
1871 log_stderr("failure: compare ids");
1876 log_debug("Ran test");
1878 safe_close(file1_fd);
1879 safe_close(open_tree_fd);
1884 static int symlink_idmapped_mounts(void)
1887 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1888 struct mount_attr attr = {
1889 .attr_set = MOUNT_ATTR_IDMAP,
1893 if (!caps_supported())
1896 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1898 log_stderr("failure: openat");
1902 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1903 log_stderr("failure: chown_r");
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");
1914 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1917 AT_SYMLINK_NOFOLLOW |
1920 if (open_tree_fd < 0) {
1921 log_stderr("failure: sys_open_tree");
1925 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1926 log_stderr("failure: sys_mount_setattr");
1932 log_stderr("failure: fork");
1936 if (!switch_fsids(10000, 10000))
1937 die("failure: switch fsids");
1940 die("failure: raise caps");
1942 if (symlinkat(FILE1, open_tree_fd, FILE2))
1943 die("failure: create");
1945 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1946 die("failure: change ownership");
1948 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1949 die("failure: check ownership");
1951 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1952 die("failure: check ownership");
1956 if (wait_for_pid(pid))
1960 log_debug("Ran test");
1962 safe_close(attr.userns_fd);
1963 safe_close(file1_fd);
1964 safe_close(open_tree_fd);
1969 static int symlink_idmapped_mounts_in_userns(void)
1972 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1973 struct mount_attr attr = {
1974 .attr_set = MOUNT_ATTR_IDMAP,
1978 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1979 log_stderr("failure: chown_r");
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");
1990 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1993 AT_SYMLINK_NOFOLLOW |
1996 if (open_tree_fd < 0) {
1997 log_stderr("failure: sys_open_tree");
2001 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2002 log_stderr("failure: sys_mount_setattr");
2008 log_stderr("failure: fork");
2012 if (!switch_userns(attr.userns_fd, 0, 0, false))
2013 die("failure: switch_userns");
2015 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2017 die("failure: create");
2018 safe_close(file1_fd);
2020 if (symlinkat(FILE1, open_tree_fd, FILE2))
2021 die("failure: create");
2023 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2024 die("failure: change ownership");
2026 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2027 die("failure: check ownership");
2029 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2030 die("failure: check ownership");
2035 if (wait_for_pid(pid))
2038 if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2039 log_stderr("failure: expected_uid_gid");
2043 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2044 log_stderr("failure: expected_uid_gid");
2049 log_debug("Ran test");
2051 safe_close(attr.userns_fd);
2052 safe_close(file1_fd);
2053 safe_close(open_tree_fd);
2058 /* Validate that a caller whose fsids map into the idmapped mount within it's
2059 * user namespace cannot create any device nodes.
2061 static int device_node_in_userns(void)
2064 int open_tree_fd = -EBADF;
2065 struct mount_attr attr = {
2066 .attr_set = MOUNT_ATTR_IDMAP,
2070 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2071 if (attr.userns_fd < 0) {
2072 log_stderr("failure: get_userns_fd");
2076 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2079 AT_SYMLINK_NOFOLLOW |
2082 if (open_tree_fd < 0) {
2083 log_stderr("failure: sys_open_tree");
2087 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2088 log_stderr("failure: sys_mount_setattr");
2094 log_stderr("failure: fork");
2098 if (!switch_userns(attr.userns_fd, 0, 0, false))
2099 die("failure: switch_userns");
2101 /* create character device */
2102 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2103 die("failure: create");
2108 if (wait_for_pid(pid))
2112 log_debug("Ran test");
2114 safe_close(attr.userns_fd);
2115 safe_close(open_tree_fd);
2121 /* Validate that changing file ownership works correctly on idmapped mounts. */
2122 static int expected_uid_gid_idmapped_mounts(void)
2125 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2126 struct mount_attr attr1 = {
2127 .attr_set = MOUNT_ATTR_IDMAP,
2129 struct mount_attr attr2 = {
2130 .attr_set = MOUNT_ATTR_IDMAP,
2134 if (!switch_fsids(0, 0)) {
2135 log_stderr("failure: switch_fsids");
2139 /* create regular file via open() */
2140 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2142 log_stderr("failure: openat");
2146 /* create regular file via mknod */
2147 if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2148 log_stderr("failure: mknodat");
2152 /* create character device */
2153 if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2154 log_stderr("failure: mknodat");
2158 /* create hardlink */
2159 if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2160 log_stderr("failure: linkat");
2164 /* create symlink */
2165 if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2166 log_stderr("failure: symlinkat");
2170 /* create directory */
2171 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2172 log_stderr("failure: mkdirat");
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");
2183 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2186 AT_SYMLINK_NOFOLLOW |
2189 if (open_tree_fd1 < 0) {
2190 log_stderr("failure: sys_open_tree");
2194 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2195 log_stderr("failure: sys_mount_setattr");
2199 /* Validate that all files created through the image mountpoint are
2200 * owned by the callers fsuid and fsgid.
2202 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2203 log_stderr("failure: expected_uid_gid");
2206 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2207 log_stderr("failure: expected_uid_gid");
2210 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2211 log_stderr("failure: expected_uid_gid");
2214 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2215 log_stderr("failure: expected_uid_gid");
2218 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2219 log_stderr("failure: expected_uid_gid");
2222 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2223 log_stderr("failure: expected_uid_gid");
2226 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2227 log_stderr("failure: expected_uid_gid");
2231 /* Validate that all files are owned by the uid and gid specified in
2232 * the idmapping of the mount they are accessed from.
2234 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2235 log_stderr("failure: expected_uid_gid");
2238 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2239 log_stderr("failure: expected_uid_gid");
2242 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2243 log_stderr("failure: expected_uid_gid");
2246 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2247 log_stderr("failure: expected_uid_gid");
2250 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2251 log_stderr("failure: expected_uid_gid");
2254 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2255 log_stderr("failure: expected_uid_gid");
2258 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2259 log_stderr("failure: expected_uid_gid");
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");
2270 open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2273 AT_SYMLINK_NOFOLLOW |
2276 if (open_tree_fd2 < 0) {
2277 log_stderr("failure: sys_open_tree");
2281 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2282 log_stderr("failure: sys_mount_setattr");
2286 /* Validate that all files are owned by the uid and gid specified in
2287 * the idmapping of the mount they are accessed from.
2289 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2290 log_stderr("failure: expected_uid_gid");
2293 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2294 log_stderr("failure: expected_uid_gid");
2297 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2298 log_stderr("failure: expected_uid_gid");
2301 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2302 log_stderr("failure: expected_uid_gid");
2305 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2306 log_stderr("failure: expected_uid_gid");
2309 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2310 log_stderr("failure: expected_uid_gid");
2313 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2314 log_stderr("failure: expected_uid_gid");
2318 /* Change ownership throught original image mountpoint. */
2319 if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2320 log_stderr("failure: fchownat");
2323 if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2324 log_stderr("failure: fchownat");
2327 if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2328 log_stderr("failure: fchownat");
2331 if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2332 log_stderr("failure: fchownat");
2335 if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2336 log_stderr("failure: fchownat");
2339 if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2340 log_stderr("failure: fchownat");
2343 if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2344 log_stderr("failure: fchownat");
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");
2353 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2354 log_stderr("failure: expected_uid_gid");
2357 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2358 log_stderr("failure: expected_uid_gid");
2361 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2362 log_stderr("failure: expected_uid_gid");
2365 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2366 log_stderr("failure: expected_uid_gid");
2369 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2370 log_stderr("failure: expected_uid_gid");
2373 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2374 log_stderr("failure: expected_uid_gid");
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 ");
2383 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2384 log_stderr("failure: expected_uid_gid");
2387 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2388 log_stderr("failure: expected_uid_gid");
2391 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2392 log_stderr("failure: expected_uid_gid");
2395 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2396 log_stderr("failure: expected_uid_gid");
2399 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2400 log_stderr("failure:expected_uid_gid ");
2403 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2404 log_stderr("failure: expected_uid_gid");
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");
2413 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2414 log_stderr("failure: expected_uid_gid");
2417 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2418 log_stderr("failure: expected_uid_gid");
2421 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2422 log_stderr("failure: expected_uid_gid");
2425 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2426 log_stderr("failure: expected_uid_gid");
2429 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2430 log_stderr("failure: expected_uid_gid");
2433 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2434 log_stderr("failure: expected_uid_gid");
2440 log_stderr("failure: fork");
2444 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2445 die("failure: switch_userns");
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");
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");
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");
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");
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");
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");
2540 if (wait_for_pid(pid))
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");
2548 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2549 log_stderr("failure: expected_uid_gid");
2552 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2553 log_stderr("failure: expected_uid_gid");
2556 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2557 log_stderr("failure: expected_uid_gid");
2560 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2561 log_stderr("failure: expected_uid_gid");
2564 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2565 log_stderr("failure: expected_uid_gid");
2568 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2569 log_stderr("failure: expected_uid_gid");
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");
2578 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2579 log_stderr("failure: expected_uid_gid");
2582 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2583 log_stderr("failure: expected_uid_gid");
2586 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2587 log_stderr("failure: expected_uid_gid");
2590 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2591 log_stderr("failure: expected_uid_gid");
2594 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2595 log_stderr("failure: expected_uid_gid");
2598 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2599 log_stderr("failure: expected_uid_gid");
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");
2608 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2609 log_stderr("failure: expected_uid_gid");
2612 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2613 log_stderr("failure: expected_uid_gid");
2616 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2617 log_stderr("failure: expected_uid_gid");
2620 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2621 log_stderr("failure: expected_uid_gid");
2624 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2625 log_stderr("failure: expected_uid_gid");
2628 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2629 log_stderr("failure: expected_uid_gid");
2635 log_stderr("failure: fork");
2639 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2640 die("failure: switch_userns");
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");
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");
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");
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");
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");
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");
2735 if (wait_for_pid(pid))
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");
2743 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2744 log_stderr("failure: expected_uid_gid");
2747 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2748 log_stderr("failure: expected_uid_gid");
2751 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2752 log_stderr("failure: expected_uid_gid");
2755 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2756 log_stderr("failure: expected_uid_gid");
2759 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2760 log_stderr("failure: expected_uid_gid");
2763 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2764 log_stderr("failure: expected_uid_gid");
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");
2773 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2774 log_stderr("failure: expected_uid_gid");
2777 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2778 log_stderr("failure: expected_uid_gid");
2781 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2782 log_stderr("failure: expected_uid_gid");
2785 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2786 log_stderr("failure: expected_uid_gid");
2789 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2790 log_stderr("failure: expected_uid_gid");
2793 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2794 log_stderr("failure: expected_uid_gid");
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");
2803 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2804 log_stderr("failure: expected_uid_gid");
2807 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2808 log_stderr("failure: expected_uid_gid");
2811 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2812 log_stderr("failure: expected_uid_gid");
2815 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2816 log_stderr("failure: expected_uid_gid");
2819 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2820 log_stderr("failure: expected_uid_gid");
2823 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2824 log_stderr("failure: expected_uid_gid");
2829 log_debug("Ran test");
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);
2840 static int fscaps(void)
2843 int file1_fd = -EBADF;
2844 struct mount_attr attr = {
2845 .attr_set = MOUNT_ATTR_IDMAP,
2849 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2851 log_stderr("failure: openat");
2855 /* Skip if vfs caps are unsupported. */
2856 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
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");
2866 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
2867 log_stderr("failure: expected_dummy_vfs_caps_uid");
2873 log_stderr("failure: fork");
2877 if (!switch_userns(attr.userns_fd, 0, 0, false))
2878 die("failure: switch_userns");
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.
2887 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
2888 die("failure: expected_dummy_vfs_caps_uid");
2893 if (wait_for_pid(pid))
2896 if (fremovexattr(file1_fd, "security.capability")) {
2897 log_stderr("failure: fremovexattr");
2900 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2901 log_stderr("failure: expected_dummy_vfs_caps_uid");
2904 if (errno != ENODATA) {
2905 log_stderr("failure: errno");
2909 if (set_dummy_vfs_caps(file1_fd, 0, 10000)) {
2910 log_stderr("failure: set_dummy_vfs_caps");
2914 if (!expected_dummy_vfs_caps_uid(file1_fd, 10000)) {
2915 log_stderr("failure: expected_dummy_vfs_caps_uid");
2921 log_stderr("failure: fork");
2925 if (!switch_userns(attr.userns_fd, 0, 0, false))
2926 die("failure: switch_userns");
2928 if (!expected_dummy_vfs_caps_uid(file1_fd, 0))
2929 die("failure: expected_dummy_vfs_caps_uid");
2934 if (wait_for_pid(pid))
2937 if (fremovexattr(file1_fd, "security.capability")) {
2938 log_stderr("failure: fremovexattr");
2941 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2942 log_stderr("failure: expected_dummy_vfs_caps_uid");
2945 if (errno != ENODATA) {
2946 log_stderr("failure: errno");
2951 log_debug("Ran test");
2953 safe_close(attr.userns_fd);
2954 safe_close(file1_fd);
2959 static int fscaps_idmapped_mounts(void)
2962 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
2963 struct mount_attr attr = {
2964 .attr_set = MOUNT_ATTR_IDMAP,
2968 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2970 log_stderr("failure: openat");
2974 /* Skip if vfs caps are unsupported. */
2975 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2978 if (fremovexattr(file1_fd, "security.capability")) {
2979 log_stderr("failure: fremovexattr");
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");
2990 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2993 AT_SYMLINK_NOFOLLOW |
2996 if (open_tree_fd < 0) {
2997 log_stderr("failure: sys_open_tree");
3001 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3002 log_stderr("failure: sys_mount_setattr");
3006 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3007 if (file1_fd2 < 0) {
3008 log_stderr("failure: openat");
3012 if (!set_dummy_vfs_caps(file1_fd2, 0, 1000)) {
3013 log_stderr("failure: set_dummy_vfs_caps");
3017 if (set_dummy_vfs_caps(file1_fd2, 0, 10000)) {
3018 log_stderr("failure: set_dummy_vfs_caps");
3022 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3023 log_stderr("failure: expected_dummy_vfs_caps_uid");
3027 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3028 log_stderr("failure: expected_dummy_vfs_caps_uid");
3034 log_stderr("failure: fork");
3038 if (!switch_userns(attr.userns_fd, 0, 0, false))
3039 die("failure: switch_userns");
3041 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3042 die("failure: expected_dummy_vfs_caps_uid");
3047 if (wait_for_pid(pid))
3050 if (fremovexattr(file1_fd2, "security.capability")) {
3051 log_stderr("failure: fremovexattr");
3054 if (expected_dummy_vfs_caps_uid(file1_fd2, -1)) {
3055 log_stderr("failure: expected_dummy_vfs_caps_uid");
3058 if (errno != ENODATA) {
3059 log_stderr("failure: errno");
3063 if (set_dummy_vfs_caps(file1_fd2, 0, 12000)) {
3064 log_stderr("failure: set_dummy_vfs_caps");
3068 if (!expected_dummy_vfs_caps_uid(file1_fd2, 12000)) {
3069 log_stderr("failure: expected_dummy_vfs_caps_uid");
3073 if (!expected_dummy_vfs_caps_uid(file1_fd, 2000)) {
3074 log_stderr("failure: expected_dummy_vfs_caps_uid");
3080 log_stderr("failure: fork");
3084 if (!switch_userns(attr.userns_fd, 0, 0, false))
3085 die("failure: switch_userns");
3087 if (!expected_dummy_vfs_caps_uid(file1_fd2, 2000))
3088 die("failure: expected_dummy_vfs_caps_uid");
3093 if (wait_for_pid(pid))
3097 log_debug("Ran test");
3099 safe_close(attr.userns_fd);
3100 safe_close(file1_fd);
3101 safe_close(file1_fd2);
3102 safe_close(open_tree_fd);
3107 static int fscaps_idmapped_mounts_in_userns(void)
3110 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3111 struct mount_attr attr = {
3112 .attr_set = MOUNT_ATTR_IDMAP,
3116 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3118 log_stderr("failure: openat");
3122 /* Skip if vfs caps are unsupported. */
3123 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3126 if (fremovexattr(file1_fd, "security.capability")) {
3127 log_stderr("failure: fremovexattr");
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");
3138 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3141 AT_SYMLINK_NOFOLLOW |
3144 if (open_tree_fd < 0) {
3145 log_stderr("failure: sys_open_tree");
3149 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3150 log_stderr("failure: sys_mount_setattr");
3154 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3155 if (file1_fd2 < 0) {
3156 log_stderr("failure: openat");
3162 log_stderr("failure: fork");
3166 if (!switch_userns(attr.userns_fd, 0, 0, false))
3167 die("failure: switch_userns");
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");
3174 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3175 die("failure: set_dummy_vfs_caps");
3177 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3178 die("failure: expected_dummy_vfs_caps_uid");
3180 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
3181 die("failure: expected_dummy_vfs_caps_uid");
3186 if (wait_for_pid(pid))
3189 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
3190 log_stderr("failure: expected_dummy_vfs_caps_uid");
3195 log_debug("Ran test");
3197 safe_close(attr.userns_fd);
3198 safe_close(file1_fd);
3199 safe_close(file1_fd2);
3200 safe_close(open_tree_fd);
3205 static int fscaps_idmapped_mounts_in_userns_separate_userns(void)
3208 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3209 struct mount_attr attr = {
3210 .attr_set = MOUNT_ATTR_IDMAP,
3214 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3216 log_stderr("failure: openat");
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");
3226 if (fremovexattr(file1_fd, "security.capability")) {
3227 log_stderr("failure: fremovexattr");
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");
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");
3244 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3247 AT_SYMLINK_NOFOLLOW |
3250 if (open_tree_fd < 0) {
3251 log_stderr("failure: sys_open_tree");
3255 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3256 log_stderr("failure: sys_mount_setattr");
3260 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3261 if (file1_fd2 < 0) {
3262 log_stderr("failure: openat");
3268 log_stderr("failure: fork");
3274 userns_fd = get_userns_fd(0, 10000, 10000);
3276 die("failure: get_userns_fd");
3278 if (!switch_userns(userns_fd, 0, 0, false))
3279 die("failure: switch_userns");
3281 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3282 die("failure: set fscaps");
3284 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3285 die("failure: expected_dummy_vfs_caps_uid");
3287 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000) && errno != EOVERFLOW)
3288 die("failure: expected_dummy_vfs_caps_uid");
3293 if (wait_for_pid(pid))
3296 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000)) {
3297 log_stderr("failure: expected_dummy_vfs_caps_uid");
3303 log_stderr("failure: fork");
3309 userns_fd = get_userns_fd(0, 10000, 10000);
3311 die("failure: get_userns_fd");
3313 if (!switch_userns(userns_fd, 0, 0, false))
3314 die("failure: switch_userns");
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");
3323 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3324 die("failure: set_dummy_vfs_caps");
3326 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3327 die("failure: expected_dummy_vfs_caps_uid");
3329 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000) && errno != EOVERFLOW)
3330 die("failure: expected_dummy_vfs_caps_uid");
3335 if (wait_for_pid(pid))
3338 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000)) {
3339 log_stderr("failure: expected_dummy_vfs_caps_uid");
3344 log_debug("Ran test");
3346 safe_close(attr.userns_fd);
3347 safe_close(file1_fd);
3348 safe_close(file1_fd2);
3349 safe_close(open_tree_fd);
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.
3358 static void __attribute__((constructor)) setuid_rexec(void)
3360 const char *expected_euid_str, *expected_egid_str, *rexec;
3362 rexec = getenv("IDMAP_MOUNT_TEST_RUN_SETID");
3363 /* This is a regular test-suite run. */
3367 expected_euid_str = getenv("EXPECTED_EUID");
3368 expected_egid_str = getenv("EXPECTED_EGID");
3370 if (expected_euid_str && expected_egid_str) {
3371 uid_t expected_euid;
3372 gid_t expected_egid;
3374 expected_euid = atoi(expected_euid_str);
3375 expected_egid = atoi(expected_egid_str);
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()))
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()))
3388 die("failure: non-setid");
3395 /* Validate that setid transitions are handled correctly. */
3396 static int setid_binaries(void)
3399 int file1_fd = -EBADF, exec_fd = -EBADF;
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);
3405 log_stderr("failure: openat");
3409 /* open our own executable */
3410 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3412 log_stderr("failure: openat");
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");
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");
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");
3434 /* Verify that the sid bits got raised. */
3435 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3436 log_stderr("failure: is_setid");
3440 safe_close(exec_fd);
3441 safe_close(file1_fd);
3443 /* Verify we run setid binary as uid and gid 5000 from the original
3448 log_stderr("failure: fork");
3452 static char *envp[] = {
3453 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3454 "EXPECTED_EUID=5000",
3455 "EXPECTED_EGID=5000",
3458 static char *argv[] = {
3462 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 5000, 5000))
3463 die("failure: expected_uid_gid");
3465 sys_execveat(t_dir1_fd, FILE1, argv, envp, 0);
3466 die("failure: sys_execveat");
3470 if (wait_for_pid(pid))
3474 log_debug("Ran test");
3480 /* Validate that setid transitions are handled correctly on idmapped mounts. */
3481 static int setid_binaries_idmapped_mounts(void)
3484 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3485 struct mount_attr attr = {
3486 .attr_set = MOUNT_ATTR_IDMAP,
3490 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3491 log_stderr("failure: mkdirat");
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);
3498 log_stderr("failure: openat");
3502 /* open our own executable */
3503 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3505 log_stderr("failure:openat ");
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");
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");
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");
3527 /* Verify that the sid bits got raised. */
3528 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3529 log_stderr("failure: is_setid");
3533 safe_close(exec_fd);
3534 safe_close(file1_fd);
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");
3543 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3546 AT_SYMLINK_NOFOLLOW |
3549 if (open_tree_fd < 0) {
3550 log_stderr("failure: sys_open_tree");
3554 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3555 log_stderr("failure: sys_mount_setattr");
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.
3568 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3569 log_stderr("failure: sys_move_mount");
3573 /* Verify we run setid binary as uid and gid 10000 from idmapped mount mount. */
3576 log_stderr("failure: fork");
3580 static char *envp[] = {
3581 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3582 "EXPECTED_EUID=15000",
3583 "EXPECTED_EGID=15000",
3586 static char *argv[] = {
3590 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 15000, 15000))
3591 die("failure: expected_uid_gid");
3593 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3594 die("failure: sys_execveat");
3599 if (wait_for_pid(pid))
3603 log_debug("Ran test");
3605 safe_close(exec_fd);
3606 safe_close(file1_fd);
3607 safe_close(open_tree_fd);
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);
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
3620 static int setid_binaries_idmapped_mounts_in_userns(void)
3623 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3624 struct mount_attr attr = {
3625 .attr_set = MOUNT_ATTR_IDMAP,
3629 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3630 log_stderr("failure: ");
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);
3637 log_stderr("failure: openat");
3641 /* open our own executable */
3642 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3644 log_stderr("failure: openat");
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");
3654 safe_close(exec_fd);
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");
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");
3668 /* Verify that the sid bits got raised. */
3669 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3670 log_stderr("failure: is_setid");
3674 safe_close(file1_fd);
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");
3683 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3686 AT_SYMLINK_NOFOLLOW |
3689 if (open_tree_fd < 0) {
3690 log_stderr("failure: sys_open_tree");
3694 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3695 log_stderr("failure: sys_mount_setattr");
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.
3708 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3709 log_stderr("failure: sys_move_mount");
3715 log_stderr("failure: fork");
3719 static char *envp[] = {
3720 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3721 "EXPECTED_EUID=5000",
3722 "EXPECTED_EGID=5000",
3725 static char *argv[] = {
3729 if (!switch_userns(attr.userns_fd, 0, 0, false))
3730 die("failure: switch_userns");
3732 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
3733 die("failure: expected_uid_gid");
3735 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3736 die("failure: sys_execveat");
3741 if (wait_for_pid(pid)) {
3742 log_stderr("failure: wait_for_pid");
3746 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3748 log_stderr("failure: openat");
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");
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");
3764 /* Verify that the sid bits got raised. */
3765 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3766 log_stderr("failure: is_setid");
3770 safe_close(file1_fd);
3774 log_stderr("failure: fork");
3778 static char *envp[] = {
3779 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3784 static char *argv[] = {
3788 if (!caps_supported()) {
3789 log_debug("skip: capability library not installed");
3793 if (!switch_userns(attr.userns_fd, 5000, 5000, true))
3794 die("failure: switch_userns");
3796 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
3797 die("failure: expected_uid_gid");
3799 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3800 die("failure: sys_execveat");
3805 if (wait_for_pid(pid)) {
3806 log_stderr("failure: wait_for_pid");
3810 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3812 log_stderr("failure: openat");
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");
3822 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
3823 log_stderr("failure: fchmod");
3827 /* Verify that the sid bits got raised. */
3828 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3829 log_stderr("failure: is_setid");
3833 safe_close(file1_fd);
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.
3840 log_stderr("failure: fork");
3844 char expected_euid[100];
3845 char expected_egid[100];
3846 static char *envp[4] = {
3852 static char *argv[] = {
3856 if (!switch_userns(attr.userns_fd, 0, 0, false))
3857 die("failure: switch_userns");
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;
3865 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
3866 die("failure: expected_uid_gid");
3868 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3869 die("failure: sys_execveat");
3874 if (wait_for_pid(pid)) {
3875 log_stderr("failure: wait_for_pid");
3880 log_debug("Ran test");
3882 safe_close(attr.userns_fd);
3883 safe_close(exec_fd);
3884 safe_close(file1_fd);
3885 safe_close(open_tree_fd);
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);
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
3898 static int setid_binaries_idmapped_mounts_in_userns_separate_userns(void)
3901 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3902 struct mount_attr attr = {
3903 .attr_set = MOUNT_ATTR_IDMAP,
3907 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3908 log_stderr("failure: mkdirat");
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);
3915 log_stderr("failure: openat");
3919 /* open our own executable */
3920 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3922 log_stderr("failure: openat");
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");
3932 safe_close(exec_fd);
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");
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");
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");
3952 /* Verify that the sid bits got raised. */
3953 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3954 log_stderr("failure: is_setid");
3958 safe_close(file1_fd);
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");
3967 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3970 AT_SYMLINK_NOFOLLOW |
3973 if (open_tree_fd < 0) {
3974 log_stderr("failure: sys_open_tree");
3978 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3979 log_stderr("failure: sys_mount_setattr");
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.
3992 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3993 log_stderr("failure: sys_move_mount");
3999 log_stderr("failure: fork");
4004 static char *envp[] = {
4005 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4006 "EXPECTED_EUID=5000",
4007 "EXPECTED_EGID=5000",
4010 static char *argv[] = {
4014 userns_fd = get_userns_fd(0, 10000, 10000);
4016 die("failure: get_userns_fd");
4018 if (!switch_userns(userns_fd, 0, 0, false))
4019 die("failure: switch_userns");
4021 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
4022 die("failure: expected_uid_gid");
4024 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4025 die("failure: sys_execveat");
4030 if (wait_for_pid(pid)) {
4031 log_stderr("failure: wait_for_pid");
4035 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4037 log_stderr("failure: openat");
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");
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");
4053 /* Verify that the sid bits got raised. */
4054 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4055 log_stderr("failure: is_setid");
4059 safe_close(file1_fd);
4063 log_stderr("failure: fork");
4068 static char *envp[] = {
4069 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4074 static char *argv[] = {
4078 userns_fd = get_userns_fd(0, 10000, 10000);
4080 die("failure: get_userns_fd");
4082 if (!caps_supported()) {
4083 log_debug("skip: capability library not installed");
4087 if (!switch_userns(userns_fd, 1000, 1000, true))
4088 die("failure: switch_userns");
4090 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
4091 die("failure: expected_uid_gid");
4093 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4094 die("failure: sys_execveat");
4098 if (wait_for_pid(pid)) {
4099 log_stderr("failure: wait_for_pid");
4103 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4105 log_stderr("failure: openat");
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");
4115 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
4116 log_stderr("failure: fchmod");
4120 /* Verify that the sid bits got raised. */
4121 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4122 log_stderr("failure: is_setid");
4126 safe_close(file1_fd);
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.
4133 log_stderr("failure: fork");
4138 char expected_euid[100];
4139 char expected_egid[100];
4140 static char *envp[4] = {
4146 static char *argv[] = {
4150 userns_fd = get_userns_fd(0, 10000, 10000);
4152 die("failure: get_userns_fd");
4154 if (!switch_userns(userns_fd, 0, 0, false))
4155 die("failure: switch_userns");
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;
4163 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4164 die("failure: expected_uid_gid");
4166 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4167 die("failure: sys_execveat");
4171 if (wait_for_pid(pid)) {
4172 log_stderr("failure: wait_for_pid");
4177 log_debug("Ran test");
4179 safe_close(attr.userns_fd);
4180 safe_close(exec_fd);
4181 safe_close(file1_fd);
4182 safe_close(open_tree_fd);
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);
4191 static int sticky_bit_unlink(void)
4194 int dir_fd = -EBADF;
4197 if (!caps_supported())
4200 /* create directory */
4201 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4202 log_stderr("failure: mkdirat");
4206 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4208 log_stderr("failure: openat");
4212 if (fchown(dir_fd, 0, 0)) {
4213 log_stderr("failure: fchown");
4217 if (fchmod(dir_fd, 0777)) {
4218 log_stderr("failure: fchmod");
4222 /* create regular file via mknod */
4223 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4224 log_stderr("failure: mknodat");
4227 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4228 log_stderr("failure: fchownat");
4231 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4232 log_stderr("failure: fchmodat");
4236 /* create regular file via mknod */
4237 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4238 log_stderr("failure: mknodat");
4241 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4242 log_stderr("failure: fchownat");
4245 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4246 log_stderr("failure: fchmodat");
4250 /* The sticky bit is not set so we must be able to delete files not
4255 log_stderr("failure: fork");
4259 if (!switch_ids(1000, 1000))
4260 die("failure: switch_ids");
4262 if (unlinkat(dir_fd, FILE1, 0))
4263 die("failure: unlinkat");
4265 if (unlinkat(dir_fd, FILE2, 0))
4266 die("failure: unlinkat");
4270 if (wait_for_pid(pid)) {
4271 log_stderr("failure: wait_for_pid");
4275 /* set sticky bit */
4276 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4277 log_stderr("failure: fchmod");
4281 /* validate sticky bit is set */
4282 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4283 log_stderr("failure: is_sticky");
4287 /* create regular file via mknod */
4288 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4289 log_stderr("failure: mknodat");
4292 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4293 log_stderr("failure: fchownat");
4296 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4297 log_stderr("failure: fchmodat");
4301 /* create regular file via mknod */
4302 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4303 log_stderr("failure: mknodat");
4306 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4307 log_stderr("failure: fchownat");
4310 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4311 log_stderr("failure: fchmodat");
4315 /* The sticky bit is set so we must not be able to delete files not
4320 log_stderr("failure: fork");
4324 if (!switch_ids(1000, 1000))
4325 die("failure: switch_ids");
4327 if (!unlinkat(dir_fd, FILE1, 0))
4328 die("failure: unlinkat");
4330 die("failure: errno");
4332 if (!unlinkat(dir_fd, FILE2, 0))
4333 die("failure: unlinkat");
4335 die("failure: errno");
4339 if (wait_for_pid(pid)) {
4340 log_stderr("failure: wait_for_pid");
4344 /* The sticky bit is set and we own the files so we must be able to
4345 * delete the files now.
4349 log_stderr("failure: fork");
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");
4363 if (!switch_ids(1000, 1000))
4364 die("failure: switch_ids");
4366 if (unlinkat(dir_fd, FILE1, 0))
4367 die("failure: unlinkat");
4369 if (unlinkat(dir_fd, FILE2, 0))
4370 die("failure: unlinkat");
4374 if (wait_for_pid(pid)) {
4375 log_stderr("failure: wait_for_pid");
4379 /* change uid to unprivileged user */
4380 if (fchown(dir_fd, 1000, -1)) {
4381 log_stderr("failure: fchown");
4384 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4385 log_stderr("failure: fchmod");
4388 /* validate sticky bit is set */
4389 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4390 log_stderr("failure: is_sticky");
4394 /* create regular file via mknod */
4395 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4396 log_stderr("failure: mknodat");
4399 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4400 log_stderr("failure: fchownat");
4403 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4404 log_stderr("failure: fchmodat");
4408 /* create regular file via mknod */
4409 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4410 log_stderr("failure: mknodat");
4413 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4414 log_stderr("failure: fchownat");
4417 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4418 log_stderr("failure: fchmodat");
4422 /* The sticky bit is set and we own the directory so we must be able to
4423 * delete the files now.
4427 log_stderr("failure: fork");
4431 if (!switch_ids(1000, 1000))
4432 die("failure: switch_ids");
4434 if (unlinkat(dir_fd, FILE1, 0))
4435 die("failure: unlinkat");
4437 if (unlinkat(dir_fd, FILE2, 0))
4438 die("failure: unlinkat");
4442 if (wait_for_pid(pid)) {
4443 log_stderr("failure: wait_for_pid");
4448 log_debug("Ran test");
4455 static int sticky_bit_unlink_idmapped_mounts(void)
4458 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4459 struct mount_attr attr = {
4460 .attr_set = MOUNT_ATTR_IDMAP,
4464 if (!caps_supported())
4467 /* create directory */
4468 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4469 log_stderr("failure: mkdirat");
4473 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4475 log_stderr("failure: openat");
4478 if (fchown(dir_fd, 10000, 10000)) {
4479 log_stderr("failure: fchown");
4482 if (fchmod(dir_fd, 0777)) {
4483 log_stderr("failure: fchmod");
4487 /* create regular file via mknod */
4488 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4489 log_stderr("failure: mknodat");
4492 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4493 log_stderr("failure: fchownat");
4496 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4497 log_stderr("failure: fchmodat");
4501 /* create regular file via mknod */
4502 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4503 log_stderr("failure: mknodat");
4506 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4507 log_stderr("failure: fchownat");
4510 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4511 log_stderr("failure: fchmodat");
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");
4522 open_tree_fd = sys_open_tree(dir_fd, "",
4525 AT_SYMLINK_NOFOLLOW |
4528 if (open_tree_fd < 0) {
4529 log_stderr("failure: sys_open_tree");
4533 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4534 log_stderr("failure: sys_mount_setattr");
4538 /* The sticky bit is not set so we must be able to delete files not
4543 log_stderr("failure: fork");
4547 if (!switch_ids(1000, 1000))
4548 die("failure: switch_ids");
4550 if (unlinkat(open_tree_fd, FILE1, 0))
4551 die("failure: unlinkat");
4553 if (unlinkat(open_tree_fd, FILE2, 0))
4554 die("failure: unlinkat");
4558 if (wait_for_pid(pid)) {
4559 log_stderr("failure: wait_for_pid");
4563 /* set sticky bit */
4564 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4565 log_stderr("failure: fchmod");
4569 /* validate sticky bit is set */
4570 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4571 log_stderr("failure: is_sticky");
4575 /* create regular file via mknod */
4576 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4577 log_stderr("failure: mknodat");
4580 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4581 log_stderr("failure: fchownat");
4584 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4585 log_stderr("failure: fchmodat");
4589 /* create regular file via mknod */
4590 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4591 log_stderr("failure: mknodat");
4594 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4595 log_stderr("failure: fchownat");
4598 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4599 log_stderr("failure: fchmodat");
4603 /* The sticky bit is set so we must not be able to delete files not
4608 log_stderr("failure: fork");
4612 if (!switch_ids(1000, 1000))
4613 die("failure: switch_ids");
4615 if (!unlinkat(open_tree_fd, FILE1, 0))
4616 die("failure: unlinkat");
4618 die("failure: errno");
4620 if (!unlinkat(open_tree_fd, FILE2, 0))
4621 die("failure: unlinkat");
4623 die("failure: errno");
4627 if (wait_for_pid(pid)) {
4628 log_stderr("failure: wait_for_pid");
4632 /* The sticky bit is set and we own the files so we must be able to
4633 * delete the files now.
4637 log_stderr("failure: fork");
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");
4651 if (!switch_ids(1000, 1000))
4652 die("failure: switch_ids");
4654 if (unlinkat(open_tree_fd, FILE1, 0))
4655 die("failure: unlinkat");
4657 if (unlinkat(open_tree_fd, FILE2, 0))
4658 die("failure: unlinkat");
4662 if (wait_for_pid(pid)) {
4663 log_stderr("failure: wait_for_pid");
4667 /* change uid to unprivileged user */
4668 if (fchown(dir_fd, 11000, -1)) {
4669 log_stderr("failure: fchown");
4672 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4673 log_stderr("failure: fchmod");
4676 /* validate sticky bit is set */
4677 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4678 log_stderr("failure: is_sticky");
4682 /* create regular file via mknod */
4683 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4684 log_stderr("failure: mknodat");
4687 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4688 log_stderr("failure: fchownat");
4691 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4692 log_stderr("failure: fchmodat");
4696 /* create regular file via mknod */
4697 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4698 log_stderr("failure: mknodat");
4701 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4702 log_stderr("failure: fchownat");
4705 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4706 log_stderr("failure: fchmodat");
4710 /* The sticky bit is set and we own the directory so we must be able to
4711 * delete the files now.
4715 log_stderr("failure: fork");
4719 if (!switch_ids(1000, 1000))
4720 die("failure: switch_ids");
4722 if (unlinkat(open_tree_fd, FILE1, 0))
4723 die("failure: unlinkat");
4725 if (unlinkat(open_tree_fd, FILE2, 0))
4726 die("failure: unlinkat");
4730 if (wait_for_pid(pid)) {
4731 log_stderr("failure: wait_for_pid");
4736 log_debug("Ran test");
4738 safe_close(attr.userns_fd);
4740 safe_close(open_tree_fd);
4745 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
4746 * operations in a user namespace.
4748 static int sticky_bit_unlink_idmapped_mounts_in_userns(void)
4751 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4752 struct mount_attr attr = {
4753 .attr_set = MOUNT_ATTR_IDMAP,
4757 if (!caps_supported())
4760 /* create directory */
4761 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4762 log_stderr("failure: mkdirat");
4766 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4768 log_stderr("failure: openat");
4771 if (fchown(dir_fd, 0, 0)) {
4772 log_stderr("failure: fchown");
4775 if (fchmod(dir_fd, 0777)) {
4776 log_stderr("failure: fchmod");
4780 /* create regular file via mknod */
4781 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4782 log_stderr("failure: mknodat");
4785 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4786 log_stderr("failure: fchownat");
4789 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4790 log_stderr("failure: fchmodat");
4794 /* create regular file via mknod */
4795 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4796 log_stderr("failure: mknodat");
4799 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4800 log_stderr("failure: fchownat");
4803 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4804 log_stderr("failure: fchmodat");
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");
4815 open_tree_fd = sys_open_tree(dir_fd, "",
4818 AT_SYMLINK_NOFOLLOW |
4821 if (open_tree_fd < 0) {
4822 log_stderr("failure: sys_open_tree");
4826 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4827 log_stderr("failure: sys_mount_setattr");
4831 /* The sticky bit is not set so we must be able to delete files not
4836 log_stderr("failure: fork");
4840 if (!caps_supported()) {
4841 log_debug("skip: capability library not installed");
4845 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4846 die("failure: switch_userns");
4848 if (unlinkat(dir_fd, FILE1, 0))
4849 die("failure: unlinkat");
4851 if (unlinkat(dir_fd, FILE2, 0))
4852 die("failure: unlinkat");
4856 if (wait_for_pid(pid)) {
4857 log_stderr("failure: wait_for_pid");
4861 /* set sticky bit */
4862 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4863 log_stderr("failure: fchmod");
4867 /* validate sticky bit is set */
4868 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4869 log_stderr("failure: is_sticky");
4873 /* create regular file via mknod */
4874 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4875 log_stderr("failure: mknodat");
4878 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4879 log_stderr("failure: fchownat");
4882 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4883 log_stderr("failure: fchmodat");
4887 /* create regular file via mknod */
4888 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4889 log_stderr("failure: mknodat");
4892 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4893 log_stderr("failure: fchownat");
4896 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4897 log_stderr("failure: fchmodat");
4901 /* The sticky bit is set so we must not be able to delete files not
4906 log_stderr("failure: fork");
4910 if (!caps_supported()) {
4911 log_debug("skip: capability library not installed");
4915 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4916 die("failure: switch_userns");
4918 if (!unlinkat(dir_fd, FILE1, 0))
4919 die("failure: unlinkat");
4921 die("failure: errno");
4923 if (!unlinkat(dir_fd, FILE2, 0))
4924 die("failure: unlinkat");
4926 die("failure: errno");
4928 if (!unlinkat(open_tree_fd, FILE1, 0))
4929 die("failure: unlinkat");
4931 die("failure: errno");
4933 if (!unlinkat(open_tree_fd, FILE2, 0))
4934 die("failure: unlinkat");
4936 die("failure: errno");
4940 if (wait_for_pid(pid)) {
4941 log_stderr("failure: wait_for_pid");
4945 /* The sticky bit is set and we own the files so we must be able to
4946 * delete the files now.
4950 log_stderr("failure: fork");
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");
4964 if (!caps_supported()) {
4965 log_debug("skip: capability library not installed");
4969 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4970 die("failure: switch_userns");
4972 if (!unlinkat(dir_fd, FILE1, 0))
4973 die("failure: unlinkat");
4975 die("failure: errno");
4977 if (!unlinkat(dir_fd, FILE2, 0))
4978 die("failure: unlinkat");
4980 die("failure: errno");
4982 if (unlinkat(open_tree_fd, FILE1, 0))
4983 die("failure: unlinkat");
4985 if (unlinkat(open_tree_fd, FILE2, 0))
4986 die("failure: unlinkat");
4990 if (wait_for_pid(pid)) {
4991 log_stderr("failure: wait_for_pid");
4995 /* change uid to unprivileged user */
4996 if (fchown(dir_fd, 1000, -1)) {
4997 log_stderr("failure: fchown");
5000 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5001 log_stderr("failure: fchmod");
5004 /* validate sticky bit is set */
5005 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5006 log_stderr("failure: is_sticky");
5010 /* create regular file via mknod */
5011 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5012 log_stderr("failure: mknodat");
5015 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5016 log_stderr("failure: fchownat");
5019 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5020 log_stderr("failure: fchmodat");
5024 /* create regular file via mknod */
5025 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5026 log_stderr("failure: mknodat");
5029 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5030 log_stderr("failure: fchownat");
5033 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5034 log_stderr("failure: fchmodat");
5038 /* The sticky bit is set and we own the directory so we must be able to
5039 * delete the files now.
5043 log_stderr("failure: fork");
5047 if (!caps_supported()) {
5048 log_debug("skip: capability library not installed");
5052 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5053 die("failure: switch_userns");
5055 /* we don't own the directory from the original mount */
5056 if (!unlinkat(dir_fd, FILE1, 0))
5057 die("failure: unlinkat");
5059 die("failure: errno");
5061 if (!unlinkat(dir_fd, FILE2, 0))
5062 die("failure: unlinkat");
5064 die("failure: errno");
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");
5074 if (wait_for_pid(pid)) {
5075 log_stderr("failure: wait_for_pid");
5080 log_debug("Ran test");
5082 safe_close(attr.userns_fd);
5084 safe_close(open_tree_fd);
5089 static int sticky_bit_rename(void)
5092 int dir_fd = -EBADF;
5095 if (!caps_supported())
5098 /* create directory */
5099 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5100 log_stderr("failure: mkdirat");
5104 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5106 log_stderr("failure: openat");
5109 if (fchown(dir_fd, 0, 0)) {
5110 log_stderr("failure: fchown");
5113 if (fchmod(dir_fd, 0777)) {
5114 log_stderr("failure: fchmod");
5118 /* create regular file via mknod */
5119 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5120 log_stderr("failure: mknodat");
5123 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5124 log_stderr("failure: fchownat");
5127 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5128 log_stderr("failure: fchmodat");
5132 /* create regular file via mknod */
5133 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5134 log_stderr("failure: mknodat");
5137 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5138 log_stderr("failure: fchownat");
5141 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5142 log_stderr("failure: fchmodat");
5146 /* The sticky bit is not set so we must be able to delete files not
5151 log_stderr("failure: fork");
5155 if (!switch_ids(1000, 1000))
5156 die("failure: switch_ids");
5158 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5159 die("failure: renameat");
5161 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5162 die("failure: renameat");
5164 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5165 die("failure: renameat");
5167 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5168 die("failure: renameat");
5172 if (wait_for_pid(pid)) {
5173 log_stderr("failure: wait_for_pid");
5177 /* set sticky bit */
5178 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5179 log_stderr("failure: fchmod");
5183 /* validate sticky bit is set */
5184 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5185 log_stderr("failure: is_sticky");
5189 /* The sticky bit is set so we must not be able to delete files not
5194 log_stderr("failure: fork");
5198 if (!switch_ids(1000, 1000))
5199 die("failure: switch_ids");
5201 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5202 die("failure: renameat");
5204 die("failure: errno");
5206 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5207 die("failure: renameat");
5209 die("failure: errno");
5213 if (wait_for_pid(pid)) {
5214 log_stderr("failure: wait_for_pid");
5218 /* The sticky bit is set and we own the files so we must be able to
5219 * delete the files now.
5223 log_stderr("failure: fork");
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");
5237 if (!switch_ids(1000, 1000))
5238 die("failure: switch_ids");
5240 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5241 die("failure: renameat");
5243 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5244 die("failure: renameat");
5246 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5247 die("failure: renameat");
5249 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5250 die("failure: renameat");
5254 if (wait_for_pid(pid)) {
5255 log_stderr("failure: wait_for_pid");
5259 /* change uid to unprivileged user */
5260 if (fchown(dir_fd, 1000, -1)) {
5261 log_stderr("failure: fchown");
5264 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5265 log_stderr("failure: fchmod");
5268 /* validate sticky bit is set */
5269 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5270 log_stderr("failure: is_sticky");
5275 /* The sticky bit is set and we own the directory so we must be able to
5276 * delete the files now.
5280 log_stderr("failure: fork");
5284 if (!switch_ids(1000, 1000))
5285 die("failure: switch_ids");
5287 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5288 die("failure: renameat");
5290 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5291 die("failure: renameat");
5293 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5294 die("failure: renameat");
5296 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5297 die("failure: renameat");
5301 if (wait_for_pid(pid)) {
5302 log_stderr("failure: wait_for_pid");
5307 log_debug("Ran test");
5314 static int sticky_bit_rename_idmapped_mounts(void)
5317 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5318 struct mount_attr attr = {
5319 .attr_set = MOUNT_ATTR_IDMAP,
5323 if (!caps_supported())
5326 /* create directory */
5327 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5328 log_stderr("failure: mkdirat");
5332 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5334 log_stderr("failure: openat");
5338 if (fchown(dir_fd, 10000, 10000)) {
5339 log_stderr("failure: fchown");
5343 if (fchmod(dir_fd, 0777)) {
5344 log_stderr("failure: fchmod");
5348 /* create regular file via mknod */
5349 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5350 log_stderr("failure: mknodat");
5353 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
5354 log_stderr("failure: fchownat");
5357 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5358 log_stderr("failure: fchmodat");
5362 /* create regular file via mknod */
5363 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5364 log_stderr("failure: mknodat");
5367 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
5368 log_stderr("failure: fchownat");
5371 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5372 log_stderr("failure: fchmodat");
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");
5383 open_tree_fd = sys_open_tree(dir_fd, "",
5386 AT_SYMLINK_NOFOLLOW |
5389 if (open_tree_fd < 0) {
5390 log_stderr("failure: sys_open_tree");
5394 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5395 log_stderr("failure: sys_mount_setattr");
5399 /* The sticky bit is not set so we must be able to delete files not
5404 log_stderr("failure: fork");
5408 if (!switch_ids(1000, 1000))
5409 die("failure: switch_ids");
5411 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5412 die("failure: renameat");
5414 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5415 die("failure: renameat");
5417 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5418 die("failure: renameat");
5420 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5421 die("failure: renameat");
5425 if (wait_for_pid(pid)) {
5426 log_stderr("failure: wait_for_pid");
5430 /* set sticky bit */
5431 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5432 log_stderr("failure: fchmod");
5436 /* validate sticky bit is set */
5437 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5438 log_stderr("failure: is_sticky");
5442 /* The sticky bit is set so we must not be able to delete files not
5447 log_stderr("failure: fork");
5451 if (!switch_ids(1000, 1000))
5452 die("failure: switch_ids");
5454 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5455 die("failure: renameat");
5457 die("failure: errno");
5459 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5460 die("failure: renameat");
5462 die("failure: errno");
5466 if (wait_for_pid(pid)) {
5467 log_stderr("failure: wait_for_pid");
5471 /* The sticky bit is set and we own the files so we must be able to
5472 * delete the files now.
5476 log_stderr("failure: fork");
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");
5490 if (!switch_ids(1000, 1000))
5491 die("failure: switch_ids");
5493 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5494 die("failure: renameat");
5496 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5497 die("failure: renameat");
5499 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5500 die("failure: renameat");
5502 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5503 die("failure: renameat");
5507 if (wait_for_pid(pid)) {
5508 log_stderr("failure: wait_for_pid");
5512 /* change uid to unprivileged user */
5513 if (fchown(dir_fd, 11000, -1)) {
5514 log_stderr("failure: fchown");
5517 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5518 log_stderr("failure: fchmod");
5521 /* validate sticky bit is set */
5522 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5523 log_stderr("failure: is_sticky");
5527 /* The sticky bit is set and we own the directory so we must be able to
5528 * delete the files now.
5532 log_stderr("failure: fork");
5536 if (!switch_ids(1000, 1000))
5537 die("failure: switch_ids");
5539 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5540 die("failure: renameat");
5542 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5543 die("failure: renameat");
5545 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5546 die("failure: renameat");
5548 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5549 die("failure: renameat");
5553 if (wait_for_pid(pid)) {
5554 log_stderr("failure: wait_for_pid");
5559 log_debug("Ran test");
5561 safe_close(attr.userns_fd);
5563 safe_close(open_tree_fd);
5568 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
5569 * operations in a user namespace.
5571 static int sticky_bit_rename_idmapped_mounts_in_userns(void)
5574 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5575 struct mount_attr attr = {
5576 .attr_set = MOUNT_ATTR_IDMAP,
5580 if (!caps_supported())
5583 /* create directory */
5584 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5585 log_stderr("failure: mkdirat");
5589 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5591 log_stderr("failure: openat");
5594 if (fchown(dir_fd, 0, 0)) {
5595 log_stderr("failure: fchown");
5598 if (fchmod(dir_fd, 0777)) {
5599 log_stderr("failure: fchmod");
5603 /* create regular file via mknod */
5604 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5605 log_stderr("failure: mknodat");
5608 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5609 log_stderr("failure: fchownat");
5612 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5613 log_stderr("failure: fchmodat");
5617 /* create regular file via mknod */
5618 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5619 log_stderr("failure: mknodat");
5622 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5623 log_stderr("failure: fchownat");
5626 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5627 log_stderr("failure: fchmodat");
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");
5638 open_tree_fd = sys_open_tree(dir_fd, "",
5641 AT_SYMLINK_NOFOLLOW |
5644 if (open_tree_fd < 0) {
5645 log_stderr("failure: sys_open_tree");
5649 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5650 log_stderr("failure: sys_mount_setattr");
5654 /* The sticky bit is not set so we must be able to delete files not
5659 log_stderr("failure: fork");
5663 if (!caps_supported()) {
5664 log_debug("skip: capability library not installed");
5668 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5669 die("failure: switch_userns");
5671 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5672 die("failure: renameat");
5674 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5675 die("failure: renameat");
5677 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5678 die("failure: renameat");
5680 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5681 die("failure: renameat");
5685 if (wait_for_pid(pid)) {
5686 log_stderr("failure: wait_for_pid");
5690 /* set sticky bit */
5691 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5692 log_stderr("failure: fchmod");
5696 /* validate sticky bit is set */
5697 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5698 log_stderr("failure: is_sticky");
5702 /* The sticky bit is set so we must not be able to delete files not
5707 log_stderr("failure: fork");
5711 if (!caps_supported()) {
5712 log_debug("skip: capability library not installed");
5716 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5717 die("failure: switch_userns");
5719 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5720 die("failure: renameat");
5722 die("failure: errno");
5724 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5725 die("failure: renameat");
5727 die("failure: errno");
5729 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5730 die("failure: renameat");
5732 die("failure: errno");
5734 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5735 die("failure: renameat");
5737 die("failure: errno");
5741 if (wait_for_pid(pid)) {
5742 log_stderr("failure: wait_for_pid");
5746 /* The sticky bit is set and we own the files so we must be able to
5747 * delete the files now.
5751 log_stderr("failure: fork");
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");
5765 if (!caps_supported()) {
5766 log_debug("skip: capability library not installed");
5770 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5771 die("failure: switch_userns");
5773 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5774 die("failure: renameat");
5776 die("failure: errno");
5778 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5779 die("failure: renameat");
5781 die("failure: errno");
5783 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5784 die("failure: renameat");
5786 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5787 die("failure: renameat");
5789 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5790 die("failure: renameat");
5792 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5793 die("failure: renameat");
5797 if (wait_for_pid(pid)) {
5798 log_stderr("failure: wait_for_pid");
5802 /* change uid to unprivileged user */
5803 if (fchown(dir_fd, 1000, -1)) {
5804 log_stderr("failure: fchown");
5807 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5808 log_stderr("failure: fchmod");
5811 /* validate sticky bit is set */
5812 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5813 log_stderr("failure: is_sticky");
5817 /* The sticky bit is set and we own the directory so we must be able to
5818 * delete the files now.
5822 log_stderr("failure: fork");
5826 if (!caps_supported()) {
5827 log_debug("skip: capability library not installed");
5831 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5832 die("failure: switch_userns");
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");
5838 die("failure: errno");
5840 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5841 die("failure: renameat");
5843 die("failure: errno");
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");
5849 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5850 die("failure: renameat");
5852 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5853 die("failure: renameat");
5855 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5856 die("failure: renameat");
5860 if (wait_for_pid(pid)) {
5861 log_stderr("failure: wait_for_pid");
5866 log_debug("Ran test");
5868 safe_close(open_tree_fd);
5869 safe_close(attr.userns_fd);
5875 /* Validate that protected symlinks work correctly. */
5876 static int protected_symlinks(void)
5879 int dir_fd = -EBADF, fd = -EBADF;
5882 if (!protected_symlinks_enabled())
5885 if (!caps_supported())
5888 /* create directory */
5889 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5890 log_stderr("failure: mkdirat");
5894 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5896 log_stderr("failure: openat");
5899 if (fchown(dir_fd, 0, 0)) {
5900 log_stderr("failure: fchown");
5903 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5904 log_stderr("failure: fchmod");
5907 /* validate sticky bit is set */
5908 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5909 log_stderr("failure: is_sticky");
5913 /* create regular file via mknod */
5914 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5915 log_stderr("failure: mknodat");
5918 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5919 log_stderr("failure: fchownat");
5922 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5923 log_stderr("failure: fchmodat");
5927 /* create symlinks */
5928 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
5929 log_stderr("failure: symlinkat");
5932 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
5933 log_stderr("failure: fchownat");
5936 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
5937 log_stderr("failure: expected_uid_gid");
5940 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5941 log_stderr("failure: expected_uid_gid");
5945 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
5946 log_stderr("failure: symlinkat");
5949 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
5950 log_stderr("failure: fchownat");
5953 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
5954 log_stderr("failure: expected_uid_gid");
5957 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5958 log_stderr("failure: expected_uid_gid");
5962 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
5963 log_stderr("failure: symlinkat");
5966 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
5967 log_stderr("failure: fchownat");
5970 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
5971 log_stderr("failure: expected_uid_gid");
5974 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5975 log_stderr("failure: expected_uid_gid");
5979 /* validate file can be directly read */
5980 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
5982 log_stderr("failure: openat");
5987 /* validate file can be read through own symlink */
5988 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
5990 log_stderr("failure: openat");
5997 log_stderr("failure: fork");
6001 if (!switch_ids(1000, 1000))
6002 die("failure: switch_ids");
6004 /* validate file can be directly read */
6005 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6007 die("failure: openat");
6010 /* validate file can be read through own symlink */
6011 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6013 die("failure: openat");
6016 /* validate file can be read through root symlink */
6017 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6019 die("failure: openat");
6022 /* validate file can't be read through other users symlink */
6023 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6025 die("failure: openat");
6026 if (errno != EACCES)
6027 die("failure: errno");
6031 if (wait_for_pid(pid)) {
6032 log_stderr("failure: wait_for_pid");
6038 log_stderr("failure: fork");
6042 if (!switch_ids(2000, 2000))
6043 die("failure: switch_ids");
6045 /* validate file can be directly read */
6046 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6048 die("failure: openat");
6051 /* validate file can be read through own symlink */
6052 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6054 die("failure: openat");
6057 /* validate file can be read through root symlink */
6058 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6060 die("failure: openat");
6063 /* validate file can't be read through other users symlink */
6064 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6066 die("failure: openat");
6067 if (errno != EACCES)
6068 die("failure: errno");
6072 if (wait_for_pid(pid)) {
6073 log_stderr("failure: wait_for_pid");
6078 log_debug("Ran test");
6086 /* Validate that protected symlinks work correctly on idmapped mounts. */
6087 static int protected_symlinks_idmapped_mounts(void)
6090 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6091 struct mount_attr attr = {
6092 .attr_set = MOUNT_ATTR_IDMAP,
6096 if (!protected_symlinks_enabled())
6099 if (!caps_supported())
6102 /* create directory */
6103 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6104 log_stderr("failure: mkdirat");
6108 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6110 log_stderr("failure: openat");
6113 if (fchown(dir_fd, 10000, 10000)) {
6114 log_stderr("failure: fchown");
6117 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6118 log_stderr("failure: fchmod");
6121 /* validate sticky bit is set */
6122 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6123 log_stderr("failure: is_sticky");
6127 /* create regular file via mknod */
6128 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6129 log_stderr("failure: mknodat");
6132 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
6133 log_stderr("failure: fchownat");
6136 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6137 log_stderr("failure: fchmodat");
6141 /* create symlinks */
6142 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6143 log_stderr("failure: symlinkat");
6146 if (fchownat(dir_fd, SYMLINK_USER1, 10000, 10000, AT_SYMLINK_NOFOLLOW)) {
6147 log_stderr("failure: fchownat");
6150 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
6151 log_stderr("failure: expected_uid_gid");
6154 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6155 log_stderr("failure: expected_uid_gid");
6159 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6160 log_stderr("failure: symlinkat");
6163 if (fchownat(dir_fd, SYMLINK_USER2, 11000, 11000, AT_SYMLINK_NOFOLLOW)) {
6164 log_stderr("failure: fchownat");
6167 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 11000, 11000)) {
6168 log_stderr("failure: expected_uid_gid");
6171 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6172 log_stderr("failure: expected_uid_gid");
6176 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6177 log_stderr("failure: symlinkat");
6180 if (fchownat(dir_fd, SYMLINK_USER3, 12000, 12000, AT_SYMLINK_NOFOLLOW)) {
6181 log_stderr("failure: fchownat");
6184 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
6185 log_stderr("failure: expected_uid_gid");
6188 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6189 log_stderr("failure: expected_uid_gid");
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");
6200 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6203 AT_SYMLINK_NOFOLLOW |
6206 if (open_tree_fd < 0) {
6207 log_stderr("failure: open_tree_fd");
6211 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6212 log_stderr("failure: sys_mount_setattr");
6216 /* validate file can be directly read */
6217 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6219 log_stderr("failure: openat");
6224 /* validate file can be read through own symlink */
6225 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6227 log_stderr("failure: openat");
6234 log_stderr("failure: fork");
6238 if (!switch_ids(1000, 1000))
6239 die("failure: switch_ids");
6241 /* validate file can be directly read */
6242 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6244 die("failure: openat");
6247 /* validate file can be read through own symlink */
6248 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6250 die("failure: openat");
6253 /* validate file can be read through root symlink */
6254 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6256 die("failure: openat");
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);
6262 die("failure: openat");
6263 if (errno != EACCES)
6264 die("failure: errno");
6268 if (wait_for_pid(pid)) {
6269 log_stderr("failure: wait_for_pid");
6275 log_stderr("failure: fork");
6279 if (!switch_ids(2000, 2000))
6280 die("failure: switch_ids");
6282 /* validate file can be directly read */
6283 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6285 die("failure: openat");
6288 /* validate file can be read through own symlink */
6289 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6291 die("failure: openat");
6294 /* validate file can be read through root symlink */
6295 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6297 die("failure: openat");
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);
6303 die("failure: openat");
6304 if (errno != EACCES)
6305 die("failure: errno");
6309 if (wait_for_pid(pid)) {
6310 log_stderr("failure: wait_for_pid");
6315 log_debug("Ran test");
6317 safe_close(attr.userns_fd);
6320 safe_close(open_tree_fd);
6325 /* Validate that protected symlinks work correctly on idmapped mounts inside a
6328 static int protected_symlinks_idmapped_mounts_in_userns(void)
6331 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6332 struct mount_attr attr = {
6333 .attr_set = MOUNT_ATTR_IDMAP,
6337 if (!protected_symlinks_enabled())
6340 if (!caps_supported())
6343 /* create directory */
6344 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6345 log_stderr("failure: mkdirat");
6349 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6351 log_stderr("failure: openat");
6354 if (fchown(dir_fd, 0, 0)) {
6355 log_stderr("failure: fchown");
6358 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6359 log_stderr("failure: fchmod");
6362 /* validate sticky bit is set */
6363 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6364 log_stderr("failure: is_sticky");
6368 /* create regular file via mknod */
6369 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6370 log_stderr("failure: mknodat");
6373 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6374 log_stderr("failure: fchownat");
6377 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6378 log_stderr("failure: fchmodat");
6382 /* create symlinks */
6383 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6384 log_stderr("failure: symlinkat");
6387 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6388 log_stderr("failure: fchownat");
6391 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6392 log_stderr("failure: expected_uid_gid");
6395 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6396 log_stderr("failure: expected_uid_gid");
6400 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6401 log_stderr("failure: symlinkat");
6404 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6405 log_stderr("failure: fchownat");
6408 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6409 log_stderr("failure: expected_uid_gid");
6412 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6413 log_stderr("failure: expected_uid_gid");
6417 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6418 log_stderr("failure: symlinkat");
6421 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6422 log_stderr("failure: fchownat");
6425 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6426 log_stderr("failure: expected_uid_gid");
6429 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6430 log_stderr("failure: expected_uid_gid");
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");
6441 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6444 AT_SYMLINK_NOFOLLOW |
6447 if (open_tree_fd < 0) {
6448 log_stderr("failure: sys_open_tree");
6452 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6453 log_stderr("failure: sys_mount_setattr");
6457 /* validate file can be directly read */
6458 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6460 log_stderr("failure: openat");
6465 /* validate file can be read through own symlink */
6466 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6468 log_stderr("failure: openat");
6475 log_stderr("failure: fork");
6479 if (!caps_supported()) {
6480 log_debug("skip: capability library not installed");
6484 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
6485 die("failure: switch_userns");
6487 /* validate file can be directly read */
6488 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6490 die("failure: openat");
6493 /* validate file can be read through own symlink */
6494 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6496 die("failure: openat");
6499 /* validate file can be read through root symlink */
6500 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6502 die("failure: openat");
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);
6508 die("failure: openat");
6509 if (errno != EACCES)
6510 die("failure: errno");
6514 if (wait_for_pid(pid)) {
6515 log_stderr("failure: wait_for_pid");
6521 log_stderr("failure: fork");
6525 if (!caps_supported()) {
6526 log_debug("skip: capability library not installed");
6530 if (!switch_userns(attr.userns_fd, 2000, 2000, true))
6531 die("failure: switch_userns");
6533 /* validate file can be directly read */
6534 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6536 die("failure: openat");
6539 /* validate file can be read through own symlink */
6540 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6542 die("failure: openat");
6545 /* validate file can be read through root symlink */
6546 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6548 die("failure: openat");
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);
6554 die("failure: openat");
6555 if (errno != EACCES)
6556 die("failure: errno");
6560 if (wait_for_pid(pid)) {
6561 log_stderr("failure: wait_for_pid");
6566 log_debug("Ran test");
6569 safe_close(open_tree_fd);
6570 safe_close(attr.userns_fd);
6575 static int acls(void)
6578 int dir1_fd = -EBADF, open_tree_fd = -EBADF;
6579 struct mount_attr attr = {
6580 .attr_set = MOUNT_ATTR_IDMAP,
6584 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
6585 log_stderr("failure: mkdirat");
6588 if (fchmodat(t_dir1_fd, DIR1, 0777, 0)) {
6589 log_stderr("failure: fchmodat");
6593 if (mkdirat(t_dir1_fd, DIR2, 0777)) {
6594 log_stderr("failure: mkdirat");
6597 if (fchmodat(t_dir1_fd, DIR2, 0777, 0)) {
6598 log_stderr("failure: fchmodat");
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");
6609 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
6611 AT_SYMLINK_NOFOLLOW |
6614 if (open_tree_fd < 0) {
6615 log_stderr("failure: sys_open_tree");
6619 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6620 log_stderr("failure: sys_mount_setattr");
6624 if (sys_move_mount(open_tree_fd, "", t_dir1_fd, DIR2, MOVE_MOUNT_F_EMPTY_PATH)) {
6625 log_stderr("failure: sys_move_mount");
6629 dir1_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6631 log_stderr("failure: openat");
6635 if (mkdirat(dir1_fd, DIR3, 0000)) {
6636 log_stderr("failure: mkdirat");
6639 if (fchown(dir1_fd, 100010, 100010)) {
6640 log_stderr("failure: fchown");
6643 if (fchmod(dir1_fd, 0777)) {
6644 log_stderr("failure: fchmod");
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");
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");
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");
6668 log_stderr("failure: fork");
6672 if (!caps_supported()) {
6673 log_debug("skip: capability library not installed");
6677 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6678 die("failure: switch_userns");
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);
6683 die("failure: system");
6687 if (wait_for_pid(pid)) {
6688 log_stderr("failure: wait_for_pid");
6694 log_stderr("failure: fork");
6698 if (!caps_supported()) {
6699 log_debug("skip: capability library not installed");
6703 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6704 die("failure: switch_userns");
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);
6709 die("failure: system");
6713 if (wait_for_pid(pid)) {
6714 log_stderr("failure: wait_for_pid");
6718 /* Now, dir is owned by someone else in the user namespace, but we can
6719 * still read it because of acls.
6721 if (fchown(dir1_fd, 100012, 100012)) {
6722 log_stderr("failure: fchown");
6728 log_stderr("failure: fork");
6734 if (!caps_supported()) {
6735 log_debug("skip: capability library not installed");
6739 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6740 die("failure: switch_userns");
6742 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6744 die("failure: openat");
6748 if (wait_for_pid(pid)) {
6749 log_stderr("failure: wait_for_pid");
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");
6762 log_stderr("failure: fork");
6768 if (!caps_supported()) {
6769 log_debug("skip: capability library not installed");
6773 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6774 die("failure: switch_userns");
6776 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6778 die("failure: openat");
6782 if (wait_for_pid(pid)) {
6783 log_stderr("failure: wait_for_pid");
6787 snprintf(t_buf, sizeof(t_buf), "%s/" T_DIR1 "/" DIR2, t_mountpoint);
6788 sys_umount2(t_buf, MNT_DETACH);
6791 log_debug("Ran test");
6793 safe_close(attr.userns_fd);
6794 safe_close(dir1_fd);
6795 safe_close(open_tree_fd);
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)
6804 struct io_uring_cqe *cqe;
6805 struct io_uring_sqe *sqe;
6806 int ret, i, to_submit = 1;
6809 sqe = io_uring_get_sqe(ring);
6811 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6812 io_uring_prep_nop(sqe);
6813 sqe->flags |= IOSQE_IO_LINK;
6818 sqe = io_uring_get_sqe(ring);
6820 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6821 io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0);
6825 sqe->personality = cred_id;
6827 ret = io_uring_submit(ring);
6828 if (ret != to_submit) {
6829 log_stderr("failure: io_uring_submit");
6833 for (i = 0; i < to_submit; i++) {
6834 ret = io_uring_wait_cqe(ring, &cqe);
6836 log_stderr("failure: io_uring_wait_cqe");
6842 * Make sure caller can identify that this is a proper io_uring
6843 * failure and not some earlier error.
6847 io_uring_cqe_seen(ring, cqe);
6849 log_debug("Ran test");
6854 static int io_uring(void)
6857 int file1_fd = -EBADF;
6858 struct io_uring *ring;
6859 int cred_id, ret, ret_cqe;
6862 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6863 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6865 return log_errno(-1, "failure: io_uring_queue_init");
6867 ret = io_uring_queue_init(8, ring, 0);
6869 log_stderr("failure: io_uring_queue_init");
6873 ret = io_uring_register_personality(ring);
6876 goto out_unmap; /* personalities not supported */
6880 /* create file only owner can open */
6881 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
6883 log_stderr("failure: openat");
6886 if (fchown(file1_fd, 0, 0)) {
6887 log_stderr("failure: fchown");
6890 if (fchmod(file1_fd, 0600)) {
6891 log_stderr("failure: fchmod");
6894 safe_close(file1_fd);
6898 log_stderr("failure: fork");
6902 /* Verify we can open it with our current credentials. */
6903 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6906 die("failure: io_uring_open_file");
6910 if (wait_for_pid(pid)) {
6911 log_stderr("failure: wait_for_pid");
6917 log_stderr("failure: fork");
6921 if (!switch_ids(1000, 1000))
6922 die("failure: switch_ids");
6924 /* Verify we can't open it with our current credentials. */
6926 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6927 -1, false, &ret_cqe);
6929 die("failure: io_uring_open_file");
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));
6937 if (wait_for_pid(pid)) {
6938 log_stderr("failure: wait_for_pid");
6944 log_stderr("failure: fork");
6948 if (!switch_ids(1000, 1000))
6949 die("failure: switch_ids");
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);
6955 die("failure: io_uring_open_file");
6957 /* Verify we can open it with the registered credentials and as
6960 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6961 cred_id, true, NULL);
6963 die("failure: io_uring_open_file");
6967 if (wait_for_pid(pid)) {
6968 log_stderr("failure: wait_for_pid");
6973 log_debug("Ran test");
6975 ret = io_uring_unregister_personality(ring, cred_id);
6977 log_stderr("failure: io_uring_unregister_personality");
6980 munmap(ring, sizeof(struct io_uring));
6982 safe_close(file1_fd);
6987 static int io_uring_userns(void)
6990 int file1_fd = -EBADF, userns_fd = -EBADF;
6991 struct io_uring *ring;
6992 int cred_id, ret, ret_cqe;
6995 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6996 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6998 return log_errno(-1, "failure: io_uring_queue_init");
7000 ret = io_uring_queue_init(8, ring, 0);
7002 log_stderr("failure: io_uring_queue_init");
7006 ret = io_uring_register_personality(ring);
7009 goto out_unmap; /* personalities not supported */
7013 /* create file only owner can open */
7014 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7016 log_stderr("failure: openat");
7019 if (fchown(file1_fd, 0, 0)) {
7020 log_stderr("failure: fchown");
7023 if (fchmod(file1_fd, 0600)) {
7024 log_stderr("failure: fchmod");
7027 safe_close(file1_fd);
7029 userns_fd = get_userns_fd(0, 10000, 10000);
7030 if (userns_fd < 0) {
7031 log_stderr("failure: get_userns_fd");
7037 log_stderr("failure: fork");
7041 /* Verify we can open it with our current credentials. */
7042 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7045 die("failure: io_uring_open_file");
7049 if (wait_for_pid(pid)) {
7050 log_stderr("failure: wait_for_pid");
7056 log_stderr("failure: fork");
7060 if (!switch_userns(userns_fd, 0, 0, false))
7061 die("failure: switch_userns");
7063 /* Verify we can't open it with our current credentials. */
7065 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7066 -1, false, &ret_cqe);
7068 die("failure: io_uring_open_file");
7070 die("failure: non-open() related io_uring_open_file failure");
7071 if (ret_cqe != -EACCES)
7072 die("failure: errno(%d)", abs(ret_cqe));
7076 if (wait_for_pid(pid)) {
7077 log_stderr("failure: wait_for_pid");
7083 log_stderr("failure: fork");
7087 if (!switch_userns(userns_fd, 0, 0, false))
7088 die("failure: switch_userns");
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);
7094 die("failure: io_uring_open_file");
7096 /* Verify we can open it with the registered credentials and as
7099 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7100 cred_id, true, NULL);
7102 die("failure: io_uring_open_file");
7106 if (wait_for_pid(pid)) {
7107 log_stderr("failure: wait_for_pid");
7112 log_debug("Ran test");
7114 ret = io_uring_unregister_personality(ring, cred_id);
7116 log_stderr("failure: io_uring_unregister_personality");
7119 munmap(ring, sizeof(struct io_uring));
7121 safe_close(file1_fd);
7122 safe_close(userns_fd);
7127 static int io_uring_idmapped(void)
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,
7138 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7139 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7141 return log_errno(-1, "failure: io_uring_queue_init");
7143 ret = io_uring_queue_init(8, ring, 0);
7145 log_stderr("failure: io_uring_queue_init");
7149 ret = io_uring_register_personality(ring);
7152 goto out_unmap; /* personalities not supported */
7156 /* create file only owner can open */
7157 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7159 log_stderr("failure: openat");
7162 if (fchown(file1_fd, 0, 0)) {
7163 log_stderr("failure: fchown");
7166 if (fchmod(file1_fd, 0600)) {
7167 log_stderr("failure: fchmod");
7170 safe_close(file1_fd);
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");
7177 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7180 AT_SYMLINK_NOFOLLOW |
7183 if (open_tree_fd < 0)
7184 return log_errno(-1, "failure: create detached mount");
7186 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7187 return log_errno(-1, "failure: set mount attributes");
7191 log_stderr("failure: fork");
7195 if (!switch_ids(10000, 10000))
7196 die("failure: switch_ids");
7198 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7201 die("failure: io_uring_open_file");
7205 if (wait_for_pid(pid)) {
7206 log_stderr("failure: wait_for_pid");
7212 log_stderr("failure: fork");
7216 if (!switch_ids(10001, 10001))
7217 die("failure: switch_ids");
7219 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7220 cred_id, false, NULL);
7222 die("failure: io_uring_open_file");
7224 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7225 cred_id, true, NULL);
7227 die("failure: io_uring_open_file");
7231 if (wait_for_pid(pid)) {
7232 log_stderr("failure: wait_for_pid");
7237 log_debug("Ran test");
7239 ret = io_uring_unregister_personality(ring, cred_id);
7241 log_stderr("failure: io_uring_unregister_personality");
7244 munmap(ring, sizeof(struct io_uring));
7246 safe_close(attr.userns_fd);
7247 safe_close(file1_fd);
7248 safe_close(open_tree_fd);
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
7258 static int io_uring_idmapped_unmapped(void)
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,
7266 int cred_id, ret, ret_cqe;
7269 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7270 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7272 return log_errno(-1, "failure: io_uring_queue_init");
7274 ret = io_uring_queue_init(8, ring, 0);
7276 log_stderr("failure: io_uring_queue_init");
7280 ret = io_uring_register_personality(ring);
7283 goto out_unmap; /* personalities not supported */
7287 /* create file only owner can open */
7288 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7290 log_stderr("failure: openat");
7293 if (fchown(file1_fd, 0, 0)) {
7294 log_stderr("failure: fchown");
7297 if (fchmod(file1_fd, 0600)) {
7298 log_stderr("failure: fchmod");
7301 safe_close(file1_fd);
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");
7308 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7311 AT_SYMLINK_NOFOLLOW |
7314 if (open_tree_fd < 0)
7315 return log_errno(-1, "failure: create detached mount");
7317 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7318 return log_errno(-1, "failure: set mount attributes");
7322 log_stderr("failure: fork");
7326 if (!switch_ids(10000, 10000))
7327 die("failure: switch_ids");
7330 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7331 cred_id, false, &ret_cqe);
7333 die("failure: io_uring_open_file");
7335 die("failure: non-open() related io_uring_open_file failure");
7336 if (ret_cqe != -EACCES)
7337 die("failure: errno(%d)", abs(ret_cqe));
7340 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7341 cred_id, true, &ret_cqe);
7343 die("failure: io_uring_open_file");
7345 die("failure: non-open() related io_uring_open_file failure");
7346 if (ret_cqe != -EACCES)
7347 die("failure: errno(%d)", abs(ret_cqe));
7351 if (wait_for_pid(pid)) {
7352 log_stderr("failure: wait_for_pid");
7357 log_debug("Ran test");
7359 ret = io_uring_unregister_personality(ring, cred_id);
7361 log_stderr("failure: io_uring_unregister_personality");
7364 munmap(ring, sizeof(struct io_uring));
7366 safe_close(attr.userns_fd);
7367 safe_close(file1_fd);
7368 safe_close(open_tree_fd);
7373 static int io_uring_idmapped_userns(void)
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,
7381 int cred_id, ret, ret_cqe;
7384 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7385 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7387 return log_errno(-1, "failure: io_uring_queue_init");
7389 ret = io_uring_queue_init(8, ring, 0);
7391 log_stderr("failure: io_uring_queue_init");
7395 ret = io_uring_register_personality(ring);
7398 goto out_unmap; /* personalities not supported */
7402 /* create file only owner can open */
7403 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7405 log_stderr("failure: openat");
7408 if (fchown(file1_fd, 0, 0)) {
7409 log_stderr("failure: fchown");
7412 if (fchmod(file1_fd, 0600)) {
7413 log_stderr("failure: fchmod");
7416 safe_close(file1_fd);
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");
7423 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7426 AT_SYMLINK_NOFOLLOW |
7429 if (open_tree_fd < 0)
7430 return log_errno(-1, "failure: create detached mount");
7432 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7433 return log_errno(-1, "failure: set mount attributes");
7437 log_stderr("failure: fork");
7441 if (!switch_userns(attr.userns_fd, 0, 0, false))
7442 die("failure: switch_userns");
7444 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7447 die("failure: io_uring_open_file");
7451 if (wait_for_pid(pid)) {
7452 log_stderr("failure: wait_for_pid");
7458 log_stderr("failure: fork");
7462 if (!caps_supported()) {
7463 log_debug("skip: capability library not installed");
7467 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
7468 die("failure: switch_userns");
7471 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7472 -1, false, &ret_cqe);
7474 die("failure: io_uring_open_file");
7476 die("failure: non-open() related io_uring_open_file failure");
7477 if (ret_cqe != -EACCES)
7478 die("failure: errno(%d)", abs(ret_cqe));
7481 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7482 -1, true, &ret_cqe);
7484 die("failure: io_uring_open_file");
7486 die("failure: non-open() related io_uring_open_file failure");
7487 if (ret_cqe != -EACCES)
7488 die("failure: errno(%d)", abs(ret_cqe));
7491 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7492 -1, false, &ret_cqe);
7494 die("failure: io_uring_open_file");
7496 die("failure: non-open() related io_uring_open_file failure");
7497 if (ret_cqe != -EACCES)
7498 die("failure: errno(%d)", abs(ret_cqe));
7501 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7502 -1, true, &ret_cqe);
7504 die("failure: io_uring_open_file");
7506 die("failure: non-open() related io_uring_open_file failure");
7507 if (ret_cqe != -EACCES)
7508 die("failure: errno(%d)", abs(ret_cqe));
7510 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7511 cred_id, false, NULL);
7513 die("failure: io_uring_open_file");
7515 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7516 cred_id, true, NULL);
7518 die("failure: io_uring_open_file");
7522 if (wait_for_pid(pid)) {
7523 log_stderr("failure: wait_for_pid");
7528 log_debug("Ran test");
7530 ret = io_uring_unregister_personality(ring, cred_id);
7532 log_stderr("failure: io_uring_unregister_personality");
7535 munmap(ring, sizeof(struct io_uring));
7537 safe_close(attr.userns_fd);
7538 safe_close(file1_fd);
7539 safe_close(open_tree_fd);
7544 static int io_uring_idmapped_unmapped_userns(void)
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,
7552 int cred_id, ret, ret_cqe;
7555 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7556 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7558 return log_errno(-1, "failure: io_uring_queue_init");
7560 ret = io_uring_queue_init(8, ring, 0);
7562 log_stderr("failure: io_uring_queue_init");
7566 ret = io_uring_register_personality(ring);
7569 goto out_unmap; /* personalities not supported */
7573 /* create file only owner can open */
7574 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7576 log_stderr("failure: openat");
7579 if (fchown(file1_fd, 0, 0)) {
7580 log_stderr("failure: fchown");
7583 if (fchmod(file1_fd, 0600)) {
7584 log_stderr("failure: fchmod");
7587 safe_close(file1_fd);
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");
7594 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7597 AT_SYMLINK_NOFOLLOW |
7600 if (open_tree_fd < 0)
7601 return log_errno(-1, "failure: create detached mount");
7603 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7604 return log_errno(-1, "failure: set mount attributes");
7608 log_stderr("failure: fork");
7612 if (!caps_supported()) {
7613 log_debug("skip: capability library not installed");
7617 if (!switch_userns(attr.userns_fd, 10000, 10000, true))
7618 die("failure: switch_ids");
7621 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7622 cred_id, false, &ret_cqe);
7624 die("failure: io_uring_open_file");
7626 die("failure: non-open() related io_uring_open_file failure");
7627 if (ret_cqe != -EACCES)
7628 die("failure: errno(%d)", abs(ret_cqe));
7631 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7632 cred_id, true, &ret_cqe);
7634 die("failure: io_uring_open_file");
7636 die("failure: non-open() related io_uring_open_file failure");
7637 if (ret_cqe != -EACCES)
7638 die("failure: errno(%d)", abs(ret_cqe));
7642 if (wait_for_pid(pid)) {
7643 log_stderr("failure: wait_for_pid");
7648 log_debug("Ran test");
7650 ret = io_uring_unregister_personality(ring, cred_id);
7652 log_stderr("failure: io_uring_unregister_personality");
7655 munmap(ring, sizeof(struct io_uring));
7657 safe_close(attr.userns_fd);
7658 safe_close(file1_fd);
7659 safe_close(open_tree_fd);
7663 #endif /* HAVE_LIBURING_H */
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.
7670 static int setgid_create(void)
7673 int file1_fd = -EBADF;
7676 if (!caps_supported())
7679 if (fchmod(t_dir1_fd, S_IRUSR |
7689 log_stderr("failure: fchmod");
7693 /* Verify that the setgid bit got raised. */
7694 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7695 log_stderr("failure: is_setgid");
7701 log_stderr("failure: fork");
7705 /* create regular file via open() */
7706 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7708 die("failure: create");
7710 /* We're capable_wrt_inode_uidgid() and also our fsgid matches
7711 * the directories gid.
7713 if (!is_setgid(t_dir1_fd, FILE1, 0))
7714 die("failure: is_setgid");
7716 /* create directory */
7717 if (mkdirat(t_dir1_fd, DIR1, 0000))
7718 die("failure: create");
7720 /* Directories always inherit the setgid bit. */
7721 if (!is_setgid(t_dir1_fd, DIR1, 0))
7722 die("failure: is_setgid");
7724 if (unlinkat(t_dir1_fd, FILE1, 0))
7725 die("failure: delete");
7727 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7728 die("failure: delete");
7732 if (wait_for_pid(pid))
7737 log_stderr("failure: fork");
7741 if (!switch_ids(0, 10000))
7742 die("failure: switch_ids");
7745 die("failure: caps_down");
7747 /* create regular file via open() */
7748 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7750 die("failure: create");
7752 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7753 * bit needs to be stripped.
7755 if (is_setgid(t_dir1_fd, FILE1, 0))
7756 die("failure: is_setgid");
7758 /* create directory */
7759 if (mkdirat(t_dir1_fd, DIR1, 0000))
7760 die("failure: create");
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");
7767 /* Directories always inherit the setgid bit. */
7768 if (!is_setgid(t_dir1_fd, DIR1, 0))
7769 die("failure: is_setgid");
7774 if (wait_for_pid(pid))
7778 log_debug("Ran test");
7780 safe_close(file1_fd);
7785 static int setgid_create_idmapped(void)
7788 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7789 struct mount_attr attr = {
7790 .attr_set = MOUNT_ATTR_IDMAP,
7794 if (!caps_supported())
7797 if (fchmod(t_dir1_fd, S_IRUSR |
7807 log_stderr("failure: fchmod");
7811 /* Verify that the sid bits got raised. */
7812 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7813 log_stderr("failure: is_setgid");
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");
7824 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7827 AT_SYMLINK_NOFOLLOW |
7830 if (open_tree_fd < 0) {
7831 log_stderr("failure: sys_open_tree");
7835 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7836 log_stderr("failure: sys_mount_setattr");
7842 log_stderr("failure: fork");
7846 if (!switch_ids(10000, 11000))
7847 die("failure: switch fsids");
7849 /* create regular file via open() */
7850 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7852 die("failure: create");
7854 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7855 * bit needs to be stripped.
7857 if (is_setgid(open_tree_fd, FILE1, 0))
7858 die("failure: is_setgid");
7860 /* create directory */
7861 if (mkdirat(open_tree_fd, DIR1, 0000))
7862 die("failure: create");
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");
7869 /* Directories always inherit the setgid bit. */
7870 if (!is_setgid(open_tree_fd, DIR1, 0))
7871 die("failure: is_setgid");
7876 if (wait_for_pid(pid))
7880 log_debug("Ran test");
7882 safe_close(attr.userns_fd);
7883 safe_close(file1_fd);
7884 safe_close(open_tree_fd);
7889 static int setgid_create_idmapped_in_userns(void)
7892 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7893 struct mount_attr attr = {
7894 .attr_set = MOUNT_ATTR_IDMAP,
7898 if (!caps_supported())
7901 if (fchmod(t_dir1_fd, S_IRUSR |
7911 log_stderr("failure: fchmod");
7915 /* Verify that the sid bits got raised. */
7916 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7917 log_stderr("failure: is_setgid");
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");
7928 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7931 AT_SYMLINK_NOFOLLOW |
7934 if (open_tree_fd < 0) {
7935 log_stderr("failure: sys_open_tree");
7939 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7940 log_stderr("failure: sys_mount_setattr");
7946 log_stderr("failure: fork");
7950 if (!switch_userns(attr.userns_fd, 0, 0, false))
7951 die("failure: switch_userns");
7953 /* create regular file via open() */
7954 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7956 die("failure: create");
7958 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
7959 * bit needs to be set.
7961 if (!is_setgid(open_tree_fd, FILE1, 0))
7962 die("failure: is_setgid");
7964 /* create directory */
7965 if (mkdirat(open_tree_fd, DIR1, 0000))
7966 die("failure: create");
7968 /* Directories always inherit the setgid bit. */
7969 if (!is_setgid(open_tree_fd, DIR1, 0))
7970 die("failure: is_setgid");
7972 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
7973 die("failure: check ownership");
7975 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
7976 die("failure: check ownership");
7978 if (unlinkat(open_tree_fd, FILE1, 0))
7979 die("failure: delete");
7981 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
7982 die("failure: delete");
7986 if (wait_for_pid(pid))
7989 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7990 log_stderr("failure: fchownat");
7994 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7995 log_stderr("failure: fchownat");
8001 log_stderr("failure: fork");
8005 if (!caps_supported()) {
8006 log_debug("skip: capability library not installed");
8010 if (!switch_userns(attr.userns_fd, 0, 0, true))
8011 die("failure: switch_userns");
8013 /* create regular file via open() */
8014 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8016 die("failure: create");
8018 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8019 * bit needs to be stripped.
8021 if (is_setgid(open_tree_fd, FILE1, 0))
8022 die("failure: is_setgid");
8024 /* create directory */
8025 if (mkdirat(open_tree_fd, DIR1, 0000))
8026 die("failure: create");
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");
8033 /* Directories always inherit the setgid bit. */
8034 if (!is_setgid(open_tree_fd, DIR1, 0))
8035 die("failure: is_setgid");
8038 /* Files and directories created in setgid directories inherit
8039 * the i_gid of the parent directory.
8041 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8042 die("failure: check ownership");
8044 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8045 die("failure: check ownership");
8047 if (unlinkat(open_tree_fd, FILE1, 0))
8048 die("failure: delete");
8050 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8051 die("failure: delete");
8055 if (wait_for_pid(pid))
8058 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8059 log_stderr("failure: fchownat");
8063 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8064 log_stderr("failure: fchownat");
8070 log_stderr("failure: fork");
8074 if (!caps_supported()) {
8075 log_debug("skip: capability library not installed");
8079 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8080 die("failure: switch_userns");
8082 /* create regular file via open() */
8083 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8085 die("failure: create");
8087 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8088 * bit needs to be stripped.
8090 if (is_setgid(open_tree_fd, FILE1, 0))
8091 die("failure: is_setgid");
8093 /* create directory */
8094 if (mkdirat(open_tree_fd, DIR1, 0000))
8095 die("failure: create");
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");
8103 /* Directories always inherit the setgid bit. */
8104 if (!is_setgid(open_tree_fd, DIR1, 0))
8105 die("failure: is_setgid");
8108 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8109 die("failure: check ownership");
8111 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8112 die("failure: check ownership");
8116 if (wait_for_pid(pid))
8120 log_debug("Ran test");
8122 safe_close(attr.userns_fd);
8123 safe_close(file1_fd);
8124 safe_close(open_tree_fd);
8129 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8130 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8132 static void *idmapped_mount_create_cb(void *data)
8134 int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8135 struct mount_attr attr = {
8136 .attr_set = MOUNT_ATTR_IDMAP,
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");
8146 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8147 log_stderr("failure: sys_mount_setattr");
8151 fret = EXIT_SUCCESS;
8154 safe_close(attr.userns_fd);
8155 pthread_exit(INT_TO_PTR(fret));
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).
8167 static void *idmapped_mount_operations_cb(void *data)
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);
8173 if (!switch_fsids(10000, 10000)) {
8174 log_stderr("failure: switch fsids");
8178 file1_fd = openat(open_tree_fd, FILE1,
8179 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8181 log_stderr("failure: openat");
8185 file2_fd = openat(open_tree_fd, FILE2,
8186 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8188 log_stderr("failure: openat");
8192 if (mkdirat(open_tree_fd, DIR1, 0777)) {
8193 log_stderr("failure: mkdirat");
8197 dir1_fd = openat(open_tree_fd, DIR1,
8198 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8200 log_stderr("failure: openat");
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");
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");
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");
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");
8232 dir1_fd2 = openat(t_dir1_fd, DIR1,
8233 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8235 log_stderr("failure: openat");
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");
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");
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");
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");
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");
8269 fret = EXIT_SUCCESS;
8272 safe_close(file1_fd);
8273 safe_close(file2_fd);
8274 safe_close(dir1_fd);
8275 safe_close(dir1_fd2);
8277 pthread_exit(INT_TO_PTR(fret));
8280 static int threaded_idmapped_mount_interactions(void)
8285 pthread_attr_t thread_attr;
8286 pthread_t threads[2];
8288 pthread_attr_init(&thread_attr);
8290 for (i = 0; i < 1000; i++) {
8291 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8295 log_stderr("failure: fork");
8299 int open_tree_fd = -EBADF;
8301 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8304 AT_SYMLINK_NOFOLLOW |
8307 if (open_tree_fd < 0)
8308 die("failure: sys_open_tree");
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");
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");
8320 ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8321 ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8325 die("failure: pthread_join");
8330 die("failure: pthread_join");
8340 if (wait_for_pid(pid)) {
8341 log_stderr("failure: iteration %d", i);
8345 rm_r(t_dir1_fd, ".");
8350 log_debug("Ran test");
8356 static int setattr_truncate(void)
8359 int file1_fd = -EBADF;
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);
8364 log_stderr("failure: create");
8368 if (ftruncate(file1_fd, 10000)) {
8369 log_stderr("failure: ftruncate");
8373 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8374 log_stderr("failure: check ownership");
8378 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8379 log_stderr("failure: expected_file_size");
8383 if (ftruncate(file1_fd, 0)) {
8384 log_stderr("failure: ftruncate");
8388 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8389 log_stderr("failure: check ownership");
8393 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8394 log_stderr("failure: expected_file_size");
8398 if (unlinkat(t_dir1_fd, FILE1, 0)) {
8399 log_stderr("failure: remove");
8404 log_debug("Ran test");
8406 safe_close(file1_fd);
8411 static int setattr_truncate_idmapped(void)
8414 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8416 struct mount_attr attr = {
8417 .attr_set = MOUNT_ATTR_IDMAP,
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");
8427 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8430 AT_SYMLINK_NOFOLLOW |
8433 if (open_tree_fd < 0) {
8434 log_stderr("failure: sys_open_tree");
8438 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8439 log_stderr("failure: sys_mount_setattr");
8445 log_stderr("failure: fork");
8449 if (!switch_ids(10000, 10000))
8450 die("failure: switch_ids");
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);
8455 die("failure: create");
8457 if (ftruncate(file1_fd, 10000))
8458 die("failure: ftruncate");
8460 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8461 die("failure: check ownership");
8463 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8464 die("failure: expected_file_size");
8466 if (ftruncate(file1_fd, 0))
8467 die("failure: ftruncate");
8469 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8470 die("failure: check ownership");
8472 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8473 die("failure: expected_file_size");
8477 if (wait_for_pid(pid))
8482 log_stderr("failure: fork");
8486 int file1_fd2 = -EBADF;
8488 /* create regular file via open() */
8489 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8491 die("failure: create");
8493 if (ftruncate(file1_fd2, 10000))
8494 die("failure: ftruncate");
8496 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8497 die("failure: check ownership");
8499 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8500 die("failure: expected_file_size");
8502 if (ftruncate(file1_fd2, 0))
8503 die("failure: ftruncate");
8505 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8506 die("failure: check ownership");
8508 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8509 die("failure: expected_file_size");
8513 if (wait_for_pid(pid))
8517 log_debug("Ran test");
8519 safe_close(file1_fd);
8520 safe_close(open_tree_fd);
8525 static int setattr_truncate_idmapped_in_userns(void)
8528 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8529 struct mount_attr attr = {
8530 .attr_set = MOUNT_ATTR_IDMAP,
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");
8541 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8544 AT_SYMLINK_NOFOLLOW |
8547 if (open_tree_fd < 0) {
8548 log_stderr("failure: sys_open_tree");
8552 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8553 log_stderr("failure: sys_mount_setattr");
8559 log_stderr("failure: fork");
8563 if (!switch_userns(attr.userns_fd, 0, 0, false))
8564 die("failure: switch_userns");
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);
8569 die("failure: create");
8571 if (ftruncate(file1_fd, 10000))
8572 die("failure: ftruncate");
8574 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8575 die("failure: check ownership");
8577 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8578 die("failure: expected_file_size");
8580 if (ftruncate(file1_fd, 0))
8581 die("failure: ftruncate");
8583 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8584 die("failure: check ownership");
8586 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8587 die("failure: expected_file_size");
8589 if (unlinkat(open_tree_fd, FILE1, 0))
8590 die("failure: delete");
8594 if (wait_for_pid(pid))
8597 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8598 log_stderr("failure: fchownat");
8602 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8603 log_stderr("failure: fchownat");
8609 log_stderr("failure: fork");
8613 if (!caps_supported()) {
8614 log_debug("skip: capability library not installed");
8618 if (!switch_userns(attr.userns_fd, 0, 0, true))
8619 die("failure: switch_userns");
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);
8624 die("failure: create");
8626 if (ftruncate(file1_fd, 10000))
8627 die("failure: ftruncate");
8629 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8630 die("failure: check ownership");
8632 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8633 die("failure: expected_file_size");
8635 if (ftruncate(file1_fd, 0))
8636 die("failure: ftruncate");
8638 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8639 die("failure: check ownership");
8641 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8642 die("failure: expected_file_size");
8644 if (unlinkat(open_tree_fd, FILE1, 0))
8645 die("failure: delete");
8649 if (wait_for_pid(pid))
8652 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8653 log_stderr("failure: fchownat");
8657 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8658 log_stderr("failure: fchownat");
8664 log_stderr("failure: fork");
8668 if (!caps_supported()) {
8669 log_debug("skip: capability library not installed");
8673 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8674 die("failure: switch_userns");
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);
8679 die("failure: create");
8681 if (ftruncate(file1_fd, 10000))
8682 die("failure: ftruncate");
8684 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8685 die("failure: check ownership");
8687 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8688 die("failure: expected_file_size");
8690 if (ftruncate(file1_fd, 0))
8691 die("failure: ftruncate");
8693 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8694 die("failure: check ownership");
8696 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8697 die("failure: expected_file_size");
8699 if (unlinkat(open_tree_fd, FILE1, 0))
8700 die("failure: delete");
8704 if (wait_for_pid(pid))
8708 log_debug("Ran test");
8710 safe_close(attr.userns_fd);
8711 safe_close(file1_fd);
8712 safe_close(open_tree_fd);
8717 static void usage(void)
8719 fprintf(stderr, "Description:\n");
8720 fprintf(stderr, " Run idmapped mount tests\n\n");
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");
8726 _exit(EXIT_SUCCESS);
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'},
8738 struct t_idmapped_mounts {
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", },
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", },
8793 int main(int argc, char *argv[])
8797 bool supported = false;
8799 while ((ret = getopt_long(argc, argv, "", longopts, &index)) != -1) {
8808 t_mountpoint = optarg;
8821 die_errno(EINVAL, "test device missing");
8824 die_errno(EINVAL, "test filesystem type missing");
8827 die_errno(EINVAL, "mountpoint of test device missing");
8829 /* create separate mount namespace */
8830 if (unshare(CLONE_NEWNS))
8831 die("failure: create new mount namespace");
8833 /* turn off mount propagation */
8834 if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
8835 die("failure: turn mount propagation off");
8837 t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
8839 die("failed to open %s", t_mountpoint);
8842 * Caller just wants to know whether the filesystem we're on supports
8846 int open_tree_fd = -EBADF;
8847 struct mount_attr attr = {
8848 .attr_set = MOUNT_ATTR_IDMAP,
8849 .userns_fd = -EBADF,
8852 /* Changing mount properties on a detached mount. */
8853 attr.userns_fd = get_userns_fd(0, 1000, 1);
8854 if (attr.userns_fd < 0)
8857 open_tree_fd = sys_open_tree(t_mnt_fd, "",
8860 AT_SYMLINK_NOFOLLOW |
8863 if (open_tree_fd < 0)
8866 ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr));
8868 close(open_tree_fd);
8869 close(attr.userns_fd);
8877 stash_overflowuid();
8878 stash_overflowgid();
8880 fret = EXIT_FAILURE;
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];
8896 fprintf(stderr, "failure: %s\n", t->description);
8903 ret = wait_for_pid(pid);
8910 fret = EXIT_SUCCESS;