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 #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
85 uid_t t_overflowuid = 65534;
86 gid_t t_overflowgid = 65534;
88 /* path of the test device */
91 /* path of the test device */
94 /* mountpoint of the test device */
95 const char *t_mountpoint;
97 /* fd for @t_mountpoint */
103 /* temporary buffer */
104 char t_buf[PATH_MAX];
106 static void stash_overflowuid(void)
112 fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
116 ret = read(fd, buf, sizeof(buf));
121 t_overflowuid = atoi(buf);
124 static void stash_overflowgid(void)
130 fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
134 ret = read(fd, buf, sizeof(buf));
139 t_overflowgid = atoi(buf);
142 static bool is_xfs(void)
144 static int enabled = -1;
147 enabled = !strcmp(t_fstype, "xfs");
152 static bool protected_symlinks_enabled(void)
154 static int enabled = -1;
163 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
167 ret = read(fd, buf, sizeof(buf));
179 static bool xfs_irix_sgid_inherit_enabled(void)
181 static int enabled = -1;
191 fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
195 ret = read(fd, buf, sizeof(buf));
208 static inline bool caps_supported(void)
212 #ifdef HAVE_SYS_CAPABILITY_H
219 /* caps_down - lower all effective caps */
220 static int caps_down(void)
223 #ifdef HAVE_SYS_CAPABILITY_H
227 caps = cap_get_proc();
231 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
235 ret = cap_set_proc(caps);
247 /* caps_up - raise all permitted caps */
248 static int caps_up(void)
251 #ifdef HAVE_SYS_CAPABILITY_H
256 caps = cap_get_proc();
260 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
261 cap_flag_value_t flag;
263 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
271 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
276 ret = cap_set_proc(caps);
287 /* __expected_uid_gid - check whether file is owned by the provided uid and gid */
288 static bool __expected_uid_gid(int dfd, const char *path, int flags,
289 uid_t expected_uid, gid_t expected_gid, bool log)
294 ret = fstatat(dfd, path, &st, flags);
296 return log_errno(false, "failure: fstatat");
298 if (log && st.st_uid != expected_uid)
299 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
301 if (log && st.st_gid != expected_gid)
302 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
304 errno = 0; /* Don't report misleading errno. */
305 return st.st_uid == expected_uid && st.st_gid == expected_gid;
308 static bool expected_uid_gid(int dfd, const char *path, int flags,
309 uid_t expected_uid, gid_t expected_gid)
311 return __expected_uid_gid(dfd, path, flags,
312 expected_uid, expected_gid, true);
315 static bool expected_file_size(int dfd, const char *path,
316 int flags, off_t expected_size)
321 ret = fstatat(dfd, path, &st, flags);
323 return log_errno(false, "failure: fstatat");
325 if (st.st_size != expected_size)
326 return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)",
327 (size_t)st.st_size, (size_t)expected_size);
332 /* is_setid - check whether file is S_ISUID and S_ISGID */
333 static bool is_setid(int dfd, const char *path, int flags)
338 ret = fstatat(dfd, path, &st, flags);
342 errno = 0; /* Don't report misleading errno. */
343 return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
346 /* is_setgid - check whether file or directory is S_ISGID */
347 static bool is_setgid(int dfd, const char *path, int flags)
352 ret = fstatat(dfd, path, &st, flags);
356 errno = 0; /* Don't report misleading errno. */
357 return (st.st_mode & S_ISGID);
360 /* is_sticky - check whether file is S_ISVTX */
361 static bool is_sticky(int dfd, const char *path, int flags)
366 ret = fstatat(dfd, path, &st, flags);
370 errno = 0; /* Don't report misleading errno. */
371 return (st.st_mode & S_ISVTX) > 0;
374 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
377 return log_errno(false, "failure: setfsgid");
379 if (setfsgid(-1) != fsgid)
380 return log_errno(false, "failure: setfsgid(-1)");
383 return log_errno(false, "failure: setfsuid");
385 if (setfsuid(-1) != fsuid)
386 return log_errno(false, "failure: setfsuid(-1)");
391 static inline bool switch_ids(uid_t uid, gid_t gid)
393 if (setgroups(0, NULL))
394 return log_errno(false, "failure: setgroups");
396 if (setresgid(gid, gid, gid))
397 return log_errno(false, "failure: setresgid");
399 if (setresuid(uid, uid, uid))
400 return log_errno(false, "failure: setresuid");
405 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
407 if (setns(fd, CLONE_NEWUSER))
408 return log_errno(false, "failure: setns");
410 if (!switch_ids(uid, gid))
411 return log_errno(false, "failure: switch_ids");
413 if (drop_caps && !caps_down())
414 return log_errno(false, "failure: caps_down");
419 /* rm_r - recursively remove all files */
420 static int rm_r(int fd, const char *path)
424 struct dirent *direntp;
426 if (!path || strcmp(path, "") == 0)
429 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
433 dir = fdopendir(dfd);
439 while ((direntp = readdir(dir))) {
442 if (!strcmp(direntp->d_name, ".") ||
443 !strcmp(direntp->d_name, ".."))
446 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
447 if (ret < 0 && errno != ENOENT)
450 if (S_ISDIR(st.st_mode))
451 ret = rm_r(dfd, direntp->d_name);
453 ret = unlinkat(dfd, direntp->d_name, 0);
454 if (ret < 0 && errno != ENOENT)
458 ret = unlinkat(fd, path, AT_REMOVEDIR);
463 /* chown_r - recursively change ownership of all files */
464 static int chown_r(int fd, const char *path, uid_t uid, gid_t gid)
468 struct dirent *direntp;
470 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
474 dir = fdopendir(dfd);
480 while ((direntp = readdir(dir))) {
483 if (!strcmp(direntp->d_name, ".") ||
484 !strcmp(direntp->d_name, ".."))
487 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
488 if (ret < 0 && errno != ENOENT)
491 if (S_ISDIR(st.st_mode))
492 ret = chown_r(dfd, direntp->d_name, uid, gid);
494 ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
495 if (ret < 0 && errno != ENOENT)
499 ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
505 * There'll be scenarios where you'll want to see the attributes associated with
506 * a directory tree during debugging or just to make sure things look correct.
507 * Simply uncomment and place the print_r() helper where you need it.
510 static int fd_cloexec(int fd, bool cloexec)
514 oflags = fcntl(fd, F_GETFD, 0);
519 nflags = oflags | FD_CLOEXEC;
521 nflags = oflags & ~FD_CLOEXEC;
523 if (nflags == oflags)
526 if (fcntl(fd, F_SETFD, nflags) < 0)
532 static inline int dup_cloexec(int fd)
540 if (fd_cloexec(fd_dup, true)) {
548 __attribute__((unused)) static int print_r(int fd, const char *path)
553 struct dirent *direntp;
556 if (!path || *path == '\0') {
557 char buf[sizeof("/proc/self/fd/") + 30];
559 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
560 if (ret < 0 || (size_t)ret >= sizeof(buf))
564 * O_PATH file descriptors can't be used so we need to re-open
567 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
569 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
575 * When fdopendir() below succeeds it assumes ownership of the fd so we
576 * to make sure we always have an fd that fdopendir() can own which is
577 * why we dup() in the case where the caller wants us to operate on the
580 dfd_dup = dup_cloexec(dfd);
586 dir = fdopendir(dfd);
592 /* Transfer ownership to fdopendir(). */
595 while ((direntp = readdir(dir))) {
596 if (!strcmp(direntp->d_name, ".") ||
597 !strcmp(direntp->d_name, ".."))
600 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
601 if (ret < 0 && errno != ENOENT)
605 if (S_ISDIR(st.st_mode))
606 ret = print_r(dfd_dup, direntp->d_name);
608 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n",
609 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
610 dfd_dup, direntp->d_name);
611 if (ret < 0 && errno != ENOENT)
615 if (!path || *path == '\0')
616 ret = fstatat(fd, "", &st,
617 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
620 ret = fstatat(fd, path, &st,
621 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
623 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n",
624 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
625 (path && *path) ? path : "(null)");
634 /* fd_to_fd - transfer data from one fd to another */
635 static int fd_to_fd(int from, int to)
638 uint8_t buf[PATH_MAX];
640 ssize_t bytes_to_write;
643 bytes_read = read_nointr(from, buf, sizeof buf);
649 bytes_to_write = (size_t)bytes_read;
651 ssize_t bytes_written;
653 bytes_written = write_nointr(to, p, bytes_to_write);
654 if (bytes_written < 0)
657 bytes_to_write -= bytes_written;
659 } while (bytes_to_write > 0);
665 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
669 return syscall(__NR_execveat, fd, path, argv, envp, flags);
677 #define CAP_NET_RAW 13
680 #ifndef VFS_CAP_FLAGS_EFFECTIVE
681 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
684 #ifndef VFS_CAP_U32_3
685 #define VFS_CAP_U32_3 2
689 #define VFS_CAP_U32 VFS_CAP_U32_3
692 #ifndef VFS_CAP_REVISION_1
693 #define VFS_CAP_REVISION_1 0x01000000
696 #ifndef VFS_CAP_REVISION_2
697 #define VFS_CAP_REVISION_2 0x02000000
700 #ifndef VFS_CAP_REVISION_3
701 #define VFS_CAP_REVISION_3 0x03000000
702 struct vfs_ns_cap_data {
712 #if __BYTE_ORDER == __BIG_ENDIAN
713 #define cpu_to_le16(w16) le16_to_cpu(w16)
714 #define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
715 #define cpu_to_le32(w32) le32_to_cpu(w32)
716 #define le32_to_cpu(w32) \
717 ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
718 (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
719 #elif __BYTE_ORDER == __LITTLE_ENDIAN
720 #define cpu_to_le16(w16) ((u_int16_t)(w16))
721 #define le16_to_cpu(w16) ((u_int16_t)(w16))
722 #define cpu_to_le32(w32) ((u_int32_t)(w32))
723 #define le32_to_cpu(w32) ((u_int32_t)(w32))
725 #error Expected endianess macro to be set
728 /* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */
729 static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid)
731 #define __cap_raised_permitted(x, ns_cap_data) \
732 ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31)))
733 struct vfs_ns_cap_data ns_xattr = {};
736 ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
737 if (ret < 0 || ret == 0)
740 if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
742 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
744 log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
747 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
748 (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
750 log_stderr("failure: fscaps version");
756 /* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */
757 static int set_dummy_vfs_caps(int fd, int flags, int rootuid)
759 #define __raise_cap_permitted(x, ns_cap_data) \
760 ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
762 struct vfs_ns_cap_data ns_xattr;
764 memset(&ns_xattr, 0, sizeof(ns_xattr));
765 __raise_cap_permitted(CAP_NET_RAW, ns_xattr);
766 ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
767 ns_xattr.rootid = cpu_to_le32(rootuid);
769 return fsetxattr(fd, "security.capability",
770 &ns_xattr, sizeof(ns_xattr), flags);
773 #define safe_close(fd) \
781 static void test_setup(void)
783 if (mkdirat(t_mnt_fd, T_DIR1, 0777))
784 die("failure: mkdirat");
786 t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
788 die("failure: openat");
790 if (fchmod(t_dir1_fd, 0777))
791 die("failure: fchmod");
794 static void test_cleanup(void)
796 safe_close(t_dir1_fd);
797 if (rm_r(t_mnt_fd, T_DIR1))
798 die("failure: rm_r");
801 /* Validate that basic file operations on idmapped mounts. */
802 static int fsids_unmapped(void)
805 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
806 struct mount_attr attr = {
807 .attr_set = MOUNT_ATTR_IDMAP,
810 /* create hardlink target */
811 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
812 if (hardlink_target_fd < 0) {
813 log_stderr("failure: openat");
817 /* create directory for rename test */
818 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
819 log_stderr("failure: mkdirat");
823 /* change ownership of all files to uid 0 */
824 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
825 log_stderr("failure: chown_r");
829 /* Changing mount properties on a detached mount. */
830 attr.userns_fd = get_userns_fd(0, 10000, 10000);
831 if (attr.userns_fd < 0) {
832 log_stderr("failure: get_userns_fd");
836 open_tree_fd = sys_open_tree(t_dir1_fd, "",
839 AT_SYMLINK_NOFOLLOW |
842 if (open_tree_fd < 0) {
843 log_stderr("failure: sys_open_tree");
847 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
848 log_stderr("failure: sys_mount_setattr");
852 if (!switch_fsids(0, 0)) {
853 log_stderr("failure: switch_fsids");
857 /* The caller's fsids don't have a mappings in the idmapped mount so any
858 * file creation must fail.
861 /* create hardlink */
862 if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
863 log_stderr("failure: linkat");
866 if (errno != EOVERFLOW) {
867 log_stderr("failure: errno");
871 /* try to rename a file */
872 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
873 log_stderr("failure: renameat");
876 if (errno != EOVERFLOW) {
877 log_stderr("failure: errno");
881 /* try to rename a directory */
882 if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
883 log_stderr("failure: renameat");
886 if (errno != EOVERFLOW) {
887 log_stderr("failure: errno");
891 /* The caller is privileged over the inode so file deletion must work. */
894 if (unlinkat(open_tree_fd, FILE1, 0)) {
895 log_stderr("failure: unlinkat");
899 /* remove directory */
900 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
901 log_stderr("failure: unlinkat");
905 /* The caller's fsids don't have a mappings in the idmapped mount so
906 * any file creation must fail.
909 /* create regular file via open() */
910 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
912 log_stderr("failure: create");
915 if (errno != EOVERFLOW) {
916 log_stderr("failure: errno");
920 /* create regular file via mknod */
921 if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
922 log_stderr("failure: mknodat");
925 if (errno != EOVERFLOW) {
926 log_stderr("failure: errno");
930 /* create character device */
931 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
932 log_stderr("failure: mknodat");
935 if (errno != EOVERFLOW) {
936 log_stderr("failure: errno");
941 if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
942 log_stderr("failure: symlinkat");
945 if (errno != EOVERFLOW) {
946 log_stderr("failure: errno");
950 /* create directory */
951 if (!mkdirat(open_tree_fd, DIR1, 0700)) {
952 log_stderr("failure: mkdirat");
955 if (errno != EOVERFLOW) {
956 log_stderr("failure: errno");
961 log_debug("Ran test");
963 safe_close(attr.userns_fd);
964 safe_close(hardlink_target_fd);
965 safe_close(file1_fd);
966 safe_close(open_tree_fd);
971 static int fsids_mapped(void)
974 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
975 struct mount_attr attr = {
976 .attr_set = MOUNT_ATTR_IDMAP,
980 if (!caps_supported())
983 /* create hardlink target */
984 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
985 if (hardlink_target_fd < 0) {
986 log_stderr("failure: openat");
990 /* create directory for rename test */
991 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
992 log_stderr("failure: mkdirat");
996 /* change ownership of all files to uid 0 */
997 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
998 log_stderr("failure: chown_r");
1002 /* Changing mount properties on a detached mount. */
1003 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1004 if (attr.userns_fd < 0) {
1005 log_stderr("failure: get_userns_fd");
1009 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1012 AT_SYMLINK_NOFOLLOW |
1015 if (open_tree_fd < 0) {
1016 log_stderr("failure: sys_open_tree");
1020 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1021 log_stderr("failure: sys_mount_setattr");
1027 log_stderr("failure: fork");
1031 if (!switch_fsids(10000, 10000))
1032 die("failure: switch fsids");
1035 die("failure: raise caps");
1037 /* The caller's fsids now have mappings in the idmapped mount so
1038 * any file creation must fail.
1041 /* create hardlink */
1042 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1043 die("failure: create hardlink");
1045 /* try to rename a file */
1046 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1047 die("failure: rename");
1049 /* try to rename a directory */
1050 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1051 die("failure: rename");
1054 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1055 die("failure: delete");
1057 /* remove directory */
1058 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1059 die("failure: delete");
1061 /* The caller's fsids have mappings in the idmapped mount so any
1062 * file creation must fail.
1065 /* create regular file via open() */
1066 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1068 die("failure: create");
1070 /* create regular file via mknod */
1071 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1072 die("failure: create");
1074 /* create character device */
1075 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1076 die("failure: create");
1078 /* create symlink */
1079 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1080 die("failure: create");
1082 /* create directory */
1083 if (mkdirat(open_tree_fd, DIR1, 0700))
1084 die("failure: create");
1088 if (wait_for_pid(pid))
1092 log_debug("Ran test");
1094 safe_close(attr.userns_fd);
1095 safe_close(file1_fd);
1096 safe_close(hardlink_target_fd);
1097 safe_close(open_tree_fd);
1102 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1103 static int create_in_userns(void)
1106 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1107 struct mount_attr attr = {
1108 .attr_set = MOUNT_ATTR_IDMAP,
1112 /* change ownership of all files to uid 0 */
1113 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1114 log_stderr("failure: chown_r");
1118 /* Changing mount properties on a detached mount. */
1119 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1120 if (attr.userns_fd < 0) {
1121 log_stderr("failure: get_userns_fd");
1125 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1128 AT_SYMLINK_NOFOLLOW |
1131 if (open_tree_fd < 0) {
1132 log_stderr("failure: sys_open_tree");
1136 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1137 log_stderr("failure: sys_mount_setattr");
1143 log_stderr("failure: fork");
1147 if (!switch_userns(attr.userns_fd, 0, 0, false))
1148 die("failure: switch_userns");
1150 /* create regular file via open() */
1151 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1153 die("failure: open file");
1154 safe_close(file1_fd);
1156 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1157 die("failure: check ownership");
1159 /* create regular file via mknod */
1160 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1161 die("failure: create");
1163 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1164 die("failure: check ownership");
1166 /* create symlink */
1167 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1168 die("failure: create");
1170 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1171 die("failure: check ownership");
1173 /* create directory */
1174 if (mkdirat(open_tree_fd, DIR1, 0700))
1175 die("failure: create");
1177 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1178 die("failure: check ownership");
1180 /* try to rename a file */
1181 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1182 die("failure: create");
1184 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1185 die("failure: check ownership");
1187 /* try to rename a file */
1188 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1189 die("failure: create");
1191 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1192 die("failure: check ownership");
1195 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1196 die("failure: remove");
1198 /* remove directory */
1199 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1200 die("failure: remove");
1205 if (wait_for_pid(pid))
1209 log_debug("Ran test");
1211 safe_close(attr.userns_fd);
1212 safe_close(file1_fd);
1213 safe_close(open_tree_fd);
1218 static int hardlink_crossing_mounts(void)
1221 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1223 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1224 log_stderr("failure: chown_r");
1228 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1231 AT_SYMLINK_NOFOLLOW |
1234 if (open_tree_fd < 0) {
1235 log_stderr("failure: sys_open_tree");
1239 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1241 log_stderr("failure: openat");
1245 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1246 log_stderr("failure: mkdirat");
1250 /* We're crossing a mountpoint so this must fail.
1252 * Note that this must also fail for non-idmapped mounts but here we're
1253 * interested in making sure we're not introducing an accidental way to
1254 * violate that restriction or that suddenly this becomes possible.
1256 if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1257 log_stderr("failure: linkat");
1260 if (errno != EXDEV) {
1261 log_stderr("failure: errno");
1266 log_debug("Ran test");
1268 safe_close(file1_fd);
1269 safe_close(open_tree_fd);
1274 static int hardlink_crossing_idmapped_mounts(void)
1277 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1278 struct mount_attr attr = {
1279 .attr_set = MOUNT_ATTR_IDMAP,
1282 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1283 log_stderr("failure: chown_r");
1287 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1288 if (attr.userns_fd < 0) {
1289 log_stderr("failure: get_userns_fd");
1293 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1296 AT_SYMLINK_NOFOLLOW |
1299 if (open_tree_fd1 < 0) {
1300 log_stderr("failure: sys_open_tree");
1304 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1305 log_stderr("failure: sys_mount_setattr");
1309 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1311 log_stderr("failure: openat");
1315 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1316 log_stderr("failure: expected_uid_gid");
1320 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1321 log_stderr("failure: expected_uid_gid");
1325 safe_close(file1_fd);
1327 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1328 log_stderr("failure: mkdirat");
1332 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1334 AT_SYMLINK_NOFOLLOW |
1338 if (open_tree_fd2 < 0) {
1339 log_stderr("failure: sys_open_tree");
1343 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1344 log_stderr("failure: sys_mount_setattr");
1348 /* We're crossing a mountpoint so this must fail.
1350 * Note that this must also fail for non-idmapped mounts but here we're
1351 * interested in making sure we're not introducing an accidental way to
1352 * violate that restriction or that suddenly this becomes possible.
1354 if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1355 log_stderr("failure: linkat");
1358 if (errno != EXDEV) {
1359 log_stderr("failure: errno");
1364 log_debug("Ran test");
1366 safe_close(attr.userns_fd);
1367 safe_close(file1_fd);
1368 safe_close(open_tree_fd1);
1369 safe_close(open_tree_fd2);
1374 static int hardlink_from_idmapped_mount(void)
1377 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1378 struct mount_attr attr = {
1379 .attr_set = MOUNT_ATTR_IDMAP,
1382 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1383 log_stderr("failure: chown_r");
1387 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1388 if (attr.userns_fd < 0) {
1389 log_stderr("failure: get_userns_fd");
1393 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1396 AT_SYMLINK_NOFOLLOW |
1399 if (open_tree_fd < 0) {
1400 log_stderr("failure: sys_open_tree");
1404 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1405 log_stderr("failure: sys_mount_setattr");
1409 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1411 log_stderr("failure: openat");
1414 safe_close(file1_fd);
1416 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1417 log_stderr("failure: expected_uid_gid");
1421 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1422 log_stderr("failure: expected_uid_gid");
1426 /* We're not crossing a mountpoint so this must succeed. */
1427 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
1428 log_stderr("failure: linkat");
1434 log_debug("Ran test");
1436 safe_close(attr.userns_fd);
1437 safe_close(file1_fd);
1438 safe_close(open_tree_fd);
1443 static int hardlink_from_idmapped_mount_in_userns(void)
1446 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1447 struct mount_attr attr = {
1448 .attr_set = MOUNT_ATTR_IDMAP,
1452 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1453 log_stderr("failure: chown_r");
1457 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1458 if (attr.userns_fd < 0) {
1459 log_stderr("failure: get_userns_fd");
1463 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1466 AT_SYMLINK_NOFOLLOW |
1469 if (open_tree_fd < 0) {
1470 log_stderr("failure: sys_open_tree");
1474 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1475 log_stderr("failure: sys_mount_setattr");
1481 log_stderr("failure: fork");
1485 if (!switch_userns(attr.userns_fd, 0, 0, false))
1486 die("failure: switch_userns");
1488 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1490 die("failure: create");
1492 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1493 die("failure: check ownership");
1495 /* We're not crossing a mountpoint so this must succeed. */
1496 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1497 die("failure: create");
1499 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1500 die("failure: check ownership");
1505 if (wait_for_pid(pid))
1509 log_debug("Ran test");
1511 safe_close(attr.userns_fd);
1512 safe_close(file1_fd);
1513 safe_close(open_tree_fd);
1518 static int rename_crossing_mounts(void)
1521 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1523 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1524 log_stderr("failure: chown_r");
1528 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1531 AT_SYMLINK_NOFOLLOW |
1534 if (open_tree_fd < 0) {
1535 log_stderr("failure: sys_open_tree");
1539 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1541 log_stderr("failure: openat");
1545 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1546 log_stderr("failure: mkdirat");
1550 /* We're crossing a mountpoint so this must fail.
1552 * Note that this must also fail for non-idmapped mounts but here we're
1553 * interested in making sure we're not introducing an accidental way to
1554 * violate that restriction or that suddenly this becomes possible.
1556 if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1557 log_stderr("failure: renameat");
1560 if (errno != EXDEV) {
1561 log_stderr("failure: errno");
1566 log_debug("Ran test");
1568 safe_close(file1_fd);
1569 safe_close(open_tree_fd);
1574 static int rename_crossing_idmapped_mounts(void)
1577 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1578 struct mount_attr attr = {
1579 .attr_set = MOUNT_ATTR_IDMAP,
1582 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1583 log_stderr("failure: chown_r");
1587 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1588 if (attr.userns_fd < 0) {
1589 log_stderr("failure: get_userns_fd");
1593 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1596 AT_SYMLINK_NOFOLLOW |
1599 if (open_tree_fd1 < 0) {
1600 log_stderr("failure: sys_open_tree");
1604 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1605 log_stderr("failure: sys_mount_setattr");
1609 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1611 log_stderr("failure: openat");
1615 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1616 log_stderr("failure: expected_uid_gid");
1620 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1621 log_stderr("failure: expected_uid_gid");
1625 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1626 log_stderr("failure: mkdirat");
1630 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1632 AT_SYMLINK_NOFOLLOW |
1636 if (open_tree_fd2 < 0) {
1637 log_stderr("failure: sys_open_tree");
1641 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1642 log_stderr("failure: sys_mount_setattr");
1646 /* We're crossing a mountpoint so this must fail.
1648 * Note that this must also fail for non-idmapped mounts but here we're
1649 * interested in making sure we're not introducing an accidental way to
1650 * violate that restriction or that suddenly this becomes possible.
1652 if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1653 log_stderr("failure: renameat");
1656 if (errno != EXDEV) {
1657 log_stderr("failure: errno");
1662 log_debug("Ran test");
1664 safe_close(attr.userns_fd);
1665 safe_close(file1_fd);
1666 safe_close(open_tree_fd1);
1667 safe_close(open_tree_fd2);
1672 static int rename_from_idmapped_mount(void)
1675 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1676 struct mount_attr attr = {
1677 .attr_set = MOUNT_ATTR_IDMAP,
1680 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1681 log_stderr("failure: chown_r");
1685 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1686 if (attr.userns_fd < 0) {
1687 log_stderr("failure: get_userns_fd");
1691 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1694 AT_SYMLINK_NOFOLLOW |
1697 if (open_tree_fd < 0) {
1698 log_stderr("failure: sys_open_tree");
1702 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1703 log_stderr("failure: sys_mount_setattr");
1707 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1709 log_stderr("failure: openat");
1713 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1714 log_stderr("failure: expected_uid_gid");
1718 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1719 log_stderr("failure: expected_uid_gid");
1723 /* We're not crossing a mountpoint so this must succeed. */
1724 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
1725 log_stderr("failure: renameat");
1730 log_debug("Ran test");
1732 safe_close(attr.userns_fd);
1733 safe_close(file1_fd);
1734 safe_close(open_tree_fd);
1739 static int rename_from_idmapped_mount_in_userns(void)
1742 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1744 struct mount_attr attr = {
1745 .attr_set = MOUNT_ATTR_IDMAP,
1748 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1749 log_stderr("failure: chown_r");
1753 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1754 if (attr.userns_fd < 0) {
1755 log_stderr("failure: get_userns_fd");
1759 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1762 AT_SYMLINK_NOFOLLOW |
1765 if (open_tree_fd < 0) {
1766 log_stderr("failure: sys_open_tree");
1770 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1771 log_stderr("failure: sys_mount_setattr");
1777 log_stderr("failure: fork");
1781 if (!switch_userns(attr.userns_fd, 0, 0, false))
1782 die("failure: switch_userns");
1784 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1786 die("failure: create");
1788 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1789 die("failure: check ownership");
1791 /* We're not crossing a mountpoint so this must succeed. */
1792 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1793 die("failure: create");
1795 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1796 die("failure: check ownership");
1801 if (wait_for_pid(pid))
1805 log_debug("Ran test");
1807 safe_close(attr.userns_fd);
1808 safe_close(file1_fd);
1809 safe_close(open_tree_fd);
1814 static int symlink_regular_mounts(void)
1817 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1820 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1822 log_stderr("failure: openat");
1826 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1827 log_stderr("failure: chown_r");
1831 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1834 AT_SYMLINK_NOFOLLOW |
1837 if (open_tree_fd < 0) {
1838 log_stderr("failure: sys_open_tree");
1842 if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1843 log_stderr("failure: symlinkat");
1847 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1848 log_stderr("failure: fchownat");
1852 if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1853 log_stderr("failure: fstatat");
1857 if (st.st_uid != 15000 || st.st_gid != 15000) {
1858 log_stderr("failure: compare ids");
1862 if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1863 log_stderr("failure: fstatat");
1867 if (st.st_uid != 10000 || st.st_gid != 10000) {
1868 log_stderr("failure: compare ids");
1873 log_debug("Ran test");
1875 safe_close(file1_fd);
1876 safe_close(open_tree_fd);
1881 static int symlink_idmapped_mounts(void)
1884 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1885 struct mount_attr attr = {
1886 .attr_set = MOUNT_ATTR_IDMAP,
1890 if (!caps_supported())
1893 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1895 log_stderr("failure: openat");
1899 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1900 log_stderr("failure: chown_r");
1904 /* Changing mount properties on a detached mount. */
1905 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1906 if (attr.userns_fd < 0) {
1907 log_stderr("failure: get_userns_fd");
1911 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1914 AT_SYMLINK_NOFOLLOW |
1917 if (open_tree_fd < 0) {
1918 log_stderr("failure: sys_open_tree");
1922 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1923 log_stderr("failure: sys_mount_setattr");
1929 log_stderr("failure: fork");
1933 if (!switch_fsids(10000, 10000))
1934 die("failure: switch fsids");
1937 die("failure: raise caps");
1939 if (symlinkat(FILE1, open_tree_fd, FILE2))
1940 die("failure: create");
1942 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1943 die("failure: change ownership");
1945 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1946 die("failure: check ownership");
1948 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1949 die("failure: check ownership");
1953 if (wait_for_pid(pid))
1957 log_debug("Ran test");
1959 safe_close(attr.userns_fd);
1960 safe_close(file1_fd);
1961 safe_close(open_tree_fd);
1966 static int symlink_idmapped_mounts_in_userns(void)
1969 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1970 struct mount_attr attr = {
1971 .attr_set = MOUNT_ATTR_IDMAP,
1975 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1976 log_stderr("failure: chown_r");
1980 /* Changing mount properties on a detached mount. */
1981 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1982 if (attr.userns_fd < 0) {
1983 log_stderr("failure: get_userns_fd");
1987 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1990 AT_SYMLINK_NOFOLLOW |
1993 if (open_tree_fd < 0) {
1994 log_stderr("failure: sys_open_tree");
1998 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1999 log_stderr("failure: sys_mount_setattr");
2005 log_stderr("failure: fork");
2009 if (!switch_userns(attr.userns_fd, 0, 0, false))
2010 die("failure: switch_userns");
2012 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2014 die("failure: create");
2015 safe_close(file1_fd);
2017 if (symlinkat(FILE1, open_tree_fd, FILE2))
2018 die("failure: create");
2020 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2021 die("failure: change ownership");
2023 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2024 die("failure: check ownership");
2026 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2027 die("failure: check ownership");
2032 if (wait_for_pid(pid))
2035 if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2036 log_stderr("failure: expected_uid_gid");
2040 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2041 log_stderr("failure: expected_uid_gid");
2046 log_debug("Ran test");
2048 safe_close(attr.userns_fd);
2049 safe_close(file1_fd);
2050 safe_close(open_tree_fd);
2055 /* Validate that a caller whose fsids map into the idmapped mount within it's
2056 * user namespace cannot create any device nodes.
2058 static int device_node_in_userns(void)
2061 int open_tree_fd = -EBADF;
2062 struct mount_attr attr = {
2063 .attr_set = MOUNT_ATTR_IDMAP,
2067 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2068 if (attr.userns_fd < 0) {
2069 log_stderr("failure: get_userns_fd");
2073 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2076 AT_SYMLINK_NOFOLLOW |
2079 if (open_tree_fd < 0) {
2080 log_stderr("failure: sys_open_tree");
2084 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2085 log_stderr("failure: sys_mount_setattr");
2091 log_stderr("failure: fork");
2095 if (!switch_userns(attr.userns_fd, 0, 0, false))
2096 die("failure: switch_userns");
2098 /* create character device */
2099 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2100 die("failure: create");
2105 if (wait_for_pid(pid))
2109 log_debug("Ran test");
2111 safe_close(attr.userns_fd);
2112 safe_close(open_tree_fd);
2118 /* Validate that changing file ownership works correctly on idmapped mounts. */
2119 static int expected_uid_gid_idmapped_mounts(void)
2122 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2123 struct mount_attr attr1 = {
2124 .attr_set = MOUNT_ATTR_IDMAP,
2126 struct mount_attr attr2 = {
2127 .attr_set = MOUNT_ATTR_IDMAP,
2131 if (!switch_fsids(0, 0)) {
2132 log_stderr("failure: switch_fsids");
2136 /* create regular file via open() */
2137 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2139 log_stderr("failure: openat");
2143 /* create regular file via mknod */
2144 if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2145 log_stderr("failure: mknodat");
2149 /* create character device */
2150 if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2151 log_stderr("failure: mknodat");
2155 /* create hardlink */
2156 if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2157 log_stderr("failure: linkat");
2161 /* create symlink */
2162 if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2163 log_stderr("failure: symlinkat");
2167 /* create directory */
2168 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2169 log_stderr("failure: mkdirat");
2173 /* Changing mount properties on a detached mount. */
2174 attr1.userns_fd = get_userns_fd(0, 10000, 10000);
2175 if (attr1.userns_fd < 0) {
2176 log_stderr("failure: get_userns_fd");
2180 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2183 AT_SYMLINK_NOFOLLOW |
2186 if (open_tree_fd1 < 0) {
2187 log_stderr("failure: sys_open_tree");
2191 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2192 log_stderr("failure: sys_mount_setattr");
2196 /* Validate that all files created through the image mountpoint are
2197 * owned by the callers fsuid and fsgid.
2199 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2200 log_stderr("failure: expected_uid_gid");
2203 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2204 log_stderr("failure: expected_uid_gid");
2207 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2208 log_stderr("failure: expected_uid_gid");
2211 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2212 log_stderr("failure: expected_uid_gid");
2215 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2216 log_stderr("failure: expected_uid_gid");
2219 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2220 log_stderr("failure: expected_uid_gid");
2223 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2224 log_stderr("failure: expected_uid_gid");
2228 /* Validate that all files are owned by the uid and gid specified in
2229 * the idmapping of the mount they are accessed from.
2231 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2232 log_stderr("failure: expected_uid_gid");
2235 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2236 log_stderr("failure: expected_uid_gid");
2239 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2240 log_stderr("failure: expected_uid_gid");
2243 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2244 log_stderr("failure: expected_uid_gid");
2247 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2248 log_stderr("failure: expected_uid_gid");
2251 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2252 log_stderr("failure: expected_uid_gid");
2255 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2256 log_stderr("failure: expected_uid_gid");
2260 /* Changing mount properties on a detached mount. */
2261 attr2.userns_fd = get_userns_fd(0, 30000, 2001);
2262 if (attr2.userns_fd < 0) {
2263 log_stderr("failure: get_userns_fd");
2267 open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2270 AT_SYMLINK_NOFOLLOW |
2273 if (open_tree_fd2 < 0) {
2274 log_stderr("failure: sys_open_tree");
2278 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2279 log_stderr("failure: sys_mount_setattr");
2283 /* Validate that all files are owned by the uid and gid specified in
2284 * the idmapping of the mount they are accessed from.
2286 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2287 log_stderr("failure: expected_uid_gid");
2290 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2291 log_stderr("failure: expected_uid_gid");
2294 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2295 log_stderr("failure: expected_uid_gid");
2298 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2299 log_stderr("failure: expected_uid_gid");
2302 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2303 log_stderr("failure: expected_uid_gid");
2306 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2307 log_stderr("failure: expected_uid_gid");
2310 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2311 log_stderr("failure: expected_uid_gid");
2315 /* Change ownership throught original image mountpoint. */
2316 if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2317 log_stderr("failure: fchownat");
2320 if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2321 log_stderr("failure: fchownat");
2324 if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2325 log_stderr("failure: fchownat");
2328 if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2329 log_stderr("failure: fchownat");
2332 if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2333 log_stderr("failure: fchownat");
2336 if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2337 log_stderr("failure: fchownat");
2340 if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2341 log_stderr("failure: fchownat");
2345 /* Check ownership through original mount. */
2346 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 2000, 2000)) {
2347 log_stderr("failure: expected_uid_gid");
2350 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2351 log_stderr("failure: expected_uid_gid");
2354 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2355 log_stderr("failure: expected_uid_gid");
2358 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2359 log_stderr("failure: expected_uid_gid");
2362 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2363 log_stderr("failure: expected_uid_gid");
2366 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2367 log_stderr("failure: expected_uid_gid");
2370 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2371 log_stderr("failure: expected_uid_gid");
2375 /* Check ownership through first idmapped mount. */
2376 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 12000, 12000)) {
2377 log_stderr("failure:expected_uid_gid ");
2380 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2381 log_stderr("failure: expected_uid_gid");
2384 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2385 log_stderr("failure: expected_uid_gid");
2388 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2389 log_stderr("failure: expected_uid_gid");
2392 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2393 log_stderr("failure: expected_uid_gid");
2396 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2397 log_stderr("failure:expected_uid_gid ");
2400 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2401 log_stderr("failure: expected_uid_gid");
2405 /* Check ownership through second idmapped mount. */
2406 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 32000, 32000)) {
2407 log_stderr("failure: expected_uid_gid");
2410 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2411 log_stderr("failure: expected_uid_gid");
2414 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2415 log_stderr("failure: expected_uid_gid");
2418 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2419 log_stderr("failure: expected_uid_gid");
2422 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2423 log_stderr("failure: expected_uid_gid");
2426 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2427 log_stderr("failure: expected_uid_gid");
2430 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2431 log_stderr("failure: expected_uid_gid");
2437 log_stderr("failure: fork");
2441 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2442 die("failure: switch_userns");
2444 if (!fchownat(t_dir1_fd, FILE1, 1000, 1000, 0))
2445 die("failure: fchownat");
2446 if (!fchownat(t_dir1_fd, FILE2, 1000, 1000, 0))
2447 die("failure: fchownat");
2448 if (!fchownat(t_dir1_fd, HARDLINK1, 1000, 1000, 0))
2449 die("failure: fchownat");
2450 if (!fchownat(t_dir1_fd, CHRDEV1, 1000, 1000, 0))
2451 die("failure: fchownat");
2452 if (!fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2453 die("failure: fchownat");
2454 if (!fchownat(t_dir1_fd, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2455 die("failure: fchownat");
2456 if (!fchownat(t_dir1_fd, DIR1, 1000, 1000, AT_EMPTY_PATH))
2457 die("failure: fchownat");
2459 if (!fchownat(open_tree_fd2, FILE1, 1000, 1000, 0))
2460 die("failure: fchownat");
2461 if (!fchownat(open_tree_fd2, FILE2, 1000, 1000, 0))
2462 die("failure: fchownat");
2463 if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
2464 die("failure: fchownat");
2465 if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
2466 die("failure: fchownat");
2467 if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2468 die("failure: fchownat");
2469 if (!fchownat(open_tree_fd2, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2470 die("failure: fchownat");
2471 if (!fchownat(open_tree_fd2, DIR1, 1000, 1000, AT_EMPTY_PATH))
2472 die("failure: fchownat");
2474 if (fchownat(open_tree_fd1, FILE1, 1000, 1000, 0))
2475 die("failure: fchownat");
2476 if (fchownat(open_tree_fd1, FILE2, 1000, 1000, 0))
2477 die("failure: fchownat");
2478 if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
2479 die("failure: fchownat");
2480 if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
2481 die("failure: fchownat");
2482 if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2483 die("failure: fchownat");
2484 if (fchownat(open_tree_fd1, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2485 die("failure: fchownat");
2486 if (fchownat(open_tree_fd1, DIR1, 1000, 1000, AT_EMPTY_PATH))
2487 die("failure: fchownat");
2489 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2490 die("failure: expected_uid_gid");
2491 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2492 die("failure: expected_uid_gid");
2493 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2494 die("failure: expected_uid_gid");
2495 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2496 die("failure: expected_uid_gid");
2497 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2498 die("failure: expected_uid_gid");
2499 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2500 die("failure: expected_uid_gid");
2501 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2502 die("failure: expected_uid_gid");
2504 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, t_overflowuid, t_overflowgid))
2505 die("failure: expected_uid_gid");
2506 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, t_overflowuid, t_overflowgid))
2507 die("failure: expected_uid_gid");
2508 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2509 die("failure: expected_uid_gid");
2510 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2511 die("failure: expected_uid_gid");
2512 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2513 die("failure: expected_uid_gid");
2514 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2515 die("failure: expected_uid_gid");
2516 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, t_overflowuid, t_overflowgid))
2517 die("failure: expected_uid_gid");
2519 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 1000, 1000))
2520 die("failure: expected_uid_gid");
2521 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 1000, 1000))
2522 die("failure: expected_uid_gid");
2523 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
2524 die("failure: expected_uid_gid");
2525 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
2526 die("failure: expected_uid_gid");
2527 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2528 die("failure: expected_uid_gid");
2529 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 1000, 1000))
2530 die("failure: expected_uid_gid");
2531 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 1000, 1000))
2532 die("failure: expected_uid_gid");
2537 if (wait_for_pid(pid))
2540 /* Check ownership through original mount. */
2541 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 1000, 1000)) {
2542 log_stderr("failure: expected_uid_gid");
2545 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2546 log_stderr("failure: expected_uid_gid");
2549 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2550 log_stderr("failure: expected_uid_gid");
2553 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2554 log_stderr("failure: expected_uid_gid");
2557 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2558 log_stderr("failure: expected_uid_gid");
2561 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2562 log_stderr("failure: expected_uid_gid");
2565 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2566 log_stderr("failure: expected_uid_gid");
2570 /* Check ownership through first idmapped mount. */
2571 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 11000, 11000)) {
2572 log_stderr("failure: expected_uid_gid");
2575 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2576 log_stderr("failure: expected_uid_gid");
2579 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2580 log_stderr("failure: expected_uid_gid");
2583 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2584 log_stderr("failure: expected_uid_gid");
2587 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2588 log_stderr("failure: expected_uid_gid");
2591 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2592 log_stderr("failure: expected_uid_gid");
2595 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2596 log_stderr("failure: expected_uid_gid");
2600 /* Check ownership through second idmapped mount. */
2601 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 31000, 31000)) {
2602 log_stderr("failure: expected_uid_gid");
2605 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2606 log_stderr("failure: expected_uid_gid");
2609 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2610 log_stderr("failure: expected_uid_gid");
2613 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2614 log_stderr("failure: expected_uid_gid");
2617 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2618 log_stderr("failure: expected_uid_gid");
2621 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2622 log_stderr("failure: expected_uid_gid");
2625 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2626 log_stderr("failure: expected_uid_gid");
2632 log_stderr("failure: fork");
2636 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2637 die("failure: switch_userns");
2639 if (!fchownat(t_dir1_fd, FILE1, 0, 0, 0))
2640 die("failure: fchownat");
2641 if (!fchownat(t_dir1_fd, FILE2, 0, 0, 0))
2642 die("failure: fchownat");
2643 if (!fchownat(t_dir1_fd, HARDLINK1, 0, 0, 0))
2644 die("failure: fchownat");
2645 if (!fchownat(t_dir1_fd, CHRDEV1, 0, 0, 0))
2646 die("failure: fchownat");
2647 if (!fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2648 die("failure: fchownat");
2649 if (!fchownat(t_dir1_fd, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2650 die("failure: fchownat");
2651 if (!fchownat(t_dir1_fd, DIR1, 0, 0, AT_EMPTY_PATH))
2652 die("failure: fchownat");
2654 if (!fchownat(open_tree_fd1, FILE1, 0, 0, 0))
2655 die("failure: fchownat");
2656 if (!fchownat(open_tree_fd1, FILE2, 0, 0, 0))
2657 die("failure: fchownat");
2658 if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
2659 die("failure: fchownat");
2660 if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
2661 die("failure: fchownat");
2662 if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2663 die("failure: fchownat");
2664 if (!fchownat(open_tree_fd1, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2665 die("failure: fchownat");
2666 if (!fchownat(open_tree_fd1, DIR1, 0, 0, AT_EMPTY_PATH))
2667 die("failure: fchownat");
2669 if (fchownat(open_tree_fd2, FILE1, 0, 0, 0))
2670 die("failure: fchownat");
2671 if (fchownat(open_tree_fd2, FILE2, 0, 0, 0))
2672 die("failure: fchownat");
2673 if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
2674 die("failure: fchownat");
2675 if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
2676 die("failure: fchownat");
2677 if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2678 die("failure: fchownat");
2679 if (fchownat(open_tree_fd2, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2680 die("failure: fchownat");
2681 if (fchownat(open_tree_fd2, DIR1, 0, 0, AT_EMPTY_PATH))
2682 die("failure: fchownat");
2684 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2685 die("failure: expected_uid_gid");
2686 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2687 die("failure: expected_uid_gid");
2688 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2689 die("failure: expected_uid_gid");
2690 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2691 die("failure: expected_uid_gid");
2692 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2693 die("failure: expected_uid_gid");
2694 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2695 die("failure: expected_uid_gid");
2696 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2697 die("failure: expected_uid_gid");
2699 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, t_overflowuid, t_overflowgid))
2700 die("failure: expected_uid_gid");
2701 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, t_overflowuid, t_overflowgid))
2702 die("failure: expected_uid_gid");
2703 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2704 die("failure: expected_uid_gid");
2705 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2706 die("failure: expected_uid_gid");
2707 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2708 die("failure: expected_uid_gid");
2709 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2710 die("failure: expected_uid_gid");
2711 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, t_overflowuid, t_overflowgid))
2712 die("failure: expected_uid_gid");
2714 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 0, 0))
2715 die("failure: expected_uid_gid");
2716 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 0, 0))
2717 die("failure: expected_uid_gid");
2718 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
2719 die("failure: expected_uid_gid");
2720 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
2721 die("failure: expected_uid_gid");
2722 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2723 die("failure: expected_uid_gid");
2724 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 0, 0))
2725 die("failure: expected_uid_gid");
2726 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 0, 0))
2727 die("failure: expected_uid_gid");
2732 if (wait_for_pid(pid))
2735 /* Check ownership through original mount. */
2736 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2737 log_stderr("failure: expected_uid_gid");
2740 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2741 log_stderr("failure: expected_uid_gid");
2744 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2745 log_stderr("failure: expected_uid_gid");
2748 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2749 log_stderr("failure: expected_uid_gid");
2752 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2753 log_stderr("failure: expected_uid_gid");
2756 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2757 log_stderr("failure: expected_uid_gid");
2760 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2761 log_stderr("failure: expected_uid_gid");
2765 /* Check ownership through first idmapped mount. */
2766 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2767 log_stderr("failure: expected_uid_gid");
2770 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2771 log_stderr("failure: expected_uid_gid");
2774 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2775 log_stderr("failure: expected_uid_gid");
2778 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2779 log_stderr("failure: expected_uid_gid");
2782 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2783 log_stderr("failure: expected_uid_gid");
2786 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2787 log_stderr("failure: expected_uid_gid");
2790 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2791 log_stderr("failure: expected_uid_gid");
2795 /* Check ownership through second idmapped mount. */
2796 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2797 log_stderr("failure: expected_uid_gid");
2800 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2801 log_stderr("failure: expected_uid_gid");
2804 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2805 log_stderr("failure: expected_uid_gid");
2808 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2809 log_stderr("failure: expected_uid_gid");
2812 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2813 log_stderr("failure: expected_uid_gid");
2816 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2817 log_stderr("failure: expected_uid_gid");
2820 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2821 log_stderr("failure: expected_uid_gid");
2826 log_debug("Ran test");
2828 safe_close(attr1.userns_fd);
2829 safe_close(attr2.userns_fd);
2830 safe_close(file1_fd);
2831 safe_close(open_tree_fd1);
2832 safe_close(open_tree_fd2);
2837 static int fscaps(void)
2840 int file1_fd = -EBADF;
2841 struct mount_attr attr = {
2842 .attr_set = MOUNT_ATTR_IDMAP,
2846 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2848 log_stderr("failure: openat");
2852 /* Skip if vfs caps are unsupported. */
2853 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2856 /* Changing mount properties on a detached mount. */
2857 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2858 if (attr.userns_fd < 0) {
2859 log_stderr("failure: get_userns_fd");
2863 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
2864 log_stderr("failure: expected_dummy_vfs_caps_uid");
2870 log_stderr("failure: fork");
2874 if (!switch_userns(attr.userns_fd, 0, 0, false))
2875 die("failure: switch_userns");
2878 * On kernels before 5.12 this would succeed and return the
2879 * unconverted caps. Then - for whatever reason - this behavior
2880 * got changed and since 5.12 EOVERFLOW is returned when the
2881 * rootid stored alongside the vfs caps does not map to uid 0 in
2882 * the caller's user namespace.
2884 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
2885 die("failure: expected_dummy_vfs_caps_uid");
2890 if (wait_for_pid(pid))
2893 if (fremovexattr(file1_fd, "security.capability")) {
2894 log_stderr("failure: fremovexattr");
2897 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2898 log_stderr("failure: expected_dummy_vfs_caps_uid");
2901 if (errno != ENODATA) {
2902 log_stderr("failure: errno");
2906 if (set_dummy_vfs_caps(file1_fd, 0, 10000)) {
2907 log_stderr("failure: set_dummy_vfs_caps");
2911 if (!expected_dummy_vfs_caps_uid(file1_fd, 10000)) {
2912 log_stderr("failure: expected_dummy_vfs_caps_uid");
2918 log_stderr("failure: fork");
2922 if (!switch_userns(attr.userns_fd, 0, 0, false))
2923 die("failure: switch_userns");
2925 if (!expected_dummy_vfs_caps_uid(file1_fd, 0))
2926 die("failure: expected_dummy_vfs_caps_uid");
2931 if (wait_for_pid(pid))
2934 if (fremovexattr(file1_fd, "security.capability")) {
2935 log_stderr("failure: fremovexattr");
2938 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2939 log_stderr("failure: expected_dummy_vfs_caps_uid");
2942 if (errno != ENODATA) {
2943 log_stderr("failure: errno");
2948 log_debug("Ran test");
2950 safe_close(attr.userns_fd);
2951 safe_close(file1_fd);
2956 static int fscaps_idmapped_mounts(void)
2959 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
2960 struct mount_attr attr = {
2961 .attr_set = MOUNT_ATTR_IDMAP,
2965 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2967 log_stderr("failure: openat");
2971 /* Skip if vfs caps are unsupported. */
2972 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2975 if (fremovexattr(file1_fd, "security.capability")) {
2976 log_stderr("failure: fremovexattr");
2980 /* Changing mount properties on a detached mount. */
2981 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2982 if (attr.userns_fd < 0) {
2983 log_stderr("failure: get_userns_fd");
2987 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2990 AT_SYMLINK_NOFOLLOW |
2993 if (open_tree_fd < 0) {
2994 log_stderr("failure: sys_open_tree");
2998 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2999 log_stderr("failure: sys_mount_setattr");
3003 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3004 if (file1_fd2 < 0) {
3005 log_stderr("failure: openat");
3009 if (!set_dummy_vfs_caps(file1_fd2, 0, 1000)) {
3010 log_stderr("failure: set_dummy_vfs_caps");
3014 if (set_dummy_vfs_caps(file1_fd2, 0, 10000)) {
3015 log_stderr("failure: set_dummy_vfs_caps");
3019 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3020 log_stderr("failure: expected_dummy_vfs_caps_uid");
3024 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3025 log_stderr("failure: expected_dummy_vfs_caps_uid");
3031 log_stderr("failure: fork");
3035 if (!switch_userns(attr.userns_fd, 0, 0, false))
3036 die("failure: switch_userns");
3038 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3039 die("failure: expected_dummy_vfs_caps_uid");
3044 if (wait_for_pid(pid))
3047 if (fremovexattr(file1_fd2, "security.capability")) {
3048 log_stderr("failure: fremovexattr");
3051 if (expected_dummy_vfs_caps_uid(file1_fd2, -1)) {
3052 log_stderr("failure: expected_dummy_vfs_caps_uid");
3055 if (errno != ENODATA) {
3056 log_stderr("failure: errno");
3060 if (set_dummy_vfs_caps(file1_fd2, 0, 12000)) {
3061 log_stderr("failure: set_dummy_vfs_caps");
3065 if (!expected_dummy_vfs_caps_uid(file1_fd2, 12000)) {
3066 log_stderr("failure: expected_dummy_vfs_caps_uid");
3070 if (!expected_dummy_vfs_caps_uid(file1_fd, 2000)) {
3071 log_stderr("failure: expected_dummy_vfs_caps_uid");
3077 log_stderr("failure: fork");
3081 if (!switch_userns(attr.userns_fd, 0, 0, false))
3082 die("failure: switch_userns");
3084 if (!expected_dummy_vfs_caps_uid(file1_fd2, 2000))
3085 die("failure: expected_dummy_vfs_caps_uid");
3090 if (wait_for_pid(pid))
3094 log_debug("Ran test");
3096 safe_close(attr.userns_fd);
3097 safe_close(file1_fd);
3098 safe_close(file1_fd2);
3099 safe_close(open_tree_fd);
3104 static int fscaps_idmapped_mounts_in_userns(void)
3107 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3108 struct mount_attr attr = {
3109 .attr_set = MOUNT_ATTR_IDMAP,
3113 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3115 log_stderr("failure: openat");
3119 /* Skip if vfs caps are unsupported. */
3120 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3123 if (fremovexattr(file1_fd, "security.capability")) {
3124 log_stderr("failure: fremovexattr");
3128 /* Changing mount properties on a detached mount. */
3129 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3130 if (attr.userns_fd < 0) {
3131 log_stderr("failure: get_userns_fd");
3135 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3138 AT_SYMLINK_NOFOLLOW |
3141 if (open_tree_fd < 0) {
3142 log_stderr("failure: sys_open_tree");
3146 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3147 log_stderr("failure: sys_mount_setattr");
3151 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3152 if (file1_fd2 < 0) {
3153 log_stderr("failure: openat");
3159 log_stderr("failure: fork");
3163 if (!switch_userns(attr.userns_fd, 0, 0, false))
3164 die("failure: switch_userns");
3166 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3167 die("failure: expected_dummy_vfs_caps_uid");
3168 if (errno != ENODATA)
3169 die("failure: errno");
3171 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3172 die("failure: set_dummy_vfs_caps");
3174 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3175 die("failure: expected_dummy_vfs_caps_uid");
3177 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
3178 die("failure: expected_dummy_vfs_caps_uid");
3183 if (wait_for_pid(pid))
3186 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
3187 log_stderr("failure: expected_dummy_vfs_caps_uid");
3192 log_debug("Ran test");
3194 safe_close(attr.userns_fd);
3195 safe_close(file1_fd);
3196 safe_close(file1_fd2);
3197 safe_close(open_tree_fd);
3202 static int fscaps_idmapped_mounts_in_userns_separate_userns(void)
3205 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3206 struct mount_attr attr = {
3207 .attr_set = MOUNT_ATTR_IDMAP,
3211 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3213 log_stderr("failure: openat");
3217 /* Skip if vfs caps are unsupported. */
3218 if (set_dummy_vfs_caps(file1_fd, 0, 1000)) {
3219 log_stderr("failure: set_dummy_vfs_caps");
3223 if (fremovexattr(file1_fd, "security.capability")) {
3224 log_stderr("failure: fremovexattr");
3228 /* change ownership of all files to uid 0 */
3229 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3230 log_stderr("failure: chown_r");
3234 /* Changing mount properties on a detached mount. */
3235 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
3236 if (attr.userns_fd < 0) {
3237 log_stderr("failure: get_userns_fd");
3241 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3244 AT_SYMLINK_NOFOLLOW |
3247 if (open_tree_fd < 0) {
3248 log_stderr("failure: sys_open_tree");
3252 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3253 log_stderr("failure: sys_mount_setattr");
3257 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3258 if (file1_fd2 < 0) {
3259 log_stderr("failure: openat");
3265 log_stderr("failure: fork");
3271 userns_fd = get_userns_fd(0, 10000, 10000);
3273 die("failure: get_userns_fd");
3275 if (!switch_userns(userns_fd, 0, 0, false))
3276 die("failure: switch_userns");
3278 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3279 die("failure: set fscaps");
3281 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3282 die("failure: expected_dummy_vfs_caps_uid");
3284 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000) && errno != EOVERFLOW)
3285 die("failure: expected_dummy_vfs_caps_uid");
3290 if (wait_for_pid(pid))
3293 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000)) {
3294 log_stderr("failure: expected_dummy_vfs_caps_uid");
3300 log_stderr("failure: fork");
3306 userns_fd = get_userns_fd(0, 10000, 10000);
3308 die("failure: get_userns_fd");
3310 if (!switch_userns(userns_fd, 0, 0, false))
3311 die("failure: switch_userns");
3313 if (fremovexattr(file1_fd2, "security.capability"))
3314 die("failure: fremovexattr");
3315 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3316 die("failure: expected_dummy_vfs_caps_uid");
3317 if (errno != ENODATA)
3318 die("failure: errno");
3320 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3321 die("failure: set_dummy_vfs_caps");
3323 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3324 die("failure: expected_dummy_vfs_caps_uid");
3326 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000) && errno != EOVERFLOW)
3327 die("failure: expected_dummy_vfs_caps_uid");
3332 if (wait_for_pid(pid))
3335 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000)) {
3336 log_stderr("failure: expected_dummy_vfs_caps_uid");
3341 log_debug("Ran test");
3343 safe_close(attr.userns_fd);
3344 safe_close(file1_fd);
3345 safe_close(file1_fd2);
3346 safe_close(open_tree_fd);
3351 /* Validate that when the IDMAP_MOUNT_TEST_RUN_SETID environment variable is set
3352 * to 1 that we are executed with setid privileges and if set to 0 we are not.
3353 * If the env variable isn't set the tests are not run.
3355 static void __attribute__((constructor)) setuid_rexec(void)
3357 const char *expected_euid_str, *expected_egid_str, *rexec;
3359 rexec = getenv("IDMAP_MOUNT_TEST_RUN_SETID");
3360 /* This is a regular test-suite run. */
3364 expected_euid_str = getenv("EXPECTED_EUID");
3365 expected_egid_str = getenv("EXPECTED_EGID");
3367 if (expected_euid_str && expected_egid_str) {
3368 uid_t expected_euid;
3369 gid_t expected_egid;
3371 expected_euid = atoi(expected_euid_str);
3372 expected_egid = atoi(expected_egid_str);
3374 if (strcmp(rexec, "1") == 0) {
3375 /* we're expecting to run setid */
3376 if ((getuid() != geteuid()) && (expected_euid == geteuid()) &&
3377 (getgid() != getegid()) && (expected_egid == getegid()))
3379 } else if (strcmp(rexec, "0") == 0) {
3380 /* we're expecting to not run setid */
3381 if ((getuid() == geteuid()) && (expected_euid == geteuid()) &&
3382 (getgid() == getegid()) && (expected_egid == getegid()))
3385 die("failure: non-setid");
3392 /* Validate that setid transitions are handled correctly. */
3393 static int setid_binaries(void)
3396 int file1_fd = -EBADF, exec_fd = -EBADF;
3399 /* create a file to be used as setuid binary */
3400 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3402 log_stderr("failure: openat");
3406 /* open our own executable */
3407 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3409 log_stderr("failure: openat");
3413 /* copy our own executable into the file we created */
3414 if (fd_to_fd(exec_fd, file1_fd)) {
3415 log_stderr("failure: fd_to_fd");
3419 /* chown the file to the uid and gid we want to assume */
3420 if (fchown(file1_fd, 5000, 5000)) {
3421 log_stderr("failure: fchown");
3425 /* set the setid bits and grant execute permissions to the group */
3426 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3427 log_stderr("failure: fchmod");
3431 /* Verify that the sid bits got raised. */
3432 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3433 log_stderr("failure: is_setid");
3437 safe_close(exec_fd);
3438 safe_close(file1_fd);
3440 /* Verify we run setid binary as uid and gid 5000 from the original
3445 log_stderr("failure: fork");
3449 static char *envp[] = {
3450 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3451 "EXPECTED_EUID=5000",
3452 "EXPECTED_EGID=5000",
3455 static char *argv[] = {
3459 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 5000, 5000))
3460 die("failure: expected_uid_gid");
3462 sys_execveat(t_dir1_fd, FILE1, argv, envp, 0);
3463 die("failure: sys_execveat");
3467 if (wait_for_pid(pid))
3471 log_debug("Ran test");
3477 /* Validate that setid transitions are handled correctly on idmapped mounts. */
3478 static int setid_binaries_idmapped_mounts(void)
3481 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3482 struct mount_attr attr = {
3483 .attr_set = MOUNT_ATTR_IDMAP,
3487 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3488 log_stderr("failure: mkdirat");
3492 /* create a file to be used as setuid binary */
3493 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3495 log_stderr("failure: openat");
3499 /* open our own executable */
3500 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3502 log_stderr("failure:openat ");
3506 /* copy our own executable into the file we created */
3507 if (fd_to_fd(exec_fd, file1_fd)) {
3508 log_stderr("failure: fd_to_fd");
3512 /* chown the file to the uid and gid we want to assume */
3513 if (fchown(file1_fd, 5000, 5000)) {
3514 log_stderr("failure: fchown");
3518 /* set the setid bits and grant execute permissions to the group */
3519 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3520 log_stderr("failure: fchmod");
3524 /* Verify that the sid bits got raised. */
3525 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3526 log_stderr("failure: is_setid");
3530 safe_close(exec_fd);
3531 safe_close(file1_fd);
3533 /* Changing mount properties on a detached mount. */
3534 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3535 if (attr.userns_fd < 0) {
3536 log_stderr("failure: get_userns_fd");
3540 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3543 AT_SYMLINK_NOFOLLOW |
3546 if (open_tree_fd < 0) {
3547 log_stderr("failure: sys_open_tree");
3551 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3552 log_stderr("failure: sys_mount_setattr");
3556 /* A detached mount will have an anonymous mount namespace attached to
3557 * it. This means that we can't execute setid binaries on a detached
3558 * mount because the mnt_may_suid() helper will fail the check_mount()
3559 * part of its check which compares the caller's mount namespace to the
3560 * detached mount's mount namespace. Since by definition an anonymous
3561 * mount namespace is not equale to any mount namespace currently in
3562 * use this can't work. So attach the mount to the filesystem first
3563 * before performing this check.
3565 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3566 log_stderr("failure: sys_move_mount");
3570 /* Verify we run setid binary as uid and gid 10000 from idmapped mount mount. */
3573 log_stderr("failure: fork");
3577 static char *envp[] = {
3578 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3579 "EXPECTED_EUID=15000",
3580 "EXPECTED_EGID=15000",
3583 static char *argv[] = {
3587 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 15000, 15000))
3588 die("failure: expected_uid_gid");
3590 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3591 die("failure: sys_execveat");
3596 if (wait_for_pid(pid))
3600 log_debug("Ran test");
3602 safe_close(exec_fd);
3603 safe_close(file1_fd);
3604 safe_close(open_tree_fd);
3606 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3607 sys_umount2(t_buf, MNT_DETACH);
3608 rm_r(t_mnt_fd, DIR1);
3613 /* Validate that setid transitions are handled correctly on idmapped mounts
3614 * running in a user namespace where the uid and gid of the setid binary have no
3617 static int setid_binaries_idmapped_mounts_in_userns(void)
3620 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3621 struct mount_attr attr = {
3622 .attr_set = MOUNT_ATTR_IDMAP,
3626 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3627 log_stderr("failure: ");
3631 /* create a file to be used as setuid binary */
3632 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3634 log_stderr("failure: openat");
3638 /* open our own executable */
3639 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3641 log_stderr("failure: openat");
3645 /* copy our own executable into the file we created */
3646 if (fd_to_fd(exec_fd, file1_fd)) {
3647 log_stderr("failure: fd_to_fd");
3651 safe_close(exec_fd);
3653 /* chown the file to the uid and gid we want to assume */
3654 if (fchown(file1_fd, 5000, 5000)) {
3655 log_stderr("failure: fchown");
3659 /* set the setid bits and grant execute permissions to the group */
3660 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3661 log_stderr("failure: fchmod");
3665 /* Verify that the sid bits got raised. */
3666 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3667 log_stderr("failure: is_setid");
3671 safe_close(file1_fd);
3673 /* Changing mount properties on a detached mount. */
3674 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3675 if (attr.userns_fd < 0) {
3676 log_stderr("failure: get_userns_fd");
3680 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3683 AT_SYMLINK_NOFOLLOW |
3686 if (open_tree_fd < 0) {
3687 log_stderr("failure: sys_open_tree");
3691 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3692 log_stderr("failure: sys_mount_setattr");
3696 /* A detached mount will have an anonymous mount namespace attached to
3697 * it. This means that we can't execute setid binaries on a detached
3698 * mount because the mnt_may_suid() helper will fail the check_mount()
3699 * part of its check which compares the caller's mount namespace to the
3700 * detached mount's mount namespace. Since by definition an anonymous
3701 * mount namespace is not equale to any mount namespace currently in
3702 * use this can't work. So attach the mount to the filesystem first
3703 * before performing this check.
3705 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3706 log_stderr("failure: sys_move_mount");
3712 log_stderr("failure: fork");
3716 static char *envp[] = {
3717 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3718 "EXPECTED_EUID=5000",
3719 "EXPECTED_EGID=5000",
3722 static char *argv[] = {
3726 if (!switch_userns(attr.userns_fd, 0, 0, false))
3727 die("failure: switch_userns");
3729 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
3730 die("failure: expected_uid_gid");
3732 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3733 die("failure: sys_execveat");
3738 if (wait_for_pid(pid)) {
3739 log_stderr("failure: wait_for_pid");
3743 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3745 log_stderr("failure: openat");
3749 /* chown the file to the uid and gid we want to assume */
3750 if (fchown(file1_fd, 0, 0)) {
3751 log_stderr("failure: fchown");
3755 /* set the setid bits and grant execute permissions to the group */
3756 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3757 log_stderr("failure: fchmod");
3761 /* Verify that the sid bits got raised. */
3762 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3763 log_stderr("failure: is_setid");
3767 safe_close(file1_fd);
3771 log_stderr("failure: fork");
3775 static char *envp[] = {
3776 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3781 static char *argv[] = {
3785 if (!caps_supported()) {
3786 log_debug("skip: capability library not installed");
3790 if (!switch_userns(attr.userns_fd, 5000, 5000, true))
3791 die("failure: switch_userns");
3793 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
3794 die("failure: expected_uid_gid");
3796 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3797 die("failure: sys_execveat");
3802 if (wait_for_pid(pid)) {
3803 log_stderr("failure: wait_for_pid");
3807 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3809 log_stderr("failure: openat");
3813 /* chown the file to the uid and gid we want to assume */
3814 if (fchown(file1_fd, 30000, 30000)) {
3815 log_stderr("failure: fchown");
3819 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
3820 log_stderr("failure: fchmod");
3824 /* Verify that the sid bits got raised. */
3825 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3826 log_stderr("failure: is_setid");
3830 safe_close(file1_fd);
3832 /* Verify that we can't assume a uid and gid of a setid binary for which
3833 * we have no mapping in our user namespace.
3837 log_stderr("failure: fork");
3841 char expected_euid[100];
3842 char expected_egid[100];
3843 static char *envp[4] = {
3849 static char *argv[] = {
3853 if (!switch_userns(attr.userns_fd, 0, 0, false))
3854 die("failure: switch_userns");
3856 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
3857 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
3858 envp[1] = expected_euid;
3859 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
3860 envp[2] = expected_egid;
3862 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
3863 die("failure: expected_uid_gid");
3865 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3866 die("failure: sys_execveat");
3871 if (wait_for_pid(pid)) {
3872 log_stderr("failure: wait_for_pid");
3877 log_debug("Ran test");
3879 safe_close(attr.userns_fd);
3880 safe_close(exec_fd);
3881 safe_close(file1_fd);
3882 safe_close(open_tree_fd);
3884 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3885 sys_umount2(t_buf, MNT_DETACH);
3886 rm_r(t_mnt_fd, DIR1);
3891 /* Validate that setid transitions are handled correctly on idmapped mounts
3892 * running in a user namespace where the uid and gid of the setid binary have no
3895 static int setid_binaries_idmapped_mounts_in_userns_separate_userns(void)
3898 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3899 struct mount_attr attr = {
3900 .attr_set = MOUNT_ATTR_IDMAP,
3904 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3905 log_stderr("failure: mkdirat");
3909 /* create a file to be used as setuid binary */
3910 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3912 log_stderr("failure: openat");
3916 /* open our own executable */
3917 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3919 log_stderr("failure: openat");
3923 /* copy our own executable into the file we created */
3924 if (fd_to_fd(exec_fd, file1_fd)) {
3925 log_stderr("failure: fd_to_fd");
3929 safe_close(exec_fd);
3931 /* change ownership of all files to uid 0 */
3932 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3933 log_stderr("failure: chown_r");
3937 /* chown the file to the uid and gid we want to assume */
3938 if (fchown(file1_fd, 25000, 25000)) {
3939 log_stderr("failure: fchown");
3943 /* set the setid bits and grant execute permissions to the group */
3944 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3945 log_stderr("failure: fchmod");
3949 /* Verify that the sid bits got raised. */
3950 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3951 log_stderr("failure: is_setid");
3955 safe_close(file1_fd);
3957 /* Changing mount properties on a detached mount. */
3958 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
3959 if (attr.userns_fd < 0) {
3960 log_stderr("failure: get_userns_fd");
3964 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3967 AT_SYMLINK_NOFOLLOW |
3970 if (open_tree_fd < 0) {
3971 log_stderr("failure: sys_open_tree");
3975 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3976 log_stderr("failure: sys_mount_setattr");
3980 /* A detached mount will have an anonymous mount namespace attached to
3981 * it. This means that we can't execute setid binaries on a detached
3982 * mount because the mnt_may_suid() helper will fail the check_mount()
3983 * part of its check which compares the caller's mount namespace to the
3984 * detached mount's mount namespace. Since by definition an anonymous
3985 * mount namespace is not equale to any mount namespace currently in
3986 * use this can't work. So attach the mount to the filesystem first
3987 * before performing this check.
3989 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3990 log_stderr("failure: sys_move_mount");
3996 log_stderr("failure: fork");
4001 static char *envp[] = {
4002 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4003 "EXPECTED_EUID=5000",
4004 "EXPECTED_EGID=5000",
4007 static char *argv[] = {
4011 userns_fd = get_userns_fd(0, 10000, 10000);
4013 die("failure: get_userns_fd");
4015 if (!switch_userns(userns_fd, 0, 0, false))
4016 die("failure: switch_userns");
4018 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
4019 die("failure: expected_uid_gid");
4021 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4022 die("failure: sys_execveat");
4027 if (wait_for_pid(pid)) {
4028 log_stderr("failure: wait_for_pid");
4032 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4034 log_stderr("failure: openat");
4038 /* chown the file to the uid and gid we want to assume */
4039 if (fchown(file1_fd, 20000, 20000)) {
4040 log_stderr("failure: fchown");
4044 /* set the setid bits and grant execute permissions to the group */
4045 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4046 log_stderr("failure: fchmod");
4050 /* Verify that the sid bits got raised. */
4051 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4052 log_stderr("failure: is_setid");
4056 safe_close(file1_fd);
4060 log_stderr("failure: fork");
4065 static char *envp[] = {
4066 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4071 static char *argv[] = {
4075 userns_fd = get_userns_fd(0, 10000, 10000);
4077 die("failure: get_userns_fd");
4079 if (!caps_supported()) {
4080 log_debug("skip: capability library not installed");
4084 if (!switch_userns(userns_fd, 1000, 1000, true))
4085 die("failure: switch_userns");
4087 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
4088 die("failure: expected_uid_gid");
4090 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4091 die("failure: sys_execveat");
4095 if (wait_for_pid(pid)) {
4096 log_stderr("failure: wait_for_pid");
4100 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4102 log_stderr("failure: openat");
4106 /* chown the file to the uid and gid we want to assume */
4107 if (fchown(file1_fd, 0, 0)) {
4108 log_stderr("failure: fchown");
4112 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
4113 log_stderr("failure: fchmod");
4117 /* Verify that the sid bits got raised. */
4118 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4119 log_stderr("failure: is_setid");
4123 safe_close(file1_fd);
4125 /* Verify that we can't assume a uid and gid of a setid binary for
4126 * which we have no mapping in our user namespace.
4130 log_stderr("failure: fork");
4135 char expected_euid[100];
4136 char expected_egid[100];
4137 static char *envp[4] = {
4143 static char *argv[] = {
4147 userns_fd = get_userns_fd(0, 10000, 10000);
4149 die("failure: get_userns_fd");
4151 if (!switch_userns(userns_fd, 0, 0, false))
4152 die("failure: switch_userns");
4154 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
4155 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
4156 envp[1] = expected_euid;
4157 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
4158 envp[2] = expected_egid;
4160 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4161 die("failure: expected_uid_gid");
4163 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4164 die("failure: sys_execveat");
4168 if (wait_for_pid(pid)) {
4169 log_stderr("failure: wait_for_pid");
4174 log_debug("Ran test");
4176 safe_close(attr.userns_fd);
4177 safe_close(exec_fd);
4178 safe_close(file1_fd);
4179 safe_close(open_tree_fd);
4181 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4182 sys_umount2(t_buf, MNT_DETACH);
4183 rm_r(t_mnt_fd, DIR1);
4188 static int sticky_bit_unlink(void)
4191 int dir_fd = -EBADF;
4194 if (!caps_supported())
4197 /* create directory */
4198 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4199 log_stderr("failure: mkdirat");
4203 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4205 log_stderr("failure: openat");
4209 if (fchown(dir_fd, 0, 0)) {
4210 log_stderr("failure: fchown");
4214 if (fchmod(dir_fd, 0777)) {
4215 log_stderr("failure: fchmod");
4219 /* create regular file via mknod */
4220 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4221 log_stderr("failure: mknodat");
4224 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4225 log_stderr("failure: fchownat");
4228 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4229 log_stderr("failure: fchmodat");
4233 /* create regular file via mknod */
4234 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4235 log_stderr("failure: mknodat");
4238 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4239 log_stderr("failure: fchownat");
4242 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4243 log_stderr("failure: fchmodat");
4247 /* The sticky bit is not set so we must be able to delete files not
4252 log_stderr("failure: fork");
4256 if (!switch_ids(1000, 1000))
4257 die("failure: switch_ids");
4259 if (unlinkat(dir_fd, FILE1, 0))
4260 die("failure: unlinkat");
4262 if (unlinkat(dir_fd, FILE2, 0))
4263 die("failure: unlinkat");
4267 if (wait_for_pid(pid)) {
4268 log_stderr("failure: wait_for_pid");
4272 /* set sticky bit */
4273 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4274 log_stderr("failure: fchmod");
4278 /* validate sticky bit is set */
4279 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4280 log_stderr("failure: is_sticky");
4284 /* create regular file via mknod */
4285 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4286 log_stderr("failure: mknodat");
4289 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4290 log_stderr("failure: fchownat");
4293 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4294 log_stderr("failure: fchmodat");
4298 /* create regular file via mknod */
4299 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4300 log_stderr("failure: mknodat");
4303 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4304 log_stderr("failure: fchownat");
4307 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4308 log_stderr("failure: fchmodat");
4312 /* The sticky bit is set so we must not be able to delete files not
4317 log_stderr("failure: fork");
4321 if (!switch_ids(1000, 1000))
4322 die("failure: switch_ids");
4324 if (!unlinkat(dir_fd, FILE1, 0))
4325 die("failure: unlinkat");
4327 die("failure: errno");
4329 if (!unlinkat(dir_fd, FILE2, 0))
4330 die("failure: unlinkat");
4332 die("failure: errno");
4336 if (wait_for_pid(pid)) {
4337 log_stderr("failure: wait_for_pid");
4341 /* The sticky bit is set and we own the files so we must be able to
4342 * delete the files now.
4346 log_stderr("failure: fork");
4350 /* change ownership */
4351 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4352 die("failure: fchownat");
4353 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4354 die("failure: expected_uid_gid");
4355 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4356 die("failure: fchownat");
4357 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4358 die("failure: expected_uid_gid");
4360 if (!switch_ids(1000, 1000))
4361 die("failure: switch_ids");
4363 if (unlinkat(dir_fd, FILE1, 0))
4364 die("failure: unlinkat");
4366 if (unlinkat(dir_fd, FILE2, 0))
4367 die("failure: unlinkat");
4371 if (wait_for_pid(pid)) {
4372 log_stderr("failure: wait_for_pid");
4376 /* change uid to unprivileged user */
4377 if (fchown(dir_fd, 1000, -1)) {
4378 log_stderr("failure: fchown");
4381 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4382 log_stderr("failure: fchmod");
4385 /* validate sticky bit is set */
4386 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4387 log_stderr("failure: is_sticky");
4391 /* create regular file via mknod */
4392 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4393 log_stderr("failure: mknodat");
4396 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4397 log_stderr("failure: fchownat");
4400 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4401 log_stderr("failure: fchmodat");
4405 /* create regular file via mknod */
4406 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4407 log_stderr("failure: mknodat");
4410 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4411 log_stderr("failure: fchownat");
4414 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4415 log_stderr("failure: fchmodat");
4419 /* The sticky bit is set and we own the directory so we must be able to
4420 * delete the files now.
4424 log_stderr("failure: fork");
4428 if (!switch_ids(1000, 1000))
4429 die("failure: switch_ids");
4431 if (unlinkat(dir_fd, FILE1, 0))
4432 die("failure: unlinkat");
4434 if (unlinkat(dir_fd, FILE2, 0))
4435 die("failure: unlinkat");
4439 if (wait_for_pid(pid)) {
4440 log_stderr("failure: wait_for_pid");
4445 log_debug("Ran test");
4452 static int sticky_bit_unlink_idmapped_mounts(void)
4455 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4456 struct mount_attr attr = {
4457 .attr_set = MOUNT_ATTR_IDMAP,
4461 if (!caps_supported())
4464 /* create directory */
4465 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4466 log_stderr("failure: mkdirat");
4470 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4472 log_stderr("failure: openat");
4475 if (fchown(dir_fd, 10000, 10000)) {
4476 log_stderr("failure: fchown");
4479 if (fchmod(dir_fd, 0777)) {
4480 log_stderr("failure: fchmod");
4484 /* create regular file via mknod */
4485 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4486 log_stderr("failure: mknodat");
4489 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4490 log_stderr("failure: fchownat");
4493 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4494 log_stderr("failure: fchmodat");
4498 /* create regular file via mknod */
4499 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4500 log_stderr("failure: mknodat");
4503 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4504 log_stderr("failure: fchownat");
4507 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4508 log_stderr("failure: fchmodat");
4512 /* Changing mount properties on a detached mount. */
4513 attr.userns_fd = get_userns_fd(10000, 0, 10000);
4514 if (attr.userns_fd < 0) {
4515 log_stderr("failure: get_userns_fd");
4519 open_tree_fd = sys_open_tree(dir_fd, "",
4522 AT_SYMLINK_NOFOLLOW |
4525 if (open_tree_fd < 0) {
4526 log_stderr("failure: sys_open_tree");
4530 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4531 log_stderr("failure: sys_mount_setattr");
4535 /* The sticky bit is not set so we must be able to delete files not
4540 log_stderr("failure: fork");
4544 if (!switch_ids(1000, 1000))
4545 die("failure: switch_ids");
4547 if (unlinkat(open_tree_fd, FILE1, 0))
4548 die("failure: unlinkat");
4550 if (unlinkat(open_tree_fd, FILE2, 0))
4551 die("failure: unlinkat");
4555 if (wait_for_pid(pid)) {
4556 log_stderr("failure: wait_for_pid");
4560 /* set sticky bit */
4561 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4562 log_stderr("failure: fchmod");
4566 /* validate sticky bit is set */
4567 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4568 log_stderr("failure: is_sticky");
4572 /* create regular file via mknod */
4573 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4574 log_stderr("failure: mknodat");
4577 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4578 log_stderr("failure: fchownat");
4581 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4582 log_stderr("failure: fchmodat");
4586 /* create regular file via mknod */
4587 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4588 log_stderr("failure: mknodat");
4591 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4592 log_stderr("failure: fchownat");
4595 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4596 log_stderr("failure: fchmodat");
4600 /* The sticky bit is set so we must not be able to delete files not
4605 log_stderr("failure: fork");
4609 if (!switch_ids(1000, 1000))
4610 die("failure: switch_ids");
4612 if (!unlinkat(open_tree_fd, FILE1, 0))
4613 die("failure: unlinkat");
4615 die("failure: errno");
4617 if (!unlinkat(open_tree_fd, FILE2, 0))
4618 die("failure: unlinkat");
4620 die("failure: errno");
4624 if (wait_for_pid(pid)) {
4625 log_stderr("failure: wait_for_pid");
4629 /* The sticky bit is set and we own the files so we must be able to
4630 * delete the files now.
4634 log_stderr("failure: fork");
4638 /* change ownership */
4639 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
4640 die("failure: fchownat");
4641 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
4642 die("failure: expected_uid_gid");
4643 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
4644 die("failure: fchownat");
4645 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
4646 die("failure: expected_uid_gid");
4648 if (!switch_ids(1000, 1000))
4649 die("failure: switch_ids");
4651 if (unlinkat(open_tree_fd, FILE1, 0))
4652 die("failure: unlinkat");
4654 if (unlinkat(open_tree_fd, FILE2, 0))
4655 die("failure: unlinkat");
4659 if (wait_for_pid(pid)) {
4660 log_stderr("failure: wait_for_pid");
4664 /* change uid to unprivileged user */
4665 if (fchown(dir_fd, 11000, -1)) {
4666 log_stderr("failure: fchown");
4669 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4670 log_stderr("failure: fchmod");
4673 /* validate sticky bit is set */
4674 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4675 log_stderr("failure: is_sticky");
4679 /* create regular file via mknod */
4680 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4681 log_stderr("failure: mknodat");
4684 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4685 log_stderr("failure: fchownat");
4688 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4689 log_stderr("failure: fchmodat");
4693 /* create regular file via mknod */
4694 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4695 log_stderr("failure: mknodat");
4698 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4699 log_stderr("failure: fchownat");
4702 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4703 log_stderr("failure: fchmodat");
4707 /* The sticky bit is set and we own the directory so we must be able to
4708 * delete the files now.
4712 log_stderr("failure: fork");
4716 if (!switch_ids(1000, 1000))
4717 die("failure: switch_ids");
4719 if (unlinkat(open_tree_fd, FILE1, 0))
4720 die("failure: unlinkat");
4722 if (unlinkat(open_tree_fd, FILE2, 0))
4723 die("failure: unlinkat");
4727 if (wait_for_pid(pid)) {
4728 log_stderr("failure: wait_for_pid");
4733 log_debug("Ran test");
4735 safe_close(attr.userns_fd);
4737 safe_close(open_tree_fd);
4742 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
4743 * operations in a user namespace.
4745 static int sticky_bit_unlink_idmapped_mounts_in_userns(void)
4748 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4749 struct mount_attr attr = {
4750 .attr_set = MOUNT_ATTR_IDMAP,
4754 if (!caps_supported())
4757 /* create directory */
4758 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4759 log_stderr("failure: mkdirat");
4763 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4765 log_stderr("failure: openat");
4768 if (fchown(dir_fd, 0, 0)) {
4769 log_stderr("failure: fchown");
4772 if (fchmod(dir_fd, 0777)) {
4773 log_stderr("failure: fchmod");
4777 /* create regular file via mknod */
4778 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4779 log_stderr("failure: mknodat");
4782 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4783 log_stderr("failure: fchownat");
4786 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4787 log_stderr("failure: fchmodat");
4791 /* create regular file via mknod */
4792 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4793 log_stderr("failure: mknodat");
4796 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4797 log_stderr("failure: fchownat");
4800 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4801 log_stderr("failure: fchmodat");
4805 /* Changing mount properties on a detached mount. */
4806 attr.userns_fd = get_userns_fd(0, 10000, 10000);
4807 if (attr.userns_fd < 0) {
4808 log_stderr("failure: get_userns_fd");
4812 open_tree_fd = sys_open_tree(dir_fd, "",
4815 AT_SYMLINK_NOFOLLOW |
4818 if (open_tree_fd < 0) {
4819 log_stderr("failure: sys_open_tree");
4823 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4824 log_stderr("failure: sys_mount_setattr");
4828 /* The sticky bit is not set so we must be able to delete files not
4833 log_stderr("failure: fork");
4837 if (!caps_supported()) {
4838 log_debug("skip: capability library not installed");
4842 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4843 die("failure: switch_userns");
4845 if (unlinkat(dir_fd, FILE1, 0))
4846 die("failure: unlinkat");
4848 if (unlinkat(dir_fd, FILE2, 0))
4849 die("failure: unlinkat");
4853 if (wait_for_pid(pid)) {
4854 log_stderr("failure: wait_for_pid");
4858 /* set sticky bit */
4859 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4860 log_stderr("failure: fchmod");
4864 /* validate sticky bit is set */
4865 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4866 log_stderr("failure: is_sticky");
4870 /* create regular file via mknod */
4871 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4872 log_stderr("failure: mknodat");
4875 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4876 log_stderr("failure: fchownat");
4879 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4880 log_stderr("failure: fchmodat");
4884 /* create regular file via mknod */
4885 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4886 log_stderr("failure: mknodat");
4889 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4890 log_stderr("failure: fchownat");
4893 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4894 log_stderr("failure: fchmodat");
4898 /* The sticky bit is set so we must not be able to delete files not
4903 log_stderr("failure: fork");
4907 if (!caps_supported()) {
4908 log_debug("skip: capability library not installed");
4912 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4913 die("failure: switch_userns");
4915 if (!unlinkat(dir_fd, FILE1, 0))
4916 die("failure: unlinkat");
4918 die("failure: errno");
4920 if (!unlinkat(dir_fd, FILE2, 0))
4921 die("failure: unlinkat");
4923 die("failure: errno");
4925 if (!unlinkat(open_tree_fd, FILE1, 0))
4926 die("failure: unlinkat");
4928 die("failure: errno");
4930 if (!unlinkat(open_tree_fd, FILE2, 0))
4931 die("failure: unlinkat");
4933 die("failure: errno");
4937 if (wait_for_pid(pid)) {
4938 log_stderr("failure: wait_for_pid");
4942 /* The sticky bit is set and we own the files so we must be able to
4943 * delete the files now.
4947 log_stderr("failure: fork");
4951 /* change ownership */
4952 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4953 die("failure: fchownat");
4954 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4955 die("failure: expected_uid_gid");
4956 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4957 die("failure: fchownat");
4958 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4959 die("failure: expected_uid_gid");
4961 if (!caps_supported()) {
4962 log_debug("skip: capability library not installed");
4966 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4967 die("failure: switch_userns");
4969 if (!unlinkat(dir_fd, FILE1, 0))
4970 die("failure: unlinkat");
4972 die("failure: errno");
4974 if (!unlinkat(dir_fd, FILE2, 0))
4975 die("failure: unlinkat");
4977 die("failure: errno");
4979 if (unlinkat(open_tree_fd, FILE1, 0))
4980 die("failure: unlinkat");
4982 if (unlinkat(open_tree_fd, FILE2, 0))
4983 die("failure: unlinkat");
4987 if (wait_for_pid(pid)) {
4988 log_stderr("failure: wait_for_pid");
4992 /* change uid to unprivileged user */
4993 if (fchown(dir_fd, 1000, -1)) {
4994 log_stderr("failure: fchown");
4997 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4998 log_stderr("failure: fchmod");
5001 /* validate sticky bit is set */
5002 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5003 log_stderr("failure: is_sticky");
5007 /* create regular file via mknod */
5008 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5009 log_stderr("failure: mknodat");
5012 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5013 log_stderr("failure: fchownat");
5016 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5017 log_stderr("failure: fchmodat");
5021 /* create regular file via mknod */
5022 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5023 log_stderr("failure: mknodat");
5026 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5027 log_stderr("failure: fchownat");
5030 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5031 log_stderr("failure: fchmodat");
5035 /* The sticky bit is set and we own the directory so we must be able to
5036 * delete the files now.
5040 log_stderr("failure: fork");
5044 if (!caps_supported()) {
5045 log_debug("skip: capability library not installed");
5049 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5050 die("failure: switch_userns");
5052 /* we don't own the directory from the original mount */
5053 if (!unlinkat(dir_fd, FILE1, 0))
5054 die("failure: unlinkat");
5056 die("failure: errno");
5058 if (!unlinkat(dir_fd, FILE2, 0))
5059 die("failure: unlinkat");
5061 die("failure: errno");
5063 /* we own the file from the idmapped mount */
5064 if (unlinkat(open_tree_fd, FILE1, 0))
5065 die("failure: unlinkat");
5066 if (unlinkat(open_tree_fd, FILE2, 0))
5067 die("failure: unlinkat");
5071 if (wait_for_pid(pid)) {
5072 log_stderr("failure: wait_for_pid");
5077 log_debug("Ran test");
5079 safe_close(attr.userns_fd);
5081 safe_close(open_tree_fd);
5086 static int sticky_bit_rename(void)
5089 int dir_fd = -EBADF;
5092 if (!caps_supported())
5095 /* create directory */
5096 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5097 log_stderr("failure: mkdirat");
5101 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5103 log_stderr("failure: openat");
5106 if (fchown(dir_fd, 0, 0)) {
5107 log_stderr("failure: fchown");
5110 if (fchmod(dir_fd, 0777)) {
5111 log_stderr("failure: fchmod");
5115 /* create regular file via mknod */
5116 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5117 log_stderr("failure: mknodat");
5120 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5121 log_stderr("failure: fchownat");
5124 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5125 log_stderr("failure: fchmodat");
5129 /* create regular file via mknod */
5130 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5131 log_stderr("failure: mknodat");
5134 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5135 log_stderr("failure: fchownat");
5138 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5139 log_stderr("failure: fchmodat");
5143 /* The sticky bit is not set so we must be able to delete files not
5148 log_stderr("failure: fork");
5152 if (!switch_ids(1000, 1000))
5153 die("failure: switch_ids");
5155 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5156 die("failure: renameat");
5158 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5159 die("failure: renameat");
5161 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5162 die("failure: renameat");
5164 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5165 die("failure: renameat");
5169 if (wait_for_pid(pid)) {
5170 log_stderr("failure: wait_for_pid");
5174 /* set sticky bit */
5175 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5176 log_stderr("failure: fchmod");
5180 /* validate sticky bit is set */
5181 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5182 log_stderr("failure: is_sticky");
5186 /* The sticky bit is set so we must not be able to delete files not
5191 log_stderr("failure: fork");
5195 if (!switch_ids(1000, 1000))
5196 die("failure: switch_ids");
5198 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5199 die("failure: renameat");
5201 die("failure: errno");
5203 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5204 die("failure: renameat");
5206 die("failure: errno");
5210 if (wait_for_pid(pid)) {
5211 log_stderr("failure: wait_for_pid");
5215 /* The sticky bit is set and we own the files so we must be able to
5216 * delete the files now.
5220 log_stderr("failure: fork");
5224 /* change ownership */
5225 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5226 die("failure: fchownat");
5227 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5228 die("failure: expected_uid_gid");
5229 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5230 die("failure: fchownat");
5231 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5232 die("failure: expected_uid_gid");
5234 if (!switch_ids(1000, 1000))
5235 die("failure: switch_ids");
5237 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5238 die("failure: renameat");
5240 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5241 die("failure: renameat");
5243 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5244 die("failure: renameat");
5246 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5247 die("failure: renameat");
5251 if (wait_for_pid(pid)) {
5252 log_stderr("failure: wait_for_pid");
5256 /* change uid to unprivileged user */
5257 if (fchown(dir_fd, 1000, -1)) {
5258 log_stderr("failure: fchown");
5261 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5262 log_stderr("failure: fchmod");
5265 /* validate sticky bit is set */
5266 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5267 log_stderr("failure: is_sticky");
5272 /* The sticky bit is set and we own the directory so we must be able to
5273 * delete the files now.
5277 log_stderr("failure: fork");
5281 if (!switch_ids(1000, 1000))
5282 die("failure: switch_ids");
5284 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5285 die("failure: renameat");
5287 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5288 die("failure: renameat");
5290 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5291 die("failure: renameat");
5293 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5294 die("failure: renameat");
5298 if (wait_for_pid(pid)) {
5299 log_stderr("failure: wait_for_pid");
5304 log_debug("Ran test");
5311 static int sticky_bit_rename_idmapped_mounts(void)
5314 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5315 struct mount_attr attr = {
5316 .attr_set = MOUNT_ATTR_IDMAP,
5320 if (!caps_supported())
5323 /* create directory */
5324 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5325 log_stderr("failure: mkdirat");
5329 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5331 log_stderr("failure: openat");
5335 if (fchown(dir_fd, 10000, 10000)) {
5336 log_stderr("failure: fchown");
5340 if (fchmod(dir_fd, 0777)) {
5341 log_stderr("failure: fchmod");
5345 /* create regular file via mknod */
5346 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5347 log_stderr("failure: mknodat");
5350 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
5351 log_stderr("failure: fchownat");
5354 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5355 log_stderr("failure: fchmodat");
5359 /* create regular file via mknod */
5360 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5361 log_stderr("failure: mknodat");
5364 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
5365 log_stderr("failure: fchownat");
5368 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5369 log_stderr("failure: fchmodat");
5373 /* Changing mount properties on a detached mount. */
5374 attr.userns_fd = get_userns_fd(10000, 0, 10000);
5375 if (attr.userns_fd < 0) {
5376 log_stderr("failure: get_userns_fd");
5380 open_tree_fd = sys_open_tree(dir_fd, "",
5383 AT_SYMLINK_NOFOLLOW |
5386 if (open_tree_fd < 0) {
5387 log_stderr("failure: sys_open_tree");
5391 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5392 log_stderr("failure: sys_mount_setattr");
5396 /* The sticky bit is not set so we must be able to delete files not
5401 log_stderr("failure: fork");
5405 if (!switch_ids(1000, 1000))
5406 die("failure: switch_ids");
5408 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5409 die("failure: renameat");
5411 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5412 die("failure: renameat");
5414 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5415 die("failure: renameat");
5417 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5418 die("failure: renameat");
5422 if (wait_for_pid(pid)) {
5423 log_stderr("failure: wait_for_pid");
5427 /* set sticky bit */
5428 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5429 log_stderr("failure: fchmod");
5433 /* validate sticky bit is set */
5434 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5435 log_stderr("failure: is_sticky");
5439 /* The sticky bit is set so we must not be able to delete files not
5444 log_stderr("failure: fork");
5448 if (!switch_ids(1000, 1000))
5449 die("failure: switch_ids");
5451 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5452 die("failure: renameat");
5454 die("failure: errno");
5456 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5457 die("failure: renameat");
5459 die("failure: errno");
5463 if (wait_for_pid(pid)) {
5464 log_stderr("failure: wait_for_pid");
5468 /* The sticky bit is set and we own the files so we must be able to
5469 * delete the files now.
5473 log_stderr("failure: fork");
5477 /* change ownership */
5478 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
5479 die("failure: fchownat");
5480 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
5481 die("failure: expected_uid_gid");
5482 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
5483 die("failure: fchownat");
5484 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
5485 die("failure: expected_uid_gid");
5487 if (!switch_ids(1000, 1000))
5488 die("failure: switch_ids");
5490 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5491 die("failure: renameat");
5493 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5494 die("failure: renameat");
5496 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5497 die("failure: renameat");
5499 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5500 die("failure: renameat");
5504 if (wait_for_pid(pid)) {
5505 log_stderr("failure: wait_for_pid");
5509 /* change uid to unprivileged user */
5510 if (fchown(dir_fd, 11000, -1)) {
5511 log_stderr("failure: fchown");
5514 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5515 log_stderr("failure: fchmod");
5518 /* validate sticky bit is set */
5519 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5520 log_stderr("failure: is_sticky");
5524 /* The sticky bit is set and we own the directory so we must be able to
5525 * delete the files now.
5529 log_stderr("failure: fork");
5533 if (!switch_ids(1000, 1000))
5534 die("failure: switch_ids");
5536 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5537 die("failure: renameat");
5539 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5540 die("failure: renameat");
5542 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5543 die("failure: renameat");
5545 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5546 die("failure: renameat");
5550 if (wait_for_pid(pid)) {
5551 log_stderr("failure: wait_for_pid");
5556 log_debug("Ran test");
5558 safe_close(attr.userns_fd);
5560 safe_close(open_tree_fd);
5565 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
5566 * operations in a user namespace.
5568 static int sticky_bit_rename_idmapped_mounts_in_userns(void)
5571 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5572 struct mount_attr attr = {
5573 .attr_set = MOUNT_ATTR_IDMAP,
5577 if (!caps_supported())
5580 /* create directory */
5581 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5582 log_stderr("failure: mkdirat");
5586 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5588 log_stderr("failure: openat");
5591 if (fchown(dir_fd, 0, 0)) {
5592 log_stderr("failure: fchown");
5595 if (fchmod(dir_fd, 0777)) {
5596 log_stderr("failure: fchmod");
5600 /* create regular file via mknod */
5601 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5602 log_stderr("failure: mknodat");
5605 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5606 log_stderr("failure: fchownat");
5609 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5610 log_stderr("failure: fchmodat");
5614 /* create regular file via mknod */
5615 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5616 log_stderr("failure: mknodat");
5619 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5620 log_stderr("failure: fchownat");
5623 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5624 log_stderr("failure: fchmodat");
5628 /* Changing mount properties on a detached mount. */
5629 attr.userns_fd = get_userns_fd(0, 10000, 10000);
5630 if (attr.userns_fd < 0) {
5631 log_stderr("failure: get_userns_fd");
5635 open_tree_fd = sys_open_tree(dir_fd, "",
5638 AT_SYMLINK_NOFOLLOW |
5641 if (open_tree_fd < 0) {
5642 log_stderr("failure: sys_open_tree");
5646 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5647 log_stderr("failure: sys_mount_setattr");
5651 /* The sticky bit is not set so we must be able to delete files not
5656 log_stderr("failure: fork");
5660 if (!caps_supported()) {
5661 log_debug("skip: capability library not installed");
5665 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5666 die("failure: switch_userns");
5668 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5669 die("failure: renameat");
5671 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5672 die("failure: renameat");
5674 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5675 die("failure: renameat");
5677 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5678 die("failure: renameat");
5682 if (wait_for_pid(pid)) {
5683 log_stderr("failure: wait_for_pid");
5687 /* set sticky bit */
5688 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5689 log_stderr("failure: fchmod");
5693 /* validate sticky bit is set */
5694 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5695 log_stderr("failure: is_sticky");
5699 /* The sticky bit is set so we must not be able to delete files not
5704 log_stderr("failure: fork");
5708 if (!caps_supported()) {
5709 log_debug("skip: capability library not installed");
5713 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5714 die("failure: switch_userns");
5716 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5717 die("failure: renameat");
5719 die("failure: errno");
5721 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5722 die("failure: renameat");
5724 die("failure: errno");
5726 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5727 die("failure: renameat");
5729 die("failure: errno");
5731 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5732 die("failure: renameat");
5734 die("failure: errno");
5738 if (wait_for_pid(pid)) {
5739 log_stderr("failure: wait_for_pid");
5743 /* The sticky bit is set and we own the files so we must be able to
5744 * delete the files now.
5748 log_stderr("failure: fork");
5752 /* change ownership */
5753 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5754 die("failure: fchownat");
5755 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5756 die("failure: expected_uid_gid");
5757 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5758 die("failure: fchownat");
5759 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5760 die("failure: expected_uid_gid");
5762 if (!caps_supported()) {
5763 log_debug("skip: capability library not installed");
5767 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5768 die("failure: switch_userns");
5770 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5771 die("failure: renameat");
5773 die("failure: errno");
5775 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5776 die("failure: renameat");
5778 die("failure: errno");
5780 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5781 die("failure: renameat");
5783 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5784 die("failure: renameat");
5786 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5787 die("failure: renameat");
5789 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5790 die("failure: renameat");
5794 if (wait_for_pid(pid)) {
5795 log_stderr("failure: wait_for_pid");
5799 /* change uid to unprivileged user */
5800 if (fchown(dir_fd, 1000, -1)) {
5801 log_stderr("failure: fchown");
5804 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5805 log_stderr("failure: fchmod");
5808 /* validate sticky bit is set */
5809 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5810 log_stderr("failure: is_sticky");
5814 /* The sticky bit is set and we own the directory so we must be able to
5815 * delete the files now.
5819 log_stderr("failure: fork");
5823 if (!caps_supported()) {
5824 log_debug("skip: capability library not installed");
5828 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5829 die("failure: switch_userns");
5831 /* we don't own the directory from the original mount */
5832 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5833 die("failure: renameat");
5835 die("failure: errno");
5837 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5838 die("failure: renameat");
5840 die("failure: errno");
5842 /* we own the file from the idmapped mount */
5843 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5844 die("failure: renameat");
5846 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5847 die("failure: renameat");
5849 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5850 die("failure: renameat");
5852 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5853 die("failure: renameat");
5857 if (wait_for_pid(pid)) {
5858 log_stderr("failure: wait_for_pid");
5863 log_debug("Ran test");
5865 safe_close(open_tree_fd);
5866 safe_close(attr.userns_fd);
5872 /* Validate that protected symlinks work correctly. */
5873 static int protected_symlinks(void)
5876 int dir_fd = -EBADF, fd = -EBADF;
5879 if (!protected_symlinks_enabled())
5882 if (!caps_supported())
5885 /* create directory */
5886 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5887 log_stderr("failure: mkdirat");
5891 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5893 log_stderr("failure: openat");
5896 if (fchown(dir_fd, 0, 0)) {
5897 log_stderr("failure: fchown");
5900 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5901 log_stderr("failure: fchmod");
5904 /* validate sticky bit is set */
5905 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5906 log_stderr("failure: is_sticky");
5910 /* create regular file via mknod */
5911 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5912 log_stderr("failure: mknodat");
5915 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5916 log_stderr("failure: fchownat");
5919 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5920 log_stderr("failure: fchmodat");
5924 /* create symlinks */
5925 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
5926 log_stderr("failure: symlinkat");
5929 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
5930 log_stderr("failure: fchownat");
5933 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
5934 log_stderr("failure: expected_uid_gid");
5937 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5938 log_stderr("failure: expected_uid_gid");
5942 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
5943 log_stderr("failure: symlinkat");
5946 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
5947 log_stderr("failure: fchownat");
5950 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
5951 log_stderr("failure: expected_uid_gid");
5954 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5955 log_stderr("failure: expected_uid_gid");
5959 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
5960 log_stderr("failure: symlinkat");
5963 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
5964 log_stderr("failure: fchownat");
5967 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
5968 log_stderr("failure: expected_uid_gid");
5971 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
5972 log_stderr("failure: expected_uid_gid");
5976 /* validate file can be directly read */
5977 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
5979 log_stderr("failure: openat");
5984 /* validate file can be read through own symlink */
5985 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
5987 log_stderr("failure: openat");
5994 log_stderr("failure: fork");
5998 if (!switch_ids(1000, 1000))
5999 die("failure: switch_ids");
6001 /* validate file can be directly read */
6002 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6004 die("failure: openat");
6007 /* validate file can be read through own symlink */
6008 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6010 die("failure: openat");
6013 /* validate file can be read through root symlink */
6014 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6016 die("failure: openat");
6019 /* validate file can't be read through other users symlink */
6020 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6022 die("failure: openat");
6023 if (errno != EACCES)
6024 die("failure: errno");
6028 if (wait_for_pid(pid)) {
6029 log_stderr("failure: wait_for_pid");
6035 log_stderr("failure: fork");
6039 if (!switch_ids(2000, 2000))
6040 die("failure: switch_ids");
6042 /* validate file can be directly read */
6043 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6045 die("failure: openat");
6048 /* validate file can be read through own symlink */
6049 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6051 die("failure: openat");
6054 /* validate file can be read through root symlink */
6055 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6057 die("failure: openat");
6060 /* validate file can't be read through other users symlink */
6061 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6063 die("failure: openat");
6064 if (errno != EACCES)
6065 die("failure: errno");
6069 if (wait_for_pid(pid)) {
6070 log_stderr("failure: wait_for_pid");
6075 log_debug("Ran test");
6083 /* Validate that protected symlinks work correctly on idmapped mounts. */
6084 static int protected_symlinks_idmapped_mounts(void)
6087 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6088 struct mount_attr attr = {
6089 .attr_set = MOUNT_ATTR_IDMAP,
6093 if (!protected_symlinks_enabled())
6096 if (!caps_supported())
6099 /* create directory */
6100 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6101 log_stderr("failure: mkdirat");
6105 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6107 log_stderr("failure: openat");
6110 if (fchown(dir_fd, 10000, 10000)) {
6111 log_stderr("failure: fchown");
6114 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6115 log_stderr("failure: fchmod");
6118 /* validate sticky bit is set */
6119 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6120 log_stderr("failure: is_sticky");
6124 /* create regular file via mknod */
6125 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6126 log_stderr("failure: mknodat");
6129 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
6130 log_stderr("failure: fchownat");
6133 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6134 log_stderr("failure: fchmodat");
6138 /* create symlinks */
6139 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6140 log_stderr("failure: symlinkat");
6143 if (fchownat(dir_fd, SYMLINK_USER1, 10000, 10000, AT_SYMLINK_NOFOLLOW)) {
6144 log_stderr("failure: fchownat");
6147 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
6148 log_stderr("failure: expected_uid_gid");
6151 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6152 log_stderr("failure: expected_uid_gid");
6156 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6157 log_stderr("failure: symlinkat");
6160 if (fchownat(dir_fd, SYMLINK_USER2, 11000, 11000, AT_SYMLINK_NOFOLLOW)) {
6161 log_stderr("failure: fchownat");
6164 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 11000, 11000)) {
6165 log_stderr("failure: expected_uid_gid");
6168 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6169 log_stderr("failure: expected_uid_gid");
6173 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6174 log_stderr("failure: symlinkat");
6177 if (fchownat(dir_fd, SYMLINK_USER3, 12000, 12000, AT_SYMLINK_NOFOLLOW)) {
6178 log_stderr("failure: fchownat");
6181 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
6182 log_stderr("failure: expected_uid_gid");
6185 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6186 log_stderr("failure: expected_uid_gid");
6190 /* Changing mount properties on a detached mount. */
6191 attr.userns_fd = get_userns_fd(10000, 0, 10000);
6192 if (attr.userns_fd < 0) {
6193 log_stderr("failure: get_userns_fd");
6197 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6200 AT_SYMLINK_NOFOLLOW |
6203 if (open_tree_fd < 0) {
6204 log_stderr("failure: open_tree_fd");
6208 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6209 log_stderr("failure: sys_mount_setattr");
6213 /* validate file can be directly read */
6214 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6216 log_stderr("failure: openat");
6221 /* validate file can be read through own symlink */
6222 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6224 log_stderr("failure: openat");
6231 log_stderr("failure: fork");
6235 if (!switch_ids(1000, 1000))
6236 die("failure: switch_ids");
6238 /* validate file can be directly read */
6239 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6241 die("failure: openat");
6244 /* validate file can be read through own symlink */
6245 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6247 die("failure: openat");
6250 /* validate file can be read through root symlink */
6251 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6253 die("failure: openat");
6256 /* validate file can't be read through other users symlink */
6257 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6259 die("failure: openat");
6260 if (errno != EACCES)
6261 die("failure: errno");
6265 if (wait_for_pid(pid)) {
6266 log_stderr("failure: wait_for_pid");
6272 log_stderr("failure: fork");
6276 if (!switch_ids(2000, 2000))
6277 die("failure: switch_ids");
6279 /* validate file can be directly read */
6280 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6282 die("failure: openat");
6285 /* validate file can be read through own symlink */
6286 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6288 die("failure: openat");
6291 /* validate file can be read through root symlink */
6292 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6294 die("failure: openat");
6297 /* validate file can't be read through other users symlink */
6298 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6300 die("failure: openat");
6301 if (errno != EACCES)
6302 die("failure: errno");
6306 if (wait_for_pid(pid)) {
6307 log_stderr("failure: wait_for_pid");
6312 log_debug("Ran test");
6314 safe_close(attr.userns_fd);
6317 safe_close(open_tree_fd);
6322 /* Validate that protected symlinks work correctly on idmapped mounts inside a
6325 static int protected_symlinks_idmapped_mounts_in_userns(void)
6328 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6329 struct mount_attr attr = {
6330 .attr_set = MOUNT_ATTR_IDMAP,
6334 if (!protected_symlinks_enabled())
6337 if (!caps_supported())
6340 /* create directory */
6341 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6342 log_stderr("failure: mkdirat");
6346 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6348 log_stderr("failure: openat");
6351 if (fchown(dir_fd, 0, 0)) {
6352 log_stderr("failure: fchown");
6355 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6356 log_stderr("failure: fchmod");
6359 /* validate sticky bit is set */
6360 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6361 log_stderr("failure: is_sticky");
6365 /* create regular file via mknod */
6366 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6367 log_stderr("failure: mknodat");
6370 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6371 log_stderr("failure: fchownat");
6374 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6375 log_stderr("failure: fchmodat");
6379 /* create symlinks */
6380 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6381 log_stderr("failure: symlinkat");
6384 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6385 log_stderr("failure: fchownat");
6388 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6389 log_stderr("failure: expected_uid_gid");
6392 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6393 log_stderr("failure: expected_uid_gid");
6397 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6398 log_stderr("failure: symlinkat");
6401 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6402 log_stderr("failure: fchownat");
6405 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6406 log_stderr("failure: expected_uid_gid");
6409 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6410 log_stderr("failure: expected_uid_gid");
6414 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6415 log_stderr("failure: symlinkat");
6418 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6419 log_stderr("failure: fchownat");
6422 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6423 log_stderr("failure: expected_uid_gid");
6426 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6427 log_stderr("failure: expected_uid_gid");
6431 /* Changing mount properties on a detached mount. */
6432 attr.userns_fd = get_userns_fd(0, 10000, 10000);
6433 if (attr.userns_fd < 0) {
6434 log_stderr("failure: get_userns_fd");
6438 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6441 AT_SYMLINK_NOFOLLOW |
6444 if (open_tree_fd < 0) {
6445 log_stderr("failure: sys_open_tree");
6449 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6450 log_stderr("failure: sys_mount_setattr");
6454 /* validate file can be directly read */
6455 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6457 log_stderr("failure: openat");
6462 /* validate file can be read through own symlink */
6463 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6465 log_stderr("failure: openat");
6472 log_stderr("failure: fork");
6476 if (!caps_supported()) {
6477 log_debug("skip: capability library not installed");
6481 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
6482 die("failure: switch_userns");
6484 /* validate file can be directly read */
6485 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6487 die("failure: openat");
6490 /* validate file can be read through own symlink */
6491 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6493 die("failure: openat");
6496 /* validate file can be read through root symlink */
6497 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6499 die("failure: openat");
6502 /* validate file can't be read through other users symlink */
6503 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6505 die("failure: openat");
6506 if (errno != EACCES)
6507 die("failure: errno");
6511 if (wait_for_pid(pid)) {
6512 log_stderr("failure: wait_for_pid");
6518 log_stderr("failure: fork");
6522 if (!caps_supported()) {
6523 log_debug("skip: capability library not installed");
6527 if (!switch_userns(attr.userns_fd, 2000, 2000, true))
6528 die("failure: switch_userns");
6530 /* validate file can be directly read */
6531 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6533 die("failure: openat");
6536 /* validate file can be read through own symlink */
6537 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6539 die("failure: openat");
6542 /* validate file can be read through root symlink */
6543 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6545 die("failure: openat");
6548 /* validate file can't be read through other users symlink */
6549 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6551 die("failure: openat");
6552 if (errno != EACCES)
6553 die("failure: errno");
6557 if (wait_for_pid(pid)) {
6558 log_stderr("failure: wait_for_pid");
6563 log_debug("Ran test");
6566 safe_close(open_tree_fd);
6567 safe_close(attr.userns_fd);
6572 static int acls(void)
6575 int dir1_fd = -EBADF, open_tree_fd = -EBADF;
6576 struct mount_attr attr = {
6577 .attr_set = MOUNT_ATTR_IDMAP,
6581 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
6582 log_stderr("failure: mkdirat");
6585 if (fchmodat(t_dir1_fd, DIR1, 0777, 0)) {
6586 log_stderr("failure: fchmodat");
6590 if (mkdirat(t_dir1_fd, DIR2, 0777)) {
6591 log_stderr("failure: mkdirat");
6594 if (fchmodat(t_dir1_fd, DIR2, 0777, 0)) {
6595 log_stderr("failure: fchmodat");
6599 /* Changing mount properties on a detached mount. */
6600 attr.userns_fd = get_userns_fd(100010, 100020, 5);
6601 if (attr.userns_fd < 0) {
6602 log_stderr("failure: get_userns_fd");
6606 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
6608 AT_SYMLINK_NOFOLLOW |
6611 if (open_tree_fd < 0) {
6612 log_stderr("failure: sys_open_tree");
6616 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6617 log_stderr("failure: sys_mount_setattr");
6621 if (sys_move_mount(open_tree_fd, "", t_dir1_fd, DIR2, MOVE_MOUNT_F_EMPTY_PATH)) {
6622 log_stderr("failure: sys_move_mount");
6626 dir1_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6628 log_stderr("failure: openat");
6632 if (mkdirat(dir1_fd, DIR3, 0000)) {
6633 log_stderr("failure: mkdirat");
6636 if (fchown(dir1_fd, 100010, 100010)) {
6637 log_stderr("failure: fchown");
6640 if (fchmod(dir1_fd, 0777)) {
6641 log_stderr("failure: fchmod");
6645 snprintf(t_buf, sizeof(t_buf), "setfacl -m u:100010:rwx %s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6646 if (system(t_buf)) {
6647 log_stderr("failure: system");
6651 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100010:rwx", t_mountpoint, T_DIR1, DIR1, DIR3);
6652 if (system(t_buf)) {
6653 log_stderr("failure: system");
6657 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100020:rwx", t_mountpoint, T_DIR1, DIR2, DIR3);
6658 if (system(t_buf)) {
6659 log_stderr("failure: system");
6665 log_stderr("failure: fork");
6669 if (!caps_supported()) {
6670 log_debug("skip: capability library not installed");
6674 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6675 die("failure: switch_userns");
6677 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6678 t_mountpoint, T_DIR1, DIR1, DIR3, 4294967295LU);
6680 die("failure: system");
6684 if (wait_for_pid(pid)) {
6685 log_stderr("failure: wait_for_pid");
6691 log_stderr("failure: fork");
6695 if (!caps_supported()) {
6696 log_debug("skip: capability library not installed");
6700 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6701 die("failure: switch_userns");
6703 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6704 t_mountpoint, T_DIR1, DIR2, DIR3, 100010LU);
6706 die("failure: system");
6710 if (wait_for_pid(pid)) {
6711 log_stderr("failure: wait_for_pid");
6715 /* Now, dir is owned by someone else in the user namespace, but we can
6716 * still read it because of acls.
6718 if (fchown(dir1_fd, 100012, 100012)) {
6719 log_stderr("failure: fchown");
6725 log_stderr("failure: fork");
6731 if (!caps_supported()) {
6732 log_debug("skip: capability library not installed");
6736 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6737 die("failure: switch_userns");
6739 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6741 die("failure: openat");
6745 if (wait_for_pid(pid)) {
6746 log_stderr("failure: wait_for_pid");
6750 /* if we delete the acls, the ls should fail because it's 700. */
6751 snprintf(t_buf, sizeof(t_buf), "%s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6752 if (removexattr(t_buf, "system.posix_acl_access")) {
6753 log_stderr("failure: removexattr");
6759 log_stderr("failure: fork");
6765 if (!caps_supported()) {
6766 log_debug("skip: capability library not installed");
6770 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6771 die("failure: switch_userns");
6773 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6775 die("failure: openat");
6779 if (wait_for_pid(pid)) {
6780 log_stderr("failure: wait_for_pid");
6784 snprintf(t_buf, sizeof(t_buf), "%s/" T_DIR1 "/" DIR2, t_mountpoint);
6785 sys_umount2(t_buf, MNT_DETACH);
6788 log_debug("Ran test");
6790 safe_close(attr.userns_fd);
6791 safe_close(dir1_fd);
6792 safe_close(open_tree_fd);
6797 #ifdef HAVE_LIBURING_H
6798 static int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, int cred_id,
6799 bool with_link, int *ret_cqe)
6801 struct io_uring_cqe *cqe;
6802 struct io_uring_sqe *sqe;
6803 int ret, i, to_submit = 1;
6806 sqe = io_uring_get_sqe(ring);
6808 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6809 io_uring_prep_nop(sqe);
6810 sqe->flags |= IOSQE_IO_LINK;
6815 sqe = io_uring_get_sqe(ring);
6817 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6818 io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0);
6822 sqe->personality = cred_id;
6824 ret = io_uring_submit(ring);
6825 if (ret != to_submit) {
6826 log_stderr("failure: io_uring_submit");
6830 for (i = 0; i < to_submit; i++) {
6831 ret = io_uring_wait_cqe(ring, &cqe);
6833 log_stderr("failure: io_uring_wait_cqe");
6839 * Make sure caller can identify that this is a proper io_uring
6840 * failure and not some earlier error.
6844 io_uring_cqe_seen(ring, cqe);
6846 log_debug("Ran test");
6851 static int io_uring(void)
6854 int file1_fd = -EBADF;
6855 struct io_uring *ring;
6856 int cred_id, ret, ret_cqe;
6859 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6860 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6862 return log_errno(-1, "failure: io_uring_queue_init");
6864 ret = io_uring_queue_init(8, ring, 0);
6866 log_stderr("failure: io_uring_queue_init");
6870 ret = io_uring_register_personality(ring);
6873 goto out_unmap; /* personalities not supported */
6877 /* create file only owner can open */
6878 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
6880 log_stderr("failure: openat");
6883 if (fchown(file1_fd, 0, 0)) {
6884 log_stderr("failure: fchown");
6887 if (fchmod(file1_fd, 0600)) {
6888 log_stderr("failure: fchmod");
6891 safe_close(file1_fd);
6895 log_stderr("failure: fork");
6899 /* Verify we can open it with our current credentials. */
6900 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6903 die("failure: io_uring_open_file");
6907 if (wait_for_pid(pid)) {
6908 log_stderr("failure: wait_for_pid");
6914 log_stderr("failure: fork");
6918 if (!switch_ids(1000, 1000))
6919 die("failure: switch_ids");
6921 /* Verify we can't open it with our current credentials. */
6923 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6924 -1, false, &ret_cqe);
6926 die("failure: io_uring_open_file");
6928 die("failure: non-open() related io_uring_open_file failure %d", ret_cqe);
6929 if (ret_cqe != -EACCES)
6930 die("failure: errno(%d)", abs(ret_cqe));
6934 if (wait_for_pid(pid)) {
6935 log_stderr("failure: wait_for_pid");
6941 log_stderr("failure: fork");
6945 if (!switch_ids(1000, 1000))
6946 die("failure: switch_ids");
6948 /* Verify we can open it with the registered credentials. */
6949 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6950 cred_id, false, NULL);
6952 die("failure: io_uring_open_file");
6954 /* Verify we can open it with the registered credentials and as
6957 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
6958 cred_id, true, NULL);
6960 die("failure: io_uring_open_file");
6964 if (wait_for_pid(pid)) {
6965 log_stderr("failure: wait_for_pid");
6970 log_debug("Ran test");
6972 ret = io_uring_unregister_personality(ring, cred_id);
6974 log_stderr("failure: io_uring_unregister_personality");
6977 munmap(ring, sizeof(struct io_uring));
6979 safe_close(file1_fd);
6984 static int io_uring_userns(void)
6987 int file1_fd = -EBADF, userns_fd = -EBADF;
6988 struct io_uring *ring;
6989 int cred_id, ret, ret_cqe;
6992 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6993 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6995 return log_errno(-1, "failure: io_uring_queue_init");
6997 ret = io_uring_queue_init(8, ring, 0);
6999 log_stderr("failure: io_uring_queue_init");
7003 ret = io_uring_register_personality(ring);
7006 goto out_unmap; /* personalities not supported */
7010 /* create file only owner can open */
7011 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7013 log_stderr("failure: openat");
7016 if (fchown(file1_fd, 0, 0)) {
7017 log_stderr("failure: fchown");
7020 if (fchmod(file1_fd, 0600)) {
7021 log_stderr("failure: fchmod");
7024 safe_close(file1_fd);
7026 userns_fd = get_userns_fd(0, 10000, 10000);
7027 if (userns_fd < 0) {
7028 log_stderr("failure: get_userns_fd");
7034 log_stderr("failure: fork");
7038 /* Verify we can open it with our current credentials. */
7039 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7042 die("failure: io_uring_open_file");
7046 if (wait_for_pid(pid)) {
7047 log_stderr("failure: wait_for_pid");
7053 log_stderr("failure: fork");
7057 if (!switch_userns(userns_fd, 0, 0, false))
7058 die("failure: switch_userns");
7060 /* Verify we can't open it with our current credentials. */
7062 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7063 -1, false, &ret_cqe);
7065 die("failure: io_uring_open_file");
7067 die("failure: non-open() related io_uring_open_file failure");
7068 if (ret_cqe != -EACCES)
7069 die("failure: errno(%d)", abs(ret_cqe));
7073 if (wait_for_pid(pid)) {
7074 log_stderr("failure: wait_for_pid");
7080 log_stderr("failure: fork");
7084 if (!switch_userns(userns_fd, 0, 0, false))
7085 die("failure: switch_userns");
7087 /* Verify we can open it with the registered credentials. */
7088 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7089 cred_id, false, NULL);
7091 die("failure: io_uring_open_file");
7093 /* Verify we can open it with the registered credentials and as
7096 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7097 cred_id, true, NULL);
7099 die("failure: io_uring_open_file");
7103 if (wait_for_pid(pid)) {
7104 log_stderr("failure: wait_for_pid");
7109 log_debug("Ran test");
7111 ret = io_uring_unregister_personality(ring, cred_id);
7113 log_stderr("failure: io_uring_unregister_personality");
7116 munmap(ring, sizeof(struct io_uring));
7118 safe_close(file1_fd);
7119 safe_close(userns_fd);
7124 static int io_uring_idmapped(void)
7127 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7128 struct io_uring *ring;
7129 struct mount_attr attr = {
7130 .attr_set = MOUNT_ATTR_IDMAP,
7135 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7136 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7138 return log_errno(-1, "failure: io_uring_queue_init");
7140 ret = io_uring_queue_init(8, ring, 0);
7142 log_stderr("failure: io_uring_queue_init");
7146 ret = io_uring_register_personality(ring);
7149 goto out_unmap; /* personalities not supported */
7153 /* create file only owner can open */
7154 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7156 log_stderr("failure: openat");
7159 if (fchown(file1_fd, 0, 0)) {
7160 log_stderr("failure: fchown");
7163 if (fchmod(file1_fd, 0600)) {
7164 log_stderr("failure: fchmod");
7167 safe_close(file1_fd);
7169 /* Changing mount properties on a detached mount. */
7170 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7171 if (attr.userns_fd < 0)
7172 return log_errno(-1, "failure: create user namespace");
7174 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7177 AT_SYMLINK_NOFOLLOW |
7180 if (open_tree_fd < 0)
7181 return log_errno(-1, "failure: create detached mount");
7183 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7184 return log_errno(-1, "failure: set mount attributes");
7188 log_stderr("failure: fork");
7192 if (!switch_ids(10000, 10000))
7193 die("failure: switch_ids");
7195 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7198 die("failure: io_uring_open_file");
7202 if (wait_for_pid(pid)) {
7203 log_stderr("failure: wait_for_pid");
7209 log_stderr("failure: fork");
7213 if (!switch_ids(10001, 10001))
7214 die("failure: switch_ids");
7216 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7217 cred_id, false, NULL);
7219 die("failure: io_uring_open_file");
7221 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7222 cred_id, true, NULL);
7224 die("failure: io_uring_open_file");
7228 if (wait_for_pid(pid)) {
7229 log_stderr("failure: wait_for_pid");
7234 log_debug("Ran test");
7236 ret = io_uring_unregister_personality(ring, cred_id);
7238 log_stderr("failure: io_uring_unregister_personality");
7241 munmap(ring, sizeof(struct io_uring));
7243 safe_close(attr.userns_fd);
7244 safe_close(file1_fd);
7245 safe_close(open_tree_fd);
7251 * Create an idmapped mount where the we leave the owner of the file unmapped.
7252 * In no circumstances, even with recorded credentials can it be allowed to
7255 static int io_uring_idmapped_unmapped(void)
7258 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7259 struct io_uring *ring;
7260 struct mount_attr attr = {
7261 .attr_set = MOUNT_ATTR_IDMAP,
7263 int cred_id, ret, ret_cqe;
7266 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7267 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7269 return log_errno(-1, "failure: io_uring_queue_init");
7271 ret = io_uring_queue_init(8, ring, 0);
7273 log_stderr("failure: io_uring_queue_init");
7277 ret = io_uring_register_personality(ring);
7280 goto out_unmap; /* personalities not supported */
7284 /* create file only owner can open */
7285 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7287 log_stderr("failure: openat");
7290 if (fchown(file1_fd, 0, 0)) {
7291 log_stderr("failure: fchown");
7294 if (fchmod(file1_fd, 0600)) {
7295 log_stderr("failure: fchmod");
7298 safe_close(file1_fd);
7300 /* Changing mount properties on a detached mount. */
7301 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7302 if (attr.userns_fd < 0)
7303 return log_errno(-1, "failure: create user namespace");
7305 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7308 AT_SYMLINK_NOFOLLOW |
7311 if (open_tree_fd < 0)
7312 return log_errno(-1, "failure: create detached mount");
7314 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7315 return log_errno(-1, "failure: set mount attributes");
7319 log_stderr("failure: fork");
7323 if (!switch_ids(10000, 10000))
7324 die("failure: switch_ids");
7327 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7328 cred_id, false, &ret_cqe);
7330 die("failure: io_uring_open_file");
7332 die("failure: non-open() related io_uring_open_file failure");
7333 if (ret_cqe != -EACCES)
7334 die("failure: errno(%d)", abs(ret_cqe));
7337 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7338 cred_id, true, &ret_cqe);
7340 die("failure: io_uring_open_file");
7342 die("failure: non-open() related io_uring_open_file failure");
7343 if (ret_cqe != -EACCES)
7344 die("failure: errno(%d)", abs(ret_cqe));
7348 if (wait_for_pid(pid)) {
7349 log_stderr("failure: wait_for_pid");
7354 log_debug("Ran test");
7356 ret = io_uring_unregister_personality(ring, cred_id);
7358 log_stderr("failure: io_uring_unregister_personality");
7361 munmap(ring, sizeof(struct io_uring));
7363 safe_close(attr.userns_fd);
7364 safe_close(file1_fd);
7365 safe_close(open_tree_fd);
7370 static int io_uring_idmapped_userns(void)
7373 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7374 struct io_uring *ring;
7375 struct mount_attr attr = {
7376 .attr_set = MOUNT_ATTR_IDMAP,
7378 int cred_id, ret, ret_cqe;
7381 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7382 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7384 return log_errno(-1, "failure: io_uring_queue_init");
7386 ret = io_uring_queue_init(8, ring, 0);
7388 log_stderr("failure: io_uring_queue_init");
7392 ret = io_uring_register_personality(ring);
7395 goto out_unmap; /* personalities not supported */
7399 /* create file only owner can open */
7400 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7402 log_stderr("failure: openat");
7405 if (fchown(file1_fd, 0, 0)) {
7406 log_stderr("failure: fchown");
7409 if (fchmod(file1_fd, 0600)) {
7410 log_stderr("failure: fchmod");
7413 safe_close(file1_fd);
7415 /* Changing mount properties on a detached mount. */
7416 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7417 if (attr.userns_fd < 0)
7418 return log_errno(-1, "failure: create user namespace");
7420 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7423 AT_SYMLINK_NOFOLLOW |
7426 if (open_tree_fd < 0)
7427 return log_errno(-1, "failure: create detached mount");
7429 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7430 return log_errno(-1, "failure: set mount attributes");
7434 log_stderr("failure: fork");
7438 if (!switch_userns(attr.userns_fd, 0, 0, false))
7439 die("failure: switch_userns");
7441 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7444 die("failure: io_uring_open_file");
7448 if (wait_for_pid(pid)) {
7449 log_stderr("failure: wait_for_pid");
7455 log_stderr("failure: fork");
7459 if (!caps_supported()) {
7460 log_debug("skip: capability library not installed");
7464 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
7465 die("failure: switch_userns");
7468 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7469 -1, false, &ret_cqe);
7471 die("failure: io_uring_open_file");
7473 die("failure: non-open() related io_uring_open_file failure");
7474 if (ret_cqe != -EACCES)
7475 die("failure: errno(%d)", abs(ret_cqe));
7478 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7479 -1, true, &ret_cqe);
7481 die("failure: io_uring_open_file");
7483 die("failure: non-open() related io_uring_open_file failure");
7484 if (ret_cqe != -EACCES)
7485 die("failure: errno(%d)", abs(ret_cqe));
7488 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7489 -1, false, &ret_cqe);
7491 die("failure: io_uring_open_file");
7493 die("failure: non-open() related io_uring_open_file failure");
7494 if (ret_cqe != -EACCES)
7495 die("failure: errno(%d)", abs(ret_cqe));
7498 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7499 -1, true, &ret_cqe);
7501 die("failure: io_uring_open_file");
7503 die("failure: non-open() related io_uring_open_file failure");
7504 if (ret_cqe != -EACCES)
7505 die("failure: errno(%d)", abs(ret_cqe));
7507 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7508 cred_id, false, NULL);
7510 die("failure: io_uring_open_file");
7512 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7513 cred_id, true, NULL);
7515 die("failure: io_uring_open_file");
7519 if (wait_for_pid(pid)) {
7520 log_stderr("failure: wait_for_pid");
7525 log_debug("Ran test");
7527 ret = io_uring_unregister_personality(ring, cred_id);
7529 log_stderr("failure: io_uring_unregister_personality");
7532 munmap(ring, sizeof(struct io_uring));
7534 safe_close(attr.userns_fd);
7535 safe_close(file1_fd);
7536 safe_close(open_tree_fd);
7541 static int io_uring_idmapped_unmapped_userns(void)
7544 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7545 struct io_uring *ring;
7546 struct mount_attr attr = {
7547 .attr_set = MOUNT_ATTR_IDMAP,
7549 int cred_id, ret, ret_cqe;
7552 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7553 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7555 return log_errno(-1, "failure: io_uring_queue_init");
7557 ret = io_uring_queue_init(8, ring, 0);
7559 log_stderr("failure: io_uring_queue_init");
7563 ret = io_uring_register_personality(ring);
7566 goto out_unmap; /* personalities not supported */
7570 /* create file only owner can open */
7571 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7573 log_stderr("failure: openat");
7576 if (fchown(file1_fd, 0, 0)) {
7577 log_stderr("failure: fchown");
7580 if (fchmod(file1_fd, 0600)) {
7581 log_stderr("failure: fchmod");
7584 safe_close(file1_fd);
7586 /* Changing mount properties on a detached mount. */
7587 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7588 if (attr.userns_fd < 0)
7589 return log_errno(-1, "failure: create user namespace");
7591 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7594 AT_SYMLINK_NOFOLLOW |
7597 if (open_tree_fd < 0)
7598 return log_errno(-1, "failure: create detached mount");
7600 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7601 return log_errno(-1, "failure: set mount attributes");
7605 log_stderr("failure: fork");
7609 if (!caps_supported()) {
7610 log_debug("skip: capability library not installed");
7614 if (!switch_userns(attr.userns_fd, 10000, 10000, true))
7615 die("failure: switch_ids");
7618 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7619 cred_id, false, &ret_cqe);
7621 die("failure: io_uring_open_file");
7623 die("failure: non-open() related io_uring_open_file failure");
7624 if (ret_cqe != -EACCES)
7625 die("failure: errno(%d)", abs(ret_cqe));
7628 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7629 cred_id, true, &ret_cqe);
7631 die("failure: io_uring_open_file");
7633 die("failure: non-open() related io_uring_open_file failure");
7634 if (ret_cqe != -EACCES)
7635 die("failure: errno(%d)", abs(ret_cqe));
7639 if (wait_for_pid(pid)) {
7640 log_stderr("failure: wait_for_pid");
7645 log_debug("Ran test");
7647 ret = io_uring_unregister_personality(ring, cred_id);
7649 log_stderr("failure: io_uring_unregister_personality");
7652 munmap(ring, sizeof(struct io_uring));
7654 safe_close(attr.userns_fd);
7655 safe_close(file1_fd);
7656 safe_close(open_tree_fd);
7660 #endif /* HAVE_LIBURING_H */
7662 /* The following tests are concerned with setgid inheritance. These can be
7663 * filesystem type specific. For xfs, if a new file or directory is created
7664 * within a setgid directory and irix_sgid_inhiert is set then inherit the
7665 * setgid bit if the caller is in the group of the directory.
7667 static int setgid_create(void)
7670 int file1_fd = -EBADF;
7673 if (!caps_supported())
7676 if (fchmod(t_dir1_fd, S_IRUSR |
7686 log_stderr("failure: fchmod");
7690 /* Verify that the setgid bit got raised. */
7691 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7692 log_stderr("failure: is_setgid");
7698 log_stderr("failure: fork");
7702 /* create regular file via open() */
7703 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7705 die("failure: create");
7707 /* We're capable_wrt_inode_uidgid() and also our fsgid matches
7708 * the directories gid.
7710 if (!is_setgid(t_dir1_fd, FILE1, 0))
7711 die("failure: is_setgid");
7713 /* create directory */
7714 if (mkdirat(t_dir1_fd, DIR1, 0000))
7715 die("failure: create");
7717 /* Directories always inherit the setgid bit. */
7718 if (!is_setgid(t_dir1_fd, DIR1, 0))
7719 die("failure: is_setgid");
7721 if (unlinkat(t_dir1_fd, FILE1, 0))
7722 die("failure: delete");
7724 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7725 die("failure: delete");
7729 if (wait_for_pid(pid))
7734 log_stderr("failure: fork");
7738 if (!switch_ids(0, 10000))
7739 die("failure: switch_ids");
7742 die("failure: caps_down");
7744 /* create regular file via open() */
7745 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7747 die("failure: create");
7749 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7750 * bit needs to be stripped.
7752 if (is_setgid(t_dir1_fd, FILE1, 0))
7753 die("failure: is_setgid");
7755 /* create directory */
7756 if (mkdirat(t_dir1_fd, DIR1, 0000))
7757 die("failure: create");
7759 if (xfs_irix_sgid_inherit_enabled()) {
7760 /* We're not in_group_p(). */
7761 if (is_setgid(t_dir1_fd, DIR1, 0))
7762 die("failure: is_setgid");
7764 /* Directories always inherit the setgid bit. */
7765 if (!is_setgid(t_dir1_fd, DIR1, 0))
7766 die("failure: is_setgid");
7771 if (wait_for_pid(pid))
7775 log_debug("Ran test");
7777 safe_close(file1_fd);
7782 static int setgid_create_idmapped(void)
7785 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7786 struct mount_attr attr = {
7787 .attr_set = MOUNT_ATTR_IDMAP,
7791 if (!caps_supported())
7794 if (fchmod(t_dir1_fd, S_IRUSR |
7804 log_stderr("failure: fchmod");
7808 /* Verify that the sid bits got raised. */
7809 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7810 log_stderr("failure: is_setgid");
7814 /* Changing mount properties on a detached mount. */
7815 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7816 if (attr.userns_fd < 0) {
7817 log_stderr("failure: get_userns_fd");
7821 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7824 AT_SYMLINK_NOFOLLOW |
7827 if (open_tree_fd < 0) {
7828 log_stderr("failure: sys_open_tree");
7832 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7833 log_stderr("failure: sys_mount_setattr");
7839 log_stderr("failure: fork");
7843 if (!switch_ids(10000, 11000))
7844 die("failure: switch fsids");
7846 /* create regular file via open() */
7847 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7849 die("failure: create");
7851 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7852 * bit needs to be stripped.
7854 if (is_setgid(open_tree_fd, FILE1, 0))
7855 die("failure: is_setgid");
7857 /* create directory */
7858 if (mkdirat(open_tree_fd, DIR1, 0000))
7859 die("failure: create");
7861 if (xfs_irix_sgid_inherit_enabled()) {
7862 /* We're not in_group_p(). */
7863 if (is_setgid(open_tree_fd, DIR1, 0))
7864 die("failure: is_setgid");
7866 /* Directories always inherit the setgid bit. */
7867 if (!is_setgid(open_tree_fd, DIR1, 0))
7868 die("failure: is_setgid");
7873 if (wait_for_pid(pid))
7877 log_debug("Ran test");
7879 safe_close(attr.userns_fd);
7880 safe_close(file1_fd);
7881 safe_close(open_tree_fd);
7886 static int setgid_create_idmapped_in_userns(void)
7889 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7890 struct mount_attr attr = {
7891 .attr_set = MOUNT_ATTR_IDMAP,
7895 if (!caps_supported())
7898 if (fchmod(t_dir1_fd, S_IRUSR |
7908 log_stderr("failure: fchmod");
7912 /* Verify that the sid bits got raised. */
7913 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7914 log_stderr("failure: is_setgid");
7918 /* Changing mount properties on a detached mount. */
7919 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7920 if (attr.userns_fd < 0) {
7921 log_stderr("failure: get_userns_fd");
7925 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7928 AT_SYMLINK_NOFOLLOW |
7931 if (open_tree_fd < 0) {
7932 log_stderr("failure: sys_open_tree");
7936 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7937 log_stderr("failure: sys_mount_setattr");
7943 log_stderr("failure: fork");
7947 if (!switch_userns(attr.userns_fd, 0, 0, false))
7948 die("failure: switch_userns");
7950 /* create regular file via open() */
7951 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7953 die("failure: create");
7955 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
7956 * bit needs to be set.
7958 if (!is_setgid(open_tree_fd, FILE1, 0))
7959 die("failure: is_setgid");
7961 /* create directory */
7962 if (mkdirat(open_tree_fd, DIR1, 0000))
7963 die("failure: create");
7965 /* Directories always inherit the setgid bit. */
7966 if (!is_setgid(open_tree_fd, DIR1, 0))
7967 die("failure: is_setgid");
7969 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
7970 die("failure: check ownership");
7972 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
7973 die("failure: check ownership");
7975 if (unlinkat(open_tree_fd, FILE1, 0))
7976 die("failure: delete");
7978 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
7979 die("failure: delete");
7983 if (wait_for_pid(pid))
7986 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7987 log_stderr("failure: fchownat");
7991 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
7992 log_stderr("failure: fchownat");
7998 log_stderr("failure: fork");
8002 if (!caps_supported()) {
8003 log_debug("skip: capability library not installed");
8007 if (!switch_userns(attr.userns_fd, 0, 0, true))
8008 die("failure: switch_userns");
8010 /* create regular file via open() */
8011 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8013 die("failure: create");
8015 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8016 * bit needs to be stripped.
8018 if (is_setgid(open_tree_fd, FILE1, 0))
8019 die("failure: is_setgid");
8021 /* create directory */
8022 if (mkdirat(open_tree_fd, DIR1, 0000))
8023 die("failure: create");
8025 if (xfs_irix_sgid_inherit_enabled()) {
8026 /* We're not in_group_p(). */
8027 if (is_setgid(open_tree_fd, DIR1, 0))
8028 die("failure: is_setgid");
8030 /* Directories always inherit the setgid bit. */
8031 if (!is_setgid(open_tree_fd, DIR1, 0))
8032 die("failure: is_setgid");
8035 /* Files and directories created in setgid directories inherit
8036 * the i_gid of the parent directory.
8038 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8039 die("failure: check ownership");
8041 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8042 die("failure: check ownership");
8044 if (unlinkat(open_tree_fd, FILE1, 0))
8045 die("failure: delete");
8047 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8048 die("failure: delete");
8052 if (wait_for_pid(pid))
8055 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8056 log_stderr("failure: fchownat");
8060 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8061 log_stderr("failure: fchownat");
8067 log_stderr("failure: fork");
8071 if (!caps_supported()) {
8072 log_debug("skip: capability library not installed");
8076 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8077 die("failure: switch_userns");
8079 /* create regular file via open() */
8080 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8082 die("failure: create");
8084 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8085 * bit needs to be stripped.
8087 if (is_setgid(open_tree_fd, FILE1, 0))
8088 die("failure: is_setgid");
8090 /* create directory */
8091 if (mkdirat(open_tree_fd, DIR1, 0000))
8092 die("failure: create");
8094 /* Directories always inherit the setgid bit. */
8095 if (xfs_irix_sgid_inherit_enabled()) {
8096 /* We're not in_group_p(). */
8097 if (is_setgid(open_tree_fd, DIR1, 0))
8098 die("failure: is_setgid");
8100 /* Directories always inherit the setgid bit. */
8101 if (!is_setgid(open_tree_fd, DIR1, 0))
8102 die("failure: is_setgid");
8105 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8106 die("failure: check ownership");
8108 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8109 die("failure: check ownership");
8113 if (wait_for_pid(pid))
8117 log_debug("Ran test");
8119 safe_close(attr.userns_fd);
8120 safe_close(file1_fd);
8121 safe_close(open_tree_fd);
8126 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8127 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8129 static void *idmapped_mount_create_cb(void *data)
8131 int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8132 struct mount_attr attr = {
8133 .attr_set = MOUNT_ATTR_IDMAP,
8136 /* Changing mount properties on a detached mount. */
8137 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8138 if (attr.userns_fd < 0) {
8139 log_stderr("failure: get_userns_fd");
8143 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8144 log_stderr("failure: sys_mount_setattr");
8148 fret = EXIT_SUCCESS;
8151 safe_close(attr.userns_fd);
8152 pthread_exit(INT_TO_PTR(fret));
8155 /* This tries to verify that we never see an inconistent ownership on-disk and
8156 * can't write invalid ids to disk. To do this we create a race between
8157 * idmapping a mount and creating files on it.
8158 * Note, while it is perfectly fine to see overflowuid and overflowgid as owner
8159 * if we create files through the open_tree_fd before the mount is idmapped but
8160 * look at the files after the mount has been idmapped in this test it can never
8161 * be the case that we see overflowuid and overflowgid when we access the file
8162 * through a non-idmapped mount (in the initial user namespace).
8164 static void *idmapped_mount_operations_cb(void *data)
8166 int file1_fd = -EBADF, file2_fd = -EBADF, dir1_fd = -EBADF,
8167 dir1_fd2 = -EBADF, fret = EXIT_FAILURE,
8168 open_tree_fd = PTR_TO_INT(data);
8170 if (!switch_fsids(10000, 10000)) {
8171 log_stderr("failure: switch fsids");
8175 file1_fd = openat(open_tree_fd, FILE1,
8176 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8178 log_stderr("failure: openat");
8182 file2_fd = openat(open_tree_fd, FILE2,
8183 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8185 log_stderr("failure: openat");
8189 if (mkdirat(open_tree_fd, DIR1, 0777)) {
8190 log_stderr("failure: mkdirat");
8194 dir1_fd = openat(open_tree_fd, DIR1,
8195 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8197 log_stderr("failure: openat");
8201 if (!__expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0, false) &&
8202 !__expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000, false) &&
8203 !__expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid, false)) {
8204 log_stderr("failure: expected_uid_gid");
8208 if (!__expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0, false) &&
8209 !__expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000, false) &&
8210 !__expected_uid_gid(open_tree_fd, FILE2, 0, t_overflowuid, t_overflowgid, false)) {
8211 log_stderr("failure: expected_uid_gid");
8215 if (!__expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0, false) &&
8216 !__expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000, false) &&
8217 !__expected_uid_gid(open_tree_fd, DIR1, 0, t_overflowuid, t_overflowgid, false)) {
8218 log_stderr("failure: expected_uid_gid");
8222 if (!__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 0, 0, false) &&
8223 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 10000, 10000, false) &&
8224 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, t_overflowuid, t_overflowgid, false)) {
8225 log_stderr("failure: expected_uid_gid");
8229 dir1_fd2 = openat(t_dir1_fd, DIR1,
8230 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8232 log_stderr("failure: openat");
8236 if (!__expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0, false) &&
8237 !__expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000, false)) {
8238 log_stderr("failure: expected_uid_gid");
8242 if (!__expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0, false) &&
8243 !__expected_uid_gid(t_dir1_fd, FILE2, 0, 10000, 10000, false)) {
8244 log_stderr("failure: expected_uid_gid");
8248 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8249 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8250 log_stderr("failure: expected_uid_gid");
8254 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8255 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8256 log_stderr("failure: expected_uid_gid");
8260 if (!__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 0, 0, false) &&
8261 !__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 10000, 10000, false)) {
8262 log_stderr("failure: expected_uid_gid");
8266 fret = EXIT_SUCCESS;
8269 safe_close(file1_fd);
8270 safe_close(file2_fd);
8271 safe_close(dir1_fd);
8272 safe_close(dir1_fd2);
8274 pthread_exit(INT_TO_PTR(fret));
8277 static int threaded_idmapped_mount_interactions(void)
8282 pthread_attr_t thread_attr;
8283 pthread_t threads[2];
8285 pthread_attr_init(&thread_attr);
8287 for (i = 0; i < 1000; i++) {
8288 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8292 log_stderr("failure: fork");
8296 int open_tree_fd = -EBADF;
8298 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8301 AT_SYMLINK_NOFOLLOW |
8304 if (open_tree_fd < 0)
8305 die("failure: sys_open_tree");
8307 if (pthread_create(&threads[0], &thread_attr,
8308 idmapped_mount_create_cb,
8309 INT_TO_PTR(open_tree_fd)))
8310 die("failure: pthread_create");
8312 if (pthread_create(&threads[1], &thread_attr,
8313 idmapped_mount_operations_cb,
8314 INT_TO_PTR(open_tree_fd)))
8315 die("failure: pthread_create");
8317 ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8318 ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8322 die("failure: pthread_join");
8327 die("failure: pthread_join");
8337 if (wait_for_pid(pid)) {
8338 log_stderr("failure: iteration %d", i);
8342 rm_r(t_dir1_fd, ".");
8347 log_debug("Ran test");
8353 static int setattr_truncate(void)
8356 int file1_fd = -EBADF;
8358 /* create regular file via open() */
8359 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8361 log_stderr("failure: create");
8365 if (ftruncate(file1_fd, 10000)) {
8366 log_stderr("failure: ftruncate");
8370 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8371 log_stderr("failure: check ownership");
8375 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8376 log_stderr("failure: expected_file_size");
8380 if (ftruncate(file1_fd, 0)) {
8381 log_stderr("failure: ftruncate");
8385 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8386 log_stderr("failure: check ownership");
8390 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8391 log_stderr("failure: expected_file_size");
8395 if (unlinkat(t_dir1_fd, FILE1, 0)) {
8396 log_stderr("failure: remove");
8401 log_debug("Ran test");
8403 safe_close(file1_fd);
8408 static int setattr_truncate_idmapped(void)
8411 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8413 struct mount_attr attr = {
8414 .attr_set = MOUNT_ATTR_IDMAP,
8417 /* Changing mount properties on a detached mount. */
8418 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8419 if (attr.userns_fd < 0) {
8420 log_stderr("failure: get_userns_fd");
8424 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8427 AT_SYMLINK_NOFOLLOW |
8430 if (open_tree_fd < 0) {
8431 log_stderr("failure: sys_open_tree");
8435 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8436 log_stderr("failure: sys_mount_setattr");
8442 log_stderr("failure: fork");
8446 if (!switch_ids(10000, 10000))
8447 die("failure: switch_ids");
8449 /* create regular file via open() */
8450 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8452 die("failure: create");
8454 if (ftruncate(file1_fd, 10000))
8455 die("failure: ftruncate");
8457 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8458 die("failure: check ownership");
8460 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8461 die("failure: expected_file_size");
8463 if (ftruncate(file1_fd, 0))
8464 die("failure: ftruncate");
8466 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8467 die("failure: check ownership");
8469 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8470 die("failure: expected_file_size");
8474 if (wait_for_pid(pid))
8479 log_stderr("failure: fork");
8483 int file1_fd2 = -EBADF;
8485 /* create regular file via open() */
8486 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8488 die("failure: create");
8490 if (ftruncate(file1_fd2, 10000))
8491 die("failure: ftruncate");
8493 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8494 die("failure: check ownership");
8496 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8497 die("failure: expected_file_size");
8499 if (ftruncate(file1_fd2, 0))
8500 die("failure: ftruncate");
8502 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8503 die("failure: check ownership");
8505 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8506 die("failure: expected_file_size");
8510 if (wait_for_pid(pid))
8514 log_debug("Ran test");
8516 safe_close(file1_fd);
8517 safe_close(open_tree_fd);
8522 static int setattr_truncate_idmapped_in_userns(void)
8525 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8526 struct mount_attr attr = {
8527 .attr_set = MOUNT_ATTR_IDMAP,
8531 /* Changing mount properties on a detached mount. */
8532 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8533 if (attr.userns_fd < 0) {
8534 log_stderr("failure: get_userns_fd");
8538 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8541 AT_SYMLINK_NOFOLLOW |
8544 if (open_tree_fd < 0) {
8545 log_stderr("failure: sys_open_tree");
8549 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8550 log_stderr("failure: sys_mount_setattr");
8556 log_stderr("failure: fork");
8560 if (!switch_userns(attr.userns_fd, 0, 0, false))
8561 die("failure: switch_userns");
8563 /* create regular file via open() */
8564 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8566 die("failure: create");
8568 if (ftruncate(file1_fd, 10000))
8569 die("failure: ftruncate");
8571 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8572 die("failure: check ownership");
8574 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8575 die("failure: expected_file_size");
8577 if (ftruncate(file1_fd, 0))
8578 die("failure: ftruncate");
8580 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8581 die("failure: check ownership");
8583 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8584 die("failure: expected_file_size");
8586 if (unlinkat(open_tree_fd, FILE1, 0))
8587 die("failure: delete");
8591 if (wait_for_pid(pid))
8594 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8595 log_stderr("failure: fchownat");
8599 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8600 log_stderr("failure: fchownat");
8606 log_stderr("failure: fork");
8610 if (!caps_supported()) {
8611 log_debug("skip: capability library not installed");
8615 if (!switch_userns(attr.userns_fd, 0, 0, true))
8616 die("failure: switch_userns");
8618 /* create regular file via open() */
8619 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8621 die("failure: create");
8623 if (ftruncate(file1_fd, 10000))
8624 die("failure: ftruncate");
8626 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8627 die("failure: check ownership");
8629 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8630 die("failure: expected_file_size");
8632 if (ftruncate(file1_fd, 0))
8633 die("failure: ftruncate");
8635 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8636 die("failure: check ownership");
8638 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8639 die("failure: expected_file_size");
8641 if (unlinkat(open_tree_fd, FILE1, 0))
8642 die("failure: delete");
8646 if (wait_for_pid(pid))
8649 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8650 log_stderr("failure: fchownat");
8654 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8655 log_stderr("failure: fchownat");
8661 log_stderr("failure: fork");
8665 if (!caps_supported()) {
8666 log_debug("skip: capability library not installed");
8670 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8671 die("failure: switch_userns");
8673 /* create regular file via open() */
8674 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8676 die("failure: create");
8678 if (ftruncate(file1_fd, 10000))
8679 die("failure: ftruncate");
8681 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8682 die("failure: check ownership");
8684 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8685 die("failure: expected_file_size");
8687 if (ftruncate(file1_fd, 0))
8688 die("failure: ftruncate");
8690 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8691 die("failure: check ownership");
8693 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8694 die("failure: expected_file_size");
8696 if (unlinkat(open_tree_fd, FILE1, 0))
8697 die("failure: delete");
8701 if (wait_for_pid(pid))
8705 log_debug("Ran test");
8707 safe_close(attr.userns_fd);
8708 safe_close(file1_fd);
8709 safe_close(open_tree_fd);
8714 static void usage(void)
8716 fprintf(stderr, "Description:\n");
8717 fprintf(stderr, " Run idmapped mount tests\n\n");
8719 fprintf(stderr, "Arguments:\n");
8720 fprintf(stderr, "-d --device Device used in the tests\n");
8721 fprintf(stderr, "-m --mountpoint Mountpoint of device\n");
8723 _exit(EXIT_SUCCESS);
8726 static const struct option longopts[] = {
8727 {"device", required_argument, 0, 'd'},
8728 {"fstype", required_argument, 0, 'f'},
8729 {"mountpoint", required_argument, 0, 'm'},
8730 {"supported", no_argument, 0, 's'},
8731 {"help", no_argument, 0, 'h'},
8735 struct t_idmapped_mounts {
8737 const char *description;
8739 { acls, "posix acls on regular mounts", },
8740 { create_in_userns, "create operations in user namespace", },
8741 { device_node_in_userns, "device node in user namespace", },
8742 { expected_uid_gid_idmapped_mounts, "expected ownership on idmapped mounts", },
8743 { fscaps, "fscaps on regular mounts", },
8744 { fscaps_idmapped_mounts, "fscaps on idmapped mounts", },
8745 { fscaps_idmapped_mounts_in_userns, "fscaps on idmapped mounts in user namespace", },
8746 { fscaps_idmapped_mounts_in_userns_separate_userns, "fscaps on idmapped mounts in user namespace with different id mappings ", },
8747 { fsids_mapped, "mapped fsids", },
8748 { fsids_unmapped, "unmapped fsids", },
8749 { hardlink_crossing_mounts, "cross mount hardlink", },
8750 { hardlink_crossing_idmapped_mounts, "cross idmapped mount hardlink", },
8751 { hardlink_from_idmapped_mount, "hardlinks from idmapped mounts", },
8752 { hardlink_from_idmapped_mount_in_userns, "hardlinks from idmapped mounts in user namespace", },
8753 #ifdef HAVE_LIBURING_H
8754 { io_uring, "io_uring", },
8755 { io_uring_userns, "io_uring in user namespace", },
8756 { io_uring_idmapped, "io_uring from idmapped mounts", },
8757 { io_uring_idmapped_userns, "io_uring from idmapped mounts in user namespace", },
8758 { io_uring_idmapped_unmapped, "io_uring from idmapped mounts with unmapped ids", },
8759 { io_uring_idmapped_unmapped_userns, "io_uring from idmapped mounts with unmapped ids in user namespace", },
8761 { protected_symlinks, "following protected symlinks on regular mounts", },
8762 { protected_symlinks_idmapped_mounts, "following protected symlinks on idmapped mounts", },
8763 { protected_symlinks_idmapped_mounts_in_userns, "following protected symlinks on idmapped mounts in user namespace", },
8764 { rename_crossing_mounts, "cross mount rename", },
8765 { rename_crossing_idmapped_mounts, "cross idmapped mount rename", },
8766 { rename_from_idmapped_mount, "rename from idmapped mounts", },
8767 { rename_from_idmapped_mount_in_userns, "rename from idmapped mounts in user namespace", },
8768 { setattr_truncate, "setattr truncate", },
8769 { setattr_truncate_idmapped, "setattr truncate on idmapped mounts", },
8770 { setattr_truncate_idmapped_in_userns, "setattr truncate on idmapped mounts in user namespace", },
8771 { setgid_create, "create operations in directories with setgid bit set", },
8772 { setgid_create_idmapped, "create operations in directories with setgid bit set on idmapped mounts", },
8773 { setgid_create_idmapped_in_userns, "create operations in directories with setgid bit set on idmapped mounts in user namespace", },
8774 { setid_binaries, "setid binaries on regular mounts", },
8775 { setid_binaries_idmapped_mounts, "setid binaries on idmapped mounts", },
8776 { setid_binaries_idmapped_mounts_in_userns, "setid binaries on idmapped mounts in user namespace", },
8777 { setid_binaries_idmapped_mounts_in_userns_separate_userns, "setid binaries on idmapped mounts in user namespace with different id mappings", },
8778 { sticky_bit_unlink, "sticky bit unlink operations on regular mounts", },
8779 { sticky_bit_unlink_idmapped_mounts, "sticky bit unlink operations on idmapped mounts", },
8780 { sticky_bit_unlink_idmapped_mounts_in_userns, "sticky bit unlink operations on idmapped mounts in user namespace", },
8781 { sticky_bit_rename, "sticky bit rename operations on regular mounts", },
8782 { sticky_bit_rename_idmapped_mounts, "sticky bit rename operations on idmapped mounts", },
8783 { sticky_bit_rename_idmapped_mounts_in_userns, "sticky bit rename operations on idmapped mounts in user namespace", },
8784 { symlink_regular_mounts, "symlink from regular mounts", },
8785 { symlink_idmapped_mounts, "symlink from idmapped mounts", },
8786 { symlink_idmapped_mounts_in_userns, "symlink from idmapped mounts in user namespace", },
8787 { threaded_idmapped_mount_interactions, "threaded operations on idmapped mounts", },
8790 static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size)
8794 for (i = 0; i < suite_size; i++) {
8795 struct t_idmapped_mounts *t = &suite[i];
8808 fprintf(stderr, "failure: %s\n", t->description);
8815 ret = wait_for_pid(pid);
8825 int main(int argc, char *argv[])
8829 bool supported = false;
8831 while ((ret = getopt_long(argc, argv, "", longopts, &index)) != -1) {
8840 t_mountpoint = optarg;
8853 die_errno(EINVAL, "test device missing");
8856 die_errno(EINVAL, "test filesystem type missing");
8859 die_errno(EINVAL, "mountpoint of test device missing");
8861 /* create separate mount namespace */
8862 if (unshare(CLONE_NEWNS))
8863 die("failure: create new mount namespace");
8865 /* turn off mount propagation */
8866 if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
8867 die("failure: turn mount propagation off");
8869 t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
8871 die("failed to open %s", t_mountpoint);
8874 * Caller just wants to know whether the filesystem we're on supports
8878 int open_tree_fd = -EBADF;
8879 struct mount_attr attr = {
8880 .attr_set = MOUNT_ATTR_IDMAP,
8881 .userns_fd = -EBADF,
8884 /* Changing mount properties on a detached mount. */
8885 attr.userns_fd = get_userns_fd(0, 1000, 1);
8886 if (attr.userns_fd < 0)
8889 open_tree_fd = sys_open_tree(t_mnt_fd, "",
8892 AT_SYMLINK_NOFOLLOW |
8895 if (open_tree_fd < 0)
8898 ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr));
8900 close(open_tree_fd);
8901 close(attr.userns_fd);
8909 stash_overflowuid();
8910 stash_overflowgid();
8912 fret = EXIT_FAILURE;
8914 if (!run_test(basic_suite, ARRAY_SIZE(basic_suite)))
8917 fret = EXIT_SUCCESS;