1 // SPDX-License-Identifier: GPL-2.0
14 #include <linux/limits.h>
15 #include <linux/types.h>
20 #include <sys/fsuid.h>
22 #include <sys/types.h>
23 #include <sys/xattr.h>
26 #ifdef HAVE_LINUX_BTRFS_H
27 # ifndef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2_SUBVOLID
28 # define btrfs_ioctl_vol_args_v2 override_btrfs_ioctl_vol_args_v2
30 #include <linux/btrfs.h>
31 # undef btrfs_ioctl_vol_args_v2
34 #ifdef HAVE_LINUX_BTRFS_TREE_H
35 #include <linux/btrfs_tree.h>
38 #ifdef HAVE_SYS_CAPABILITY_H
39 #include <sys/capability.h>
42 #ifdef HAVE_LIBURING_H
49 #define T_DIR1 "idmapped_mounts_1"
51 #define FILE1_RENAME "file1_rename"
53 #define FILE2_RENAME "file2_rename"
57 #define DIR1_RENAME "dir1_rename"
58 #define HARDLINK1 "hardlink1"
59 #define SYMLINK1 "symlink1"
60 #define SYMLINK_USER1 "symlink_user1"
61 #define SYMLINK_USER2 "symlink_user2"
62 #define SYMLINK_USER3 "symlink_user3"
63 #define CHRDEV1 "chrdev1"
65 #define log_stderr(format, ...) \
66 fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \
70 #define log_debug(format, ...) \
71 fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \
72 __func__, ##__VA_ARGS__)
74 #define log_debug(format, ...)
77 #define log_error_errno(__ret__, __errno__, format, ...) \
79 typeof(__ret__) __internal_ret__ = (__ret__); \
80 errno = (__errno__); \
81 log_stderr(format, ##__VA_ARGS__); \
85 #define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__)
87 #define die_errno(__errno__, format, ...) \
89 errno = (__errno__); \
90 log_stderr(format, ##__VA_ARGS__); \
94 #define die(format, ...) die_errno(errno, format, ##__VA_ARGS__)
96 #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
98 uid_t t_overflowuid = 65534;
99 gid_t t_overflowgid = 65534;
101 /* path of the test device */
102 const char *t_fstype;
104 /* path of the test device */
105 const char *t_device;
107 /* path of the test scratch device */
108 const char *t_device_scratch;
110 /* mountpoint of the test device */
111 const char *t_mountpoint;
113 /* mountpoint of the test device */
114 const char *t_mountpoint_scratch;
116 /* fd for @t_mountpoint */
119 /* fd for @t_mountpoint_scratch */
120 int t_mnt_scratch_fd;
125 /* temporary buffer */
126 char t_buf[PATH_MAX];
128 static void stash_overflowuid(void)
134 fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
138 ret = read(fd, buf, sizeof(buf));
143 t_overflowuid = atoi(buf);
146 static void stash_overflowgid(void)
152 fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
156 ret = read(fd, buf, sizeof(buf));
161 t_overflowgid = atoi(buf);
164 static bool is_xfs(void)
166 static int enabled = -1;
169 enabled = !strcmp(t_fstype, "xfs");
174 static bool protected_symlinks_enabled(void)
176 static int enabled = -1;
185 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
189 ret = read(fd, buf, sizeof(buf));
201 static bool xfs_irix_sgid_inherit_enabled(void)
203 static int enabled = -1;
213 fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
217 ret = read(fd, buf, sizeof(buf));
230 static inline bool caps_supported(void)
234 #ifdef HAVE_SYS_CAPABILITY_H
241 /* caps_down - lower all effective caps */
242 static int caps_down(void)
245 #ifdef HAVE_SYS_CAPABILITY_H
249 caps = cap_get_proc();
253 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
257 ret = cap_set_proc(caps);
269 /* caps_up - raise all permitted caps */
270 static int caps_up(void)
273 #ifdef HAVE_SYS_CAPABILITY_H
278 caps = cap_get_proc();
282 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
283 cap_flag_value_t flag;
285 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
293 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
298 ret = cap_set_proc(caps);
309 /* __expected_uid_gid - check whether file is owned by the provided uid and gid */
310 static bool __expected_uid_gid(int dfd, const char *path, int flags,
311 uid_t expected_uid, gid_t expected_gid, bool log)
316 ret = fstatat(dfd, path, &st, flags);
318 return log_errno(false, "failure: fstatat");
320 if (log && st.st_uid != expected_uid)
321 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
323 if (log && st.st_gid != expected_gid)
324 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
326 errno = 0; /* Don't report misleading errno. */
327 return st.st_uid == expected_uid && st.st_gid == expected_gid;
330 static bool expected_uid_gid(int dfd, const char *path, int flags,
331 uid_t expected_uid, gid_t expected_gid)
333 return __expected_uid_gid(dfd, path, flags,
334 expected_uid, expected_gid, true);
337 static bool expected_file_size(int dfd, const char *path,
338 int flags, off_t expected_size)
343 ret = fstatat(dfd, path, &st, flags);
345 return log_errno(false, "failure: fstatat");
347 if (st.st_size != expected_size)
348 return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)",
349 (size_t)st.st_size, (size_t)expected_size);
354 /* is_setid - check whether file is S_ISUID and S_ISGID */
355 static bool is_setid(int dfd, const char *path, int flags)
360 ret = fstatat(dfd, path, &st, flags);
364 errno = 0; /* Don't report misleading errno. */
365 return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
368 /* is_setgid - check whether file or directory is S_ISGID */
369 static bool is_setgid(int dfd, const char *path, int flags)
374 ret = fstatat(dfd, path, &st, flags);
378 errno = 0; /* Don't report misleading errno. */
379 return (st.st_mode & S_ISGID);
382 /* is_sticky - check whether file is S_ISVTX */
383 static bool is_sticky(int dfd, const char *path, int flags)
388 ret = fstatat(dfd, path, &st, flags);
392 errno = 0; /* Don't report misleading errno. */
393 return (st.st_mode & S_ISVTX) > 0;
396 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
399 return log_errno(false, "failure: setfsgid");
401 if (setfsgid(-1) != fsgid)
402 return log_errno(false, "failure: setfsgid(-1)");
405 return log_errno(false, "failure: setfsuid");
407 if (setfsuid(-1) != fsuid)
408 return log_errno(false, "failure: setfsuid(-1)");
413 static inline bool switch_resids(uid_t uid, gid_t gid)
415 if (setresgid(gid, gid, gid))
416 return log_errno(false, "failure: setregid");
418 if (setresuid(uid, uid, uid))
419 return log_errno(false, "failure: setresuid");
421 if (setfsgid(-1) != gid)
422 return log_errno(false, "failure: setfsgid(-1)");
424 if (setfsuid(-1) != uid)
425 return log_errno(false, "failure: setfsuid(-1)");
430 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
432 if (setns(fd, CLONE_NEWUSER))
433 return log_errno(false, "failure: setns");
435 if (!switch_ids(uid, gid))
436 return log_errno(false, "failure: switch_ids");
438 if (drop_caps && !caps_down())
439 return log_errno(false, "failure: caps_down");
444 /* rm_r - recursively remove all files */
445 static int rm_r(int fd, const char *path)
449 struct dirent *direntp;
451 if (!path || strcmp(path, "") == 0)
454 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
458 dir = fdopendir(dfd);
464 while ((direntp = readdir(dir))) {
467 if (!strcmp(direntp->d_name, ".") ||
468 !strcmp(direntp->d_name, ".."))
471 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
472 if (ret < 0 && errno != ENOENT)
475 if (S_ISDIR(st.st_mode))
476 ret = rm_r(dfd, direntp->d_name);
478 ret = unlinkat(dfd, direntp->d_name, 0);
479 if (ret < 0 && errno != ENOENT)
483 ret = unlinkat(fd, path, AT_REMOVEDIR);
488 /* chown_r - recursively change ownership of all files */
489 static int chown_r(int fd, const char *path, uid_t uid, gid_t gid)
493 struct dirent *direntp;
495 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
499 dir = fdopendir(dfd);
505 while ((direntp = readdir(dir))) {
508 if (!strcmp(direntp->d_name, ".") ||
509 !strcmp(direntp->d_name, ".."))
512 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
513 if (ret < 0 && errno != ENOENT)
516 if (S_ISDIR(st.st_mode))
517 ret = chown_r(dfd, direntp->d_name, uid, gid);
519 ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
520 if (ret < 0 && errno != ENOENT)
524 ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
530 * There'll be scenarios where you'll want to see the attributes associated with
531 * a directory tree during debugging or just to make sure things look correct.
532 * Simply uncomment and place the print_r() helper where you need it.
535 static int fd_cloexec(int fd, bool cloexec)
539 oflags = fcntl(fd, F_GETFD, 0);
544 nflags = oflags | FD_CLOEXEC;
546 nflags = oflags & ~FD_CLOEXEC;
548 if (nflags == oflags)
551 if (fcntl(fd, F_SETFD, nflags) < 0)
557 static inline int dup_cloexec(int fd)
565 if (fd_cloexec(fd_dup, true)) {
573 __attribute__((unused)) static int print_r(int fd, const char *path)
578 struct dirent *direntp;
581 if (!path || *path == '\0') {
582 char buf[sizeof("/proc/self/fd/") + 30];
584 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
585 if (ret < 0 || (size_t)ret >= sizeof(buf))
589 * O_PATH file descriptors can't be used so we need to re-open
592 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
594 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
600 * When fdopendir() below succeeds it assumes ownership of the fd so we
601 * to make sure we always have an fd that fdopendir() can own which is
602 * why we dup() in the case where the caller wants us to operate on the
605 dfd_dup = dup_cloexec(dfd);
611 dir = fdopendir(dfd);
617 /* Transfer ownership to fdopendir(). */
620 while ((direntp = readdir(dir))) {
621 if (!strcmp(direntp->d_name, ".") ||
622 !strcmp(direntp->d_name, ".."))
625 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
626 if (ret < 0 && errno != ENOENT)
630 if (S_ISDIR(st.st_mode))
631 ret = print_r(dfd_dup, direntp->d_name);
633 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n",
634 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
635 dfd_dup, direntp->d_name);
636 if (ret < 0 && errno != ENOENT)
640 if (!path || *path == '\0')
641 ret = fstatat(fd, "", &st,
642 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
645 ret = fstatat(fd, path, &st,
646 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
648 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n",
649 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
650 (path && *path) ? path : "(null)");
658 __attribute__((unused)) static int print_r(int fd, const char *path)
664 /* fd_to_fd - transfer data from one fd to another */
665 static int fd_to_fd(int from, int to)
668 uint8_t buf[PATH_MAX];
670 ssize_t bytes_to_write;
673 bytes_read = read_nointr(from, buf, sizeof buf);
679 bytes_to_write = (size_t)bytes_read;
681 ssize_t bytes_written;
683 bytes_written = write_nointr(to, p, bytes_to_write);
684 if (bytes_written < 0)
687 bytes_to_write -= bytes_written;
689 } while (bytes_to_write > 0);
695 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
699 return syscall(__NR_execveat, fd, path, argv, envp, flags);
707 #define CAP_NET_RAW 13
710 #ifndef VFS_CAP_FLAGS_EFFECTIVE
711 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
714 #ifndef VFS_CAP_U32_3
715 #define VFS_CAP_U32_3 2
719 #define VFS_CAP_U32 VFS_CAP_U32_3
722 #ifndef VFS_CAP_REVISION_1
723 #define VFS_CAP_REVISION_1 0x01000000
726 #ifndef VFS_CAP_REVISION_2
727 #define VFS_CAP_REVISION_2 0x02000000
730 #ifndef VFS_CAP_REVISION_3
731 #define VFS_CAP_REVISION_3 0x03000000
732 struct vfs_ns_cap_data {
742 #if __BYTE_ORDER == __BIG_ENDIAN
743 #define cpu_to_le16(w16) le16_to_cpu(w16)
744 #define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
745 #define cpu_to_le32(w32) le32_to_cpu(w32)
746 #define le32_to_cpu(w32) \
747 ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
748 (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
749 #elif __BYTE_ORDER == __LITTLE_ENDIAN
750 #define cpu_to_le16(w16) ((u_int16_t)(w16))
751 #define le16_to_cpu(w16) ((u_int16_t)(w16))
752 #define cpu_to_le32(w32) ((u_int32_t)(w32))
753 #define le32_to_cpu(w32) ((u_int32_t)(w32))
755 #error Expected endianess macro to be set
758 /* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */
759 static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid)
761 #define __cap_raised_permitted(x, ns_cap_data) \
762 ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31)))
763 struct vfs_ns_cap_data ns_xattr = {};
766 ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
767 if (ret < 0 || ret == 0)
770 if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
772 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
774 log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
777 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
778 (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
780 log_stderr("failure: fscaps version");
786 /* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */
787 static int set_dummy_vfs_caps(int fd, int flags, int rootuid)
789 #define __raise_cap_permitted(x, ns_cap_data) \
790 ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
792 struct vfs_ns_cap_data ns_xattr;
794 memset(&ns_xattr, 0, sizeof(ns_xattr));
795 __raise_cap_permitted(CAP_NET_RAW, ns_xattr);
796 ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
797 ns_xattr.rootid = cpu_to_le32(rootuid);
799 return fsetxattr(fd, "security.capability",
800 &ns_xattr, sizeof(ns_xattr), flags);
803 #define safe_close(fd) \
811 static void test_setup(void)
813 if (mkdirat(t_mnt_fd, T_DIR1, 0777))
814 die("failure: mkdirat");
816 t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
818 die("failure: openat");
820 if (fchmod(t_dir1_fd, 0777))
821 die("failure: fchmod");
824 static void test_cleanup(void)
826 safe_close(t_dir1_fd);
827 if (rm_r(t_mnt_fd, T_DIR1))
828 die("failure: rm_r");
831 /* Validate that basic file operations on idmapped mounts. */
832 static int fsids_unmapped(void)
835 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
836 struct mount_attr attr = {
837 .attr_set = MOUNT_ATTR_IDMAP,
840 /* create hardlink target */
841 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
842 if (hardlink_target_fd < 0) {
843 log_stderr("failure: openat");
847 /* create directory for rename test */
848 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
849 log_stderr("failure: mkdirat");
853 /* change ownership of all files to uid 0 */
854 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
855 log_stderr("failure: chown_r");
859 /* Changing mount properties on a detached mount. */
860 attr.userns_fd = get_userns_fd(0, 10000, 10000);
861 if (attr.userns_fd < 0) {
862 log_stderr("failure: get_userns_fd");
866 open_tree_fd = sys_open_tree(t_dir1_fd, "",
869 AT_SYMLINK_NOFOLLOW |
872 if (open_tree_fd < 0) {
873 log_stderr("failure: sys_open_tree");
877 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
878 log_stderr("failure: sys_mount_setattr");
882 if (!switch_fsids(0, 0)) {
883 log_stderr("failure: switch_fsids");
887 /* The caller's fsids don't have a mappings in the idmapped mount so any
888 * file creation must fail.
891 /* create hardlink */
892 if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
893 log_stderr("failure: linkat");
896 if (errno != EOVERFLOW) {
897 log_stderr("failure: errno");
901 /* try to rename a file */
902 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
903 log_stderr("failure: renameat");
906 if (errno != EOVERFLOW) {
907 log_stderr("failure: errno");
911 /* try to rename a directory */
912 if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
913 log_stderr("failure: renameat");
916 if (errno != EOVERFLOW) {
917 log_stderr("failure: errno");
921 /* The caller is privileged over the inode so file deletion must work. */
924 if (unlinkat(open_tree_fd, FILE1, 0)) {
925 log_stderr("failure: unlinkat");
929 /* remove directory */
930 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
931 log_stderr("failure: unlinkat");
935 /* The caller's fsids don't have a mappings in the idmapped mount so
936 * any file creation must fail.
939 /* create regular file via open() */
940 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
942 log_stderr("failure: create");
945 if (errno != EOVERFLOW) {
946 log_stderr("failure: errno");
950 /* create regular file via mknod */
951 if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
952 log_stderr("failure: mknodat");
955 if (errno != EOVERFLOW) {
956 log_stderr("failure: errno");
960 /* create character device */
961 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
962 log_stderr("failure: mknodat");
965 if (errno != EOVERFLOW) {
966 log_stderr("failure: errno");
971 if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
972 log_stderr("failure: symlinkat");
975 if (errno != EOVERFLOW) {
976 log_stderr("failure: errno");
980 /* create directory */
981 if (!mkdirat(open_tree_fd, DIR1, 0700)) {
982 log_stderr("failure: mkdirat");
985 if (errno != EOVERFLOW) {
986 log_stderr("failure: errno");
991 log_debug("Ran test");
993 safe_close(attr.userns_fd);
994 safe_close(hardlink_target_fd);
995 safe_close(file1_fd);
996 safe_close(open_tree_fd);
1001 static int fsids_mapped(void)
1004 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
1005 struct mount_attr attr = {
1006 .attr_set = MOUNT_ATTR_IDMAP,
1010 if (!caps_supported())
1013 /* create hardlink target */
1014 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1015 if (hardlink_target_fd < 0) {
1016 log_stderr("failure: openat");
1020 /* create directory for rename test */
1021 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
1022 log_stderr("failure: mkdirat");
1026 /* change ownership of all files to uid 0 */
1027 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1028 log_stderr("failure: chown_r");
1032 /* Changing mount properties on a detached mount. */
1033 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1034 if (attr.userns_fd < 0) {
1035 log_stderr("failure: get_userns_fd");
1039 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1042 AT_SYMLINK_NOFOLLOW |
1045 if (open_tree_fd < 0) {
1046 log_stderr("failure: sys_open_tree");
1050 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1051 log_stderr("failure: sys_mount_setattr");
1057 log_stderr("failure: fork");
1061 if (!switch_fsids(10000, 10000))
1062 die("failure: switch fsids");
1065 die("failure: raise caps");
1067 /* The caller's fsids now have mappings in the idmapped mount so
1068 * any file creation must fail.
1071 /* create hardlink */
1072 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1073 die("failure: create hardlink");
1075 /* try to rename a file */
1076 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1077 die("failure: rename");
1079 /* try to rename a directory */
1080 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1081 die("failure: rename");
1084 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1085 die("failure: delete");
1087 /* remove directory */
1088 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1089 die("failure: delete");
1091 /* The caller's fsids have mappings in the idmapped mount so any
1092 * file creation must fail.
1095 /* create regular file via open() */
1096 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1098 die("failure: create");
1100 /* create regular file via mknod */
1101 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1102 die("failure: create");
1104 /* create character device */
1105 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1106 die("failure: create");
1108 /* create symlink */
1109 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1110 die("failure: create");
1112 /* create directory */
1113 if (mkdirat(open_tree_fd, DIR1, 0700))
1114 die("failure: create");
1118 if (wait_for_pid(pid))
1122 log_debug("Ran test");
1124 safe_close(attr.userns_fd);
1125 safe_close(file1_fd);
1126 safe_close(hardlink_target_fd);
1127 safe_close(open_tree_fd);
1132 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1133 static int create_in_userns(void)
1136 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1137 struct mount_attr attr = {
1138 .attr_set = MOUNT_ATTR_IDMAP,
1142 /* change ownership of all files to uid 0 */
1143 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1144 log_stderr("failure: chown_r");
1148 /* Changing mount properties on a detached mount. */
1149 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1150 if (attr.userns_fd < 0) {
1151 log_stderr("failure: get_userns_fd");
1155 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1158 AT_SYMLINK_NOFOLLOW |
1161 if (open_tree_fd < 0) {
1162 log_stderr("failure: sys_open_tree");
1166 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1167 log_stderr("failure: sys_mount_setattr");
1173 log_stderr("failure: fork");
1177 if (!switch_userns(attr.userns_fd, 0, 0, false))
1178 die("failure: switch_userns");
1180 /* create regular file via open() */
1181 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1183 die("failure: open file");
1184 safe_close(file1_fd);
1186 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1187 die("failure: check ownership");
1189 /* create regular file via mknod */
1190 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1191 die("failure: create");
1193 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1194 die("failure: check ownership");
1196 /* create symlink */
1197 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1198 die("failure: create");
1200 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1201 die("failure: check ownership");
1203 /* create directory */
1204 if (mkdirat(open_tree_fd, DIR1, 0700))
1205 die("failure: create");
1207 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1208 die("failure: check ownership");
1210 /* try to rename a file */
1211 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1212 die("failure: create");
1214 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1215 die("failure: check ownership");
1217 /* try to rename a file */
1218 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1219 die("failure: create");
1221 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1222 die("failure: check ownership");
1225 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1226 die("failure: remove");
1228 /* remove directory */
1229 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1230 die("failure: remove");
1235 if (wait_for_pid(pid))
1239 log_debug("Ran test");
1241 safe_close(attr.userns_fd);
1242 safe_close(file1_fd);
1243 safe_close(open_tree_fd);
1248 static int hardlink_crossing_mounts(void)
1251 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1253 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1254 log_stderr("failure: chown_r");
1258 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1261 AT_SYMLINK_NOFOLLOW |
1264 if (open_tree_fd < 0) {
1265 log_stderr("failure: sys_open_tree");
1269 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1271 log_stderr("failure: openat");
1275 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1276 log_stderr("failure: mkdirat");
1280 /* We're crossing a mountpoint so this must fail.
1282 * Note that this must also fail for non-idmapped mounts but here we're
1283 * interested in making sure we're not introducing an accidental way to
1284 * violate that restriction or that suddenly this becomes possible.
1286 if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1287 log_stderr("failure: linkat");
1290 if (errno != EXDEV) {
1291 log_stderr("failure: errno");
1296 log_debug("Ran test");
1298 safe_close(file1_fd);
1299 safe_close(open_tree_fd);
1304 static int hardlink_crossing_idmapped_mounts(void)
1307 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1308 struct mount_attr attr = {
1309 .attr_set = MOUNT_ATTR_IDMAP,
1312 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1313 log_stderr("failure: chown_r");
1317 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1318 if (attr.userns_fd < 0) {
1319 log_stderr("failure: get_userns_fd");
1323 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1326 AT_SYMLINK_NOFOLLOW |
1329 if (open_tree_fd1 < 0) {
1330 log_stderr("failure: sys_open_tree");
1334 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1335 log_stderr("failure: sys_mount_setattr");
1339 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1341 log_stderr("failure: openat");
1345 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1346 log_stderr("failure: expected_uid_gid");
1350 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1351 log_stderr("failure: expected_uid_gid");
1355 safe_close(file1_fd);
1357 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1358 log_stderr("failure: mkdirat");
1362 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1364 AT_SYMLINK_NOFOLLOW |
1368 if (open_tree_fd2 < 0) {
1369 log_stderr("failure: sys_open_tree");
1373 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1374 log_stderr("failure: sys_mount_setattr");
1378 /* We're crossing a mountpoint so this must fail.
1380 * Note that this must also fail for non-idmapped mounts but here we're
1381 * interested in making sure we're not introducing an accidental way to
1382 * violate that restriction or that suddenly this becomes possible.
1384 if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1385 log_stderr("failure: linkat");
1388 if (errno != EXDEV) {
1389 log_stderr("failure: errno");
1394 log_debug("Ran test");
1396 safe_close(attr.userns_fd);
1397 safe_close(file1_fd);
1398 safe_close(open_tree_fd1);
1399 safe_close(open_tree_fd2);
1404 static int hardlink_from_idmapped_mount(void)
1407 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1408 struct mount_attr attr = {
1409 .attr_set = MOUNT_ATTR_IDMAP,
1412 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1413 log_stderr("failure: chown_r");
1417 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1418 if (attr.userns_fd < 0) {
1419 log_stderr("failure: get_userns_fd");
1423 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1426 AT_SYMLINK_NOFOLLOW |
1429 if (open_tree_fd < 0) {
1430 log_stderr("failure: sys_open_tree");
1434 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1435 log_stderr("failure: sys_mount_setattr");
1439 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1441 log_stderr("failure: openat");
1444 safe_close(file1_fd);
1446 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1447 log_stderr("failure: expected_uid_gid");
1451 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1452 log_stderr("failure: expected_uid_gid");
1456 /* We're not crossing a mountpoint so this must succeed. */
1457 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
1458 log_stderr("failure: linkat");
1464 log_debug("Ran test");
1466 safe_close(attr.userns_fd);
1467 safe_close(file1_fd);
1468 safe_close(open_tree_fd);
1473 static int hardlink_from_idmapped_mount_in_userns(void)
1476 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1477 struct mount_attr attr = {
1478 .attr_set = MOUNT_ATTR_IDMAP,
1482 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1483 log_stderr("failure: chown_r");
1487 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1488 if (attr.userns_fd < 0) {
1489 log_stderr("failure: get_userns_fd");
1493 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1496 AT_SYMLINK_NOFOLLOW |
1499 if (open_tree_fd < 0) {
1500 log_stderr("failure: sys_open_tree");
1504 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1505 log_stderr("failure: sys_mount_setattr");
1511 log_stderr("failure: fork");
1515 if (!switch_userns(attr.userns_fd, 0, 0, false))
1516 die("failure: switch_userns");
1518 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1520 die("failure: create");
1522 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1523 die("failure: check ownership");
1525 /* We're not crossing a mountpoint so this must succeed. */
1526 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1527 die("failure: create");
1529 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1530 die("failure: check ownership");
1535 if (wait_for_pid(pid))
1539 log_debug("Ran test");
1541 safe_close(attr.userns_fd);
1542 safe_close(file1_fd);
1543 safe_close(open_tree_fd);
1548 static int rename_crossing_mounts(void)
1551 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1553 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1554 log_stderr("failure: chown_r");
1558 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1561 AT_SYMLINK_NOFOLLOW |
1564 if (open_tree_fd < 0) {
1565 log_stderr("failure: sys_open_tree");
1569 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1571 log_stderr("failure: openat");
1575 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1576 log_stderr("failure: mkdirat");
1580 /* We're crossing a mountpoint so this must fail.
1582 * Note that this must also fail for non-idmapped mounts but here we're
1583 * interested in making sure we're not introducing an accidental way to
1584 * violate that restriction or that suddenly this becomes possible.
1586 if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1587 log_stderr("failure: renameat");
1590 if (errno != EXDEV) {
1591 log_stderr("failure: errno");
1596 log_debug("Ran test");
1598 safe_close(file1_fd);
1599 safe_close(open_tree_fd);
1604 static int rename_crossing_idmapped_mounts(void)
1607 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1608 struct mount_attr attr = {
1609 .attr_set = MOUNT_ATTR_IDMAP,
1612 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1613 log_stderr("failure: chown_r");
1617 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1618 if (attr.userns_fd < 0) {
1619 log_stderr("failure: get_userns_fd");
1623 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1626 AT_SYMLINK_NOFOLLOW |
1629 if (open_tree_fd1 < 0) {
1630 log_stderr("failure: sys_open_tree");
1634 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1635 log_stderr("failure: sys_mount_setattr");
1639 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1641 log_stderr("failure: openat");
1645 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1646 log_stderr("failure: expected_uid_gid");
1650 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1651 log_stderr("failure: expected_uid_gid");
1655 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1656 log_stderr("failure: mkdirat");
1660 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1662 AT_SYMLINK_NOFOLLOW |
1666 if (open_tree_fd2 < 0) {
1667 log_stderr("failure: sys_open_tree");
1671 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1672 log_stderr("failure: sys_mount_setattr");
1676 /* We're crossing a mountpoint so this must fail.
1678 * Note that this must also fail for non-idmapped mounts but here we're
1679 * interested in making sure we're not introducing an accidental way to
1680 * violate that restriction or that suddenly this becomes possible.
1682 if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1683 log_stderr("failure: renameat");
1686 if (errno != EXDEV) {
1687 log_stderr("failure: errno");
1692 log_debug("Ran test");
1694 safe_close(attr.userns_fd);
1695 safe_close(file1_fd);
1696 safe_close(open_tree_fd1);
1697 safe_close(open_tree_fd2);
1702 static int rename_from_idmapped_mount(void)
1705 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1706 struct mount_attr attr = {
1707 .attr_set = MOUNT_ATTR_IDMAP,
1710 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1711 log_stderr("failure: chown_r");
1715 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1716 if (attr.userns_fd < 0) {
1717 log_stderr("failure: get_userns_fd");
1721 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1724 AT_SYMLINK_NOFOLLOW |
1727 if (open_tree_fd < 0) {
1728 log_stderr("failure: sys_open_tree");
1732 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1733 log_stderr("failure: sys_mount_setattr");
1737 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1739 log_stderr("failure: openat");
1743 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1744 log_stderr("failure: expected_uid_gid");
1748 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1749 log_stderr("failure: expected_uid_gid");
1753 /* We're not crossing a mountpoint so this must succeed. */
1754 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
1755 log_stderr("failure: renameat");
1760 log_debug("Ran test");
1762 safe_close(attr.userns_fd);
1763 safe_close(file1_fd);
1764 safe_close(open_tree_fd);
1769 static int rename_from_idmapped_mount_in_userns(void)
1772 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1774 struct mount_attr attr = {
1775 .attr_set = MOUNT_ATTR_IDMAP,
1778 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1779 log_stderr("failure: chown_r");
1783 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1784 if (attr.userns_fd < 0) {
1785 log_stderr("failure: get_userns_fd");
1789 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1792 AT_SYMLINK_NOFOLLOW |
1795 if (open_tree_fd < 0) {
1796 log_stderr("failure: sys_open_tree");
1800 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1801 log_stderr("failure: sys_mount_setattr");
1807 log_stderr("failure: fork");
1811 if (!switch_userns(attr.userns_fd, 0, 0, false))
1812 die("failure: switch_userns");
1814 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1816 die("failure: create");
1818 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1819 die("failure: check ownership");
1821 /* We're not crossing a mountpoint so this must succeed. */
1822 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1823 die("failure: create");
1825 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1826 die("failure: check ownership");
1831 if (wait_for_pid(pid))
1835 log_debug("Ran test");
1837 safe_close(attr.userns_fd);
1838 safe_close(file1_fd);
1839 safe_close(open_tree_fd);
1844 static int symlink_regular_mounts(void)
1847 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1850 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1852 log_stderr("failure: openat");
1856 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1857 log_stderr("failure: chown_r");
1861 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1864 AT_SYMLINK_NOFOLLOW |
1867 if (open_tree_fd < 0) {
1868 log_stderr("failure: sys_open_tree");
1872 if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1873 log_stderr("failure: symlinkat");
1877 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1878 log_stderr("failure: fchownat");
1882 if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1883 log_stderr("failure: fstatat");
1887 if (st.st_uid != 15000 || st.st_gid != 15000) {
1888 log_stderr("failure: compare ids");
1892 if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1893 log_stderr("failure: fstatat");
1897 if (st.st_uid != 10000 || st.st_gid != 10000) {
1898 log_stderr("failure: compare ids");
1903 log_debug("Ran test");
1905 safe_close(file1_fd);
1906 safe_close(open_tree_fd);
1911 static int symlink_idmapped_mounts(void)
1914 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1915 struct mount_attr attr = {
1916 .attr_set = MOUNT_ATTR_IDMAP,
1920 if (!caps_supported())
1923 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1925 log_stderr("failure: openat");
1929 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1930 log_stderr("failure: chown_r");
1934 /* Changing mount properties on a detached mount. */
1935 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1936 if (attr.userns_fd < 0) {
1937 log_stderr("failure: get_userns_fd");
1941 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1944 AT_SYMLINK_NOFOLLOW |
1947 if (open_tree_fd < 0) {
1948 log_stderr("failure: sys_open_tree");
1952 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1953 log_stderr("failure: sys_mount_setattr");
1959 log_stderr("failure: fork");
1963 if (!switch_fsids(10000, 10000))
1964 die("failure: switch fsids");
1967 die("failure: raise caps");
1969 if (symlinkat(FILE1, open_tree_fd, FILE2))
1970 die("failure: create");
1972 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1973 die("failure: change ownership");
1975 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1976 die("failure: check ownership");
1978 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1979 die("failure: check ownership");
1983 if (wait_for_pid(pid))
1987 log_debug("Ran test");
1989 safe_close(attr.userns_fd);
1990 safe_close(file1_fd);
1991 safe_close(open_tree_fd);
1996 static int symlink_idmapped_mounts_in_userns(void)
1999 int file1_fd = -EBADF, open_tree_fd = -EBADF;
2000 struct mount_attr attr = {
2001 .attr_set = MOUNT_ATTR_IDMAP,
2005 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
2006 log_stderr("failure: chown_r");
2010 /* Changing mount properties on a detached mount. */
2011 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2012 if (attr.userns_fd < 0) {
2013 log_stderr("failure: get_userns_fd");
2017 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2020 AT_SYMLINK_NOFOLLOW |
2023 if (open_tree_fd < 0) {
2024 log_stderr("failure: sys_open_tree");
2028 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2029 log_stderr("failure: sys_mount_setattr");
2035 log_stderr("failure: fork");
2039 if (!switch_userns(attr.userns_fd, 0, 0, false))
2040 die("failure: switch_userns");
2042 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2044 die("failure: create");
2045 safe_close(file1_fd);
2047 if (symlinkat(FILE1, open_tree_fd, FILE2))
2048 die("failure: create");
2050 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2051 die("failure: change ownership");
2053 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2054 die("failure: check ownership");
2056 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2057 die("failure: check ownership");
2062 if (wait_for_pid(pid))
2065 if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2066 log_stderr("failure: expected_uid_gid");
2070 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2071 log_stderr("failure: expected_uid_gid");
2076 log_debug("Ran test");
2078 safe_close(attr.userns_fd);
2079 safe_close(file1_fd);
2080 safe_close(open_tree_fd);
2085 /* Validate that a caller whose fsids map into the idmapped mount within it's
2086 * user namespace cannot create any device nodes.
2088 static int device_node_in_userns(void)
2091 int open_tree_fd = -EBADF;
2092 struct mount_attr attr = {
2093 .attr_set = MOUNT_ATTR_IDMAP,
2097 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2098 if (attr.userns_fd < 0) {
2099 log_stderr("failure: get_userns_fd");
2103 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2106 AT_SYMLINK_NOFOLLOW |
2109 if (open_tree_fd < 0) {
2110 log_stderr("failure: sys_open_tree");
2114 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2115 log_stderr("failure: sys_mount_setattr");
2121 log_stderr("failure: fork");
2125 if (!switch_userns(attr.userns_fd, 0, 0, false))
2126 die("failure: switch_userns");
2128 /* create character device */
2129 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2130 die("failure: create");
2135 if (wait_for_pid(pid))
2139 log_debug("Ran test");
2141 safe_close(attr.userns_fd);
2142 safe_close(open_tree_fd);
2148 /* Validate that changing file ownership works correctly on idmapped mounts. */
2149 static int expected_uid_gid_idmapped_mounts(void)
2152 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2153 struct mount_attr attr1 = {
2154 .attr_set = MOUNT_ATTR_IDMAP,
2156 struct mount_attr attr2 = {
2157 .attr_set = MOUNT_ATTR_IDMAP,
2161 if (!switch_fsids(0, 0)) {
2162 log_stderr("failure: switch_fsids");
2166 /* create regular file via open() */
2167 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2169 log_stderr("failure: openat");
2173 /* create regular file via mknod */
2174 if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2175 log_stderr("failure: mknodat");
2179 /* create character device */
2180 if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2181 log_stderr("failure: mknodat");
2185 /* create hardlink */
2186 if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2187 log_stderr("failure: linkat");
2191 /* create symlink */
2192 if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2193 log_stderr("failure: symlinkat");
2197 /* create directory */
2198 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2199 log_stderr("failure: mkdirat");
2203 /* Changing mount properties on a detached mount. */
2204 attr1.userns_fd = get_userns_fd(0, 10000, 10000);
2205 if (attr1.userns_fd < 0) {
2206 log_stderr("failure: get_userns_fd");
2210 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2213 AT_SYMLINK_NOFOLLOW |
2216 if (open_tree_fd1 < 0) {
2217 log_stderr("failure: sys_open_tree");
2221 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2222 log_stderr("failure: sys_mount_setattr");
2226 /* Validate that all files created through the image mountpoint are
2227 * owned by the callers fsuid and fsgid.
2229 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2230 log_stderr("failure: expected_uid_gid");
2233 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2234 log_stderr("failure: expected_uid_gid");
2237 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2238 log_stderr("failure: expected_uid_gid");
2241 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2242 log_stderr("failure: expected_uid_gid");
2245 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2246 log_stderr("failure: expected_uid_gid");
2249 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2250 log_stderr("failure: expected_uid_gid");
2253 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2254 log_stderr("failure: expected_uid_gid");
2258 /* Validate that all files are owned by the uid and gid specified in
2259 * the idmapping of the mount they are accessed from.
2261 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2262 log_stderr("failure: expected_uid_gid");
2265 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2266 log_stderr("failure: expected_uid_gid");
2269 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2270 log_stderr("failure: expected_uid_gid");
2273 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2274 log_stderr("failure: expected_uid_gid");
2277 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2278 log_stderr("failure: expected_uid_gid");
2281 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2282 log_stderr("failure: expected_uid_gid");
2285 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2286 log_stderr("failure: expected_uid_gid");
2290 /* Changing mount properties on a detached mount. */
2291 attr2.userns_fd = get_userns_fd(0, 30000, 2001);
2292 if (attr2.userns_fd < 0) {
2293 log_stderr("failure: get_userns_fd");
2297 open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2300 AT_SYMLINK_NOFOLLOW |
2303 if (open_tree_fd2 < 0) {
2304 log_stderr("failure: sys_open_tree");
2308 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2309 log_stderr("failure: sys_mount_setattr");
2313 /* Validate that all files are owned by the uid and gid specified in
2314 * the idmapping of the mount they are accessed from.
2316 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2317 log_stderr("failure: expected_uid_gid");
2320 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2321 log_stderr("failure: expected_uid_gid");
2324 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2325 log_stderr("failure: expected_uid_gid");
2328 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2329 log_stderr("failure: expected_uid_gid");
2332 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2333 log_stderr("failure: expected_uid_gid");
2336 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2337 log_stderr("failure: expected_uid_gid");
2340 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2341 log_stderr("failure: expected_uid_gid");
2345 /* Change ownership throught original image mountpoint. */
2346 if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2347 log_stderr("failure: fchownat");
2350 if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2351 log_stderr("failure: fchownat");
2354 if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2355 log_stderr("failure: fchownat");
2358 if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2359 log_stderr("failure: fchownat");
2362 if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2363 log_stderr("failure: fchownat");
2366 if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2367 log_stderr("failure: fchownat");
2370 if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2371 log_stderr("failure: fchownat");
2375 /* Check ownership through original mount. */
2376 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 2000, 2000)) {
2377 log_stderr("failure: expected_uid_gid");
2380 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2381 log_stderr("failure: expected_uid_gid");
2384 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2385 log_stderr("failure: expected_uid_gid");
2388 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2389 log_stderr("failure: expected_uid_gid");
2392 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2393 log_stderr("failure: expected_uid_gid");
2396 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2397 log_stderr("failure: expected_uid_gid");
2400 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2401 log_stderr("failure: expected_uid_gid");
2405 /* Check ownership through first idmapped mount. */
2406 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 12000, 12000)) {
2407 log_stderr("failure:expected_uid_gid ");
2410 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2411 log_stderr("failure: expected_uid_gid");
2414 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2415 log_stderr("failure: expected_uid_gid");
2418 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2419 log_stderr("failure: expected_uid_gid");
2422 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2423 log_stderr("failure: expected_uid_gid");
2426 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2427 log_stderr("failure:expected_uid_gid ");
2430 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2431 log_stderr("failure: expected_uid_gid");
2435 /* Check ownership through second idmapped mount. */
2436 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 32000, 32000)) {
2437 log_stderr("failure: expected_uid_gid");
2440 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2441 log_stderr("failure: expected_uid_gid");
2444 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2445 log_stderr("failure: expected_uid_gid");
2448 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2449 log_stderr("failure: expected_uid_gid");
2452 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2453 log_stderr("failure: expected_uid_gid");
2456 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2457 log_stderr("failure: expected_uid_gid");
2460 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2461 log_stderr("failure: expected_uid_gid");
2467 log_stderr("failure: fork");
2471 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2472 die("failure: switch_userns");
2474 if (!fchownat(t_dir1_fd, FILE1, 1000, 1000, 0))
2475 die("failure: fchownat");
2476 if (!fchownat(t_dir1_fd, FILE2, 1000, 1000, 0))
2477 die("failure: fchownat");
2478 if (!fchownat(t_dir1_fd, HARDLINK1, 1000, 1000, 0))
2479 die("failure: fchownat");
2480 if (!fchownat(t_dir1_fd, CHRDEV1, 1000, 1000, 0))
2481 die("failure: fchownat");
2482 if (!fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2483 die("failure: fchownat");
2484 if (!fchownat(t_dir1_fd, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2485 die("failure: fchownat");
2486 if (!fchownat(t_dir1_fd, DIR1, 1000, 1000, AT_EMPTY_PATH))
2487 die("failure: fchownat");
2489 if (!fchownat(open_tree_fd2, FILE1, 1000, 1000, 0))
2490 die("failure: fchownat");
2491 if (!fchownat(open_tree_fd2, FILE2, 1000, 1000, 0))
2492 die("failure: fchownat");
2493 if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
2494 die("failure: fchownat");
2495 if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
2496 die("failure: fchownat");
2497 if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2498 die("failure: fchownat");
2499 if (!fchownat(open_tree_fd2, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2500 die("failure: fchownat");
2501 if (!fchownat(open_tree_fd2, DIR1, 1000, 1000, AT_EMPTY_PATH))
2502 die("failure: fchownat");
2504 if (fchownat(open_tree_fd1, FILE1, 1000, 1000, 0))
2505 die("failure: fchownat");
2506 if (fchownat(open_tree_fd1, FILE2, 1000, 1000, 0))
2507 die("failure: fchownat");
2508 if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
2509 die("failure: fchownat");
2510 if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
2511 die("failure: fchownat");
2512 if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2513 die("failure: fchownat");
2514 if (fchownat(open_tree_fd1, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2515 die("failure: fchownat");
2516 if (fchownat(open_tree_fd1, DIR1, 1000, 1000, AT_EMPTY_PATH))
2517 die("failure: fchownat");
2519 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2520 die("failure: expected_uid_gid");
2521 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2522 die("failure: expected_uid_gid");
2523 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2524 die("failure: expected_uid_gid");
2525 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2526 die("failure: expected_uid_gid");
2527 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2528 die("failure: expected_uid_gid");
2529 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2530 die("failure: expected_uid_gid");
2531 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2532 die("failure: expected_uid_gid");
2534 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, t_overflowuid, t_overflowgid))
2535 die("failure: expected_uid_gid");
2536 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, t_overflowuid, t_overflowgid))
2537 die("failure: expected_uid_gid");
2538 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2539 die("failure: expected_uid_gid");
2540 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2541 die("failure: expected_uid_gid");
2542 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2543 die("failure: expected_uid_gid");
2544 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2545 die("failure: expected_uid_gid");
2546 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, t_overflowuid, t_overflowgid))
2547 die("failure: expected_uid_gid");
2549 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 1000, 1000))
2550 die("failure: expected_uid_gid");
2551 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 1000, 1000))
2552 die("failure: expected_uid_gid");
2553 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
2554 die("failure: expected_uid_gid");
2555 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
2556 die("failure: expected_uid_gid");
2557 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2558 die("failure: expected_uid_gid");
2559 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 1000, 1000))
2560 die("failure: expected_uid_gid");
2561 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 1000, 1000))
2562 die("failure: expected_uid_gid");
2567 if (wait_for_pid(pid))
2570 /* Check ownership through original mount. */
2571 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 1000, 1000)) {
2572 log_stderr("failure: expected_uid_gid");
2575 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2576 log_stderr("failure: expected_uid_gid");
2579 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2580 log_stderr("failure: expected_uid_gid");
2583 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2584 log_stderr("failure: expected_uid_gid");
2587 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2588 log_stderr("failure: expected_uid_gid");
2591 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2592 log_stderr("failure: expected_uid_gid");
2595 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2596 log_stderr("failure: expected_uid_gid");
2600 /* Check ownership through first idmapped mount. */
2601 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 11000, 11000)) {
2602 log_stderr("failure: expected_uid_gid");
2605 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2606 log_stderr("failure: expected_uid_gid");
2609 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2610 log_stderr("failure: expected_uid_gid");
2613 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2614 log_stderr("failure: expected_uid_gid");
2617 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2618 log_stderr("failure: expected_uid_gid");
2621 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2622 log_stderr("failure: expected_uid_gid");
2625 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2626 log_stderr("failure: expected_uid_gid");
2630 /* Check ownership through second idmapped mount. */
2631 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 31000, 31000)) {
2632 log_stderr("failure: expected_uid_gid");
2635 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2636 log_stderr("failure: expected_uid_gid");
2639 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2640 log_stderr("failure: expected_uid_gid");
2643 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2644 log_stderr("failure: expected_uid_gid");
2647 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2648 log_stderr("failure: expected_uid_gid");
2651 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2652 log_stderr("failure: expected_uid_gid");
2655 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2656 log_stderr("failure: expected_uid_gid");
2662 log_stderr("failure: fork");
2666 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2667 die("failure: switch_userns");
2669 if (!fchownat(t_dir1_fd, FILE1, 0, 0, 0))
2670 die("failure: fchownat");
2671 if (!fchownat(t_dir1_fd, FILE2, 0, 0, 0))
2672 die("failure: fchownat");
2673 if (!fchownat(t_dir1_fd, HARDLINK1, 0, 0, 0))
2674 die("failure: fchownat");
2675 if (!fchownat(t_dir1_fd, CHRDEV1, 0, 0, 0))
2676 die("failure: fchownat");
2677 if (!fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2678 die("failure: fchownat");
2679 if (!fchownat(t_dir1_fd, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2680 die("failure: fchownat");
2681 if (!fchownat(t_dir1_fd, DIR1, 0, 0, AT_EMPTY_PATH))
2682 die("failure: fchownat");
2684 if (!fchownat(open_tree_fd1, FILE1, 0, 0, 0))
2685 die("failure: fchownat");
2686 if (!fchownat(open_tree_fd1, FILE2, 0, 0, 0))
2687 die("failure: fchownat");
2688 if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
2689 die("failure: fchownat");
2690 if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
2691 die("failure: fchownat");
2692 if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2693 die("failure: fchownat");
2694 if (!fchownat(open_tree_fd1, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2695 die("failure: fchownat");
2696 if (!fchownat(open_tree_fd1, DIR1, 0, 0, AT_EMPTY_PATH))
2697 die("failure: fchownat");
2699 if (fchownat(open_tree_fd2, FILE1, 0, 0, 0))
2700 die("failure: fchownat");
2701 if (fchownat(open_tree_fd2, FILE2, 0, 0, 0))
2702 die("failure: fchownat");
2703 if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
2704 die("failure: fchownat");
2705 if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
2706 die("failure: fchownat");
2707 if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2708 die("failure: fchownat");
2709 if (fchownat(open_tree_fd2, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2710 die("failure: fchownat");
2711 if (fchownat(open_tree_fd2, DIR1, 0, 0, AT_EMPTY_PATH))
2712 die("failure: fchownat");
2714 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2715 die("failure: expected_uid_gid");
2716 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2717 die("failure: expected_uid_gid");
2718 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2719 die("failure: expected_uid_gid");
2720 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2721 die("failure: expected_uid_gid");
2722 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2723 die("failure: expected_uid_gid");
2724 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2725 die("failure: expected_uid_gid");
2726 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2727 die("failure: expected_uid_gid");
2729 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, t_overflowuid, t_overflowgid))
2730 die("failure: expected_uid_gid");
2731 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, t_overflowuid, t_overflowgid))
2732 die("failure: expected_uid_gid");
2733 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2734 die("failure: expected_uid_gid");
2735 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2736 die("failure: expected_uid_gid");
2737 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2738 die("failure: expected_uid_gid");
2739 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2740 die("failure: expected_uid_gid");
2741 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, t_overflowuid, t_overflowgid))
2742 die("failure: expected_uid_gid");
2744 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 0, 0))
2745 die("failure: expected_uid_gid");
2746 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 0, 0))
2747 die("failure: expected_uid_gid");
2748 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
2749 die("failure: expected_uid_gid");
2750 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
2751 die("failure: expected_uid_gid");
2752 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2753 die("failure: expected_uid_gid");
2754 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 0, 0))
2755 die("failure: expected_uid_gid");
2756 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 0, 0))
2757 die("failure: expected_uid_gid");
2762 if (wait_for_pid(pid))
2765 /* Check ownership through original mount. */
2766 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2767 log_stderr("failure: expected_uid_gid");
2770 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2771 log_stderr("failure: expected_uid_gid");
2774 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2775 log_stderr("failure: expected_uid_gid");
2778 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2779 log_stderr("failure: expected_uid_gid");
2782 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2783 log_stderr("failure: expected_uid_gid");
2786 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2787 log_stderr("failure: expected_uid_gid");
2790 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2791 log_stderr("failure: expected_uid_gid");
2795 /* Check ownership through first idmapped mount. */
2796 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2797 log_stderr("failure: expected_uid_gid");
2800 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2801 log_stderr("failure: expected_uid_gid");
2804 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2805 log_stderr("failure: expected_uid_gid");
2808 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2809 log_stderr("failure: expected_uid_gid");
2812 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2813 log_stderr("failure: expected_uid_gid");
2816 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2817 log_stderr("failure: expected_uid_gid");
2820 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2821 log_stderr("failure: expected_uid_gid");
2825 /* Check ownership through second idmapped mount. */
2826 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2827 log_stderr("failure: expected_uid_gid");
2830 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2831 log_stderr("failure: expected_uid_gid");
2834 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2835 log_stderr("failure: expected_uid_gid");
2838 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2839 log_stderr("failure: expected_uid_gid");
2842 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2843 log_stderr("failure: expected_uid_gid");
2846 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2847 log_stderr("failure: expected_uid_gid");
2850 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2851 log_stderr("failure: expected_uid_gid");
2856 log_debug("Ran test");
2858 safe_close(attr1.userns_fd);
2859 safe_close(attr2.userns_fd);
2860 safe_close(file1_fd);
2861 safe_close(open_tree_fd1);
2862 safe_close(open_tree_fd2);
2867 static int fscaps(void)
2870 int file1_fd = -EBADF;
2871 struct mount_attr attr = {
2872 .attr_set = MOUNT_ATTR_IDMAP,
2876 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2878 log_stderr("failure: openat");
2882 /* Skip if vfs caps are unsupported. */
2883 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2886 /* Changing mount properties on a detached mount. */
2887 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2888 if (attr.userns_fd < 0) {
2889 log_stderr("failure: get_userns_fd");
2893 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
2894 log_stderr("failure: expected_dummy_vfs_caps_uid");
2900 log_stderr("failure: fork");
2904 if (!switch_userns(attr.userns_fd, 0, 0, false))
2905 die("failure: switch_userns");
2908 * On kernels before 5.12 this would succeed and return the
2909 * unconverted caps. Then - for whatever reason - this behavior
2910 * got changed and since 5.12 EOVERFLOW is returned when the
2911 * rootid stored alongside the vfs caps does not map to uid 0 in
2912 * the caller's user namespace.
2914 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
2915 die("failure: expected_dummy_vfs_caps_uid");
2920 if (wait_for_pid(pid))
2923 if (fremovexattr(file1_fd, "security.capability")) {
2924 log_stderr("failure: fremovexattr");
2927 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2928 log_stderr("failure: expected_dummy_vfs_caps_uid");
2931 if (errno != ENODATA) {
2932 log_stderr("failure: errno");
2936 if (set_dummy_vfs_caps(file1_fd, 0, 10000)) {
2937 log_stderr("failure: set_dummy_vfs_caps");
2941 if (!expected_dummy_vfs_caps_uid(file1_fd, 10000)) {
2942 log_stderr("failure: expected_dummy_vfs_caps_uid");
2948 log_stderr("failure: fork");
2952 if (!switch_userns(attr.userns_fd, 0, 0, false))
2953 die("failure: switch_userns");
2955 if (!expected_dummy_vfs_caps_uid(file1_fd, 0))
2956 die("failure: expected_dummy_vfs_caps_uid");
2961 if (wait_for_pid(pid))
2964 if (fremovexattr(file1_fd, "security.capability")) {
2965 log_stderr("failure: fremovexattr");
2968 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2969 log_stderr("failure: expected_dummy_vfs_caps_uid");
2972 if (errno != ENODATA) {
2973 log_stderr("failure: errno");
2978 log_debug("Ran test");
2980 safe_close(attr.userns_fd);
2981 safe_close(file1_fd);
2986 static int fscaps_idmapped_mounts(void)
2989 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
2990 struct mount_attr attr = {
2991 .attr_set = MOUNT_ATTR_IDMAP,
2995 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2997 log_stderr("failure: openat");
3001 /* Skip if vfs caps are unsupported. */
3002 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3005 if (fremovexattr(file1_fd, "security.capability")) {
3006 log_stderr("failure: fremovexattr");
3010 /* Changing mount properties on a detached mount. */
3011 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3012 if (attr.userns_fd < 0) {
3013 log_stderr("failure: get_userns_fd");
3017 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3020 AT_SYMLINK_NOFOLLOW |
3023 if (open_tree_fd < 0) {
3024 log_stderr("failure: sys_open_tree");
3028 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3029 log_stderr("failure: sys_mount_setattr");
3033 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3034 if (file1_fd2 < 0) {
3035 log_stderr("failure: openat");
3039 if (!set_dummy_vfs_caps(file1_fd2, 0, 1000)) {
3040 log_stderr("failure: set_dummy_vfs_caps");
3044 if (set_dummy_vfs_caps(file1_fd2, 0, 10000)) {
3045 log_stderr("failure: set_dummy_vfs_caps");
3049 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3050 log_stderr("failure: expected_dummy_vfs_caps_uid");
3054 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3055 log_stderr("failure: expected_dummy_vfs_caps_uid");
3061 log_stderr("failure: fork");
3065 if (!switch_userns(attr.userns_fd, 0, 0, false))
3066 die("failure: switch_userns");
3068 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3069 die("failure: expected_dummy_vfs_caps_uid");
3074 if (wait_for_pid(pid))
3077 if (fremovexattr(file1_fd2, "security.capability")) {
3078 log_stderr("failure: fremovexattr");
3081 if (expected_dummy_vfs_caps_uid(file1_fd2, -1)) {
3082 log_stderr("failure: expected_dummy_vfs_caps_uid");
3085 if (errno != ENODATA) {
3086 log_stderr("failure: errno");
3090 if (set_dummy_vfs_caps(file1_fd2, 0, 12000)) {
3091 log_stderr("failure: set_dummy_vfs_caps");
3095 if (!expected_dummy_vfs_caps_uid(file1_fd2, 12000)) {
3096 log_stderr("failure: expected_dummy_vfs_caps_uid");
3100 if (!expected_dummy_vfs_caps_uid(file1_fd, 2000)) {
3101 log_stderr("failure: expected_dummy_vfs_caps_uid");
3107 log_stderr("failure: fork");
3111 if (!switch_userns(attr.userns_fd, 0, 0, false))
3112 die("failure: switch_userns");
3114 if (!expected_dummy_vfs_caps_uid(file1_fd2, 2000))
3115 die("failure: expected_dummy_vfs_caps_uid");
3120 if (wait_for_pid(pid))
3124 log_debug("Ran test");
3126 safe_close(attr.userns_fd);
3127 safe_close(file1_fd);
3128 safe_close(file1_fd2);
3129 safe_close(open_tree_fd);
3134 static int fscaps_idmapped_mounts_in_userns(void)
3137 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3138 struct mount_attr attr = {
3139 .attr_set = MOUNT_ATTR_IDMAP,
3143 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3145 log_stderr("failure: openat");
3149 /* Skip if vfs caps are unsupported. */
3150 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3153 if (fremovexattr(file1_fd, "security.capability")) {
3154 log_stderr("failure: fremovexattr");
3158 /* Changing mount properties on a detached mount. */
3159 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3160 if (attr.userns_fd < 0) {
3161 log_stderr("failure: get_userns_fd");
3165 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3168 AT_SYMLINK_NOFOLLOW |
3171 if (open_tree_fd < 0) {
3172 log_stderr("failure: sys_open_tree");
3176 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3177 log_stderr("failure: sys_mount_setattr");
3181 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3182 if (file1_fd2 < 0) {
3183 log_stderr("failure: openat");
3189 log_stderr("failure: fork");
3193 if (!switch_userns(attr.userns_fd, 0, 0, false))
3194 die("failure: switch_userns");
3196 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3197 die("failure: expected_dummy_vfs_caps_uid");
3198 if (errno != ENODATA)
3199 die("failure: errno");
3201 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3202 die("failure: set_dummy_vfs_caps");
3204 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3205 die("failure: expected_dummy_vfs_caps_uid");
3207 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
3208 die("failure: expected_dummy_vfs_caps_uid");
3213 if (wait_for_pid(pid))
3216 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
3217 log_stderr("failure: expected_dummy_vfs_caps_uid");
3222 log_debug("Ran test");
3224 safe_close(attr.userns_fd);
3225 safe_close(file1_fd);
3226 safe_close(file1_fd2);
3227 safe_close(open_tree_fd);
3232 static int fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns(void)
3235 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3236 struct mount_attr attr = {
3237 .attr_set = MOUNT_ATTR_IDMAP,
3241 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3243 log_stderr("failure: openat");
3247 /* Skip if vfs caps are unsupported. */
3248 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3251 if (fremovexattr(file1_fd, "security.capability")) {
3252 log_stderr("failure: fremovexattr");
3255 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
3256 log_stderr("failure: expected_dummy_vfs_caps_uid");
3259 if (errno != ENODATA) {
3260 log_stderr("failure: errno");
3264 /* Changing mount properties on a detached mount. */
3265 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3266 if (attr.userns_fd < 0) {
3267 log_stderr("failure: get_userns_fd");
3271 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3274 AT_SYMLINK_NOFOLLOW |
3277 if (open_tree_fd < 0) {
3278 log_stderr("failure: sys_open_tree");
3282 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3283 log_stderr("failure: sys_mount_setattr");
3287 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3288 if (file1_fd2 < 0) {
3289 log_stderr("failure: openat");
3294 * Verify we can set an v3 fscap for real root this was regressed at
3295 * some point. Make sure this doesn't happen again!
3299 log_stderr("failure: fork");
3303 if (!switch_userns(attr.userns_fd, 0, 0, false))
3304 die("failure: switch_userns");
3306 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3307 die("failure: expected_dummy_vfs_caps_uid");
3308 if (errno != ENODATA)
3309 die("failure: errno");
3311 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3312 die("failure: set_dummy_vfs_caps");
3314 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3315 die("failure: expected_dummy_vfs_caps_uid");
3317 if (!expected_dummy_vfs_caps_uid(file1_fd, 0) && errno != EOVERFLOW)
3318 die("failure: expected_dummy_vfs_caps_uid");
3323 if (wait_for_pid(pid))
3326 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3327 log_stderr("failure: expected_dummy_vfs_caps_uid");
3331 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3332 log_stderr("failure: expected_dummy_vfs_caps_uid");
3337 log_debug("Ran test");
3339 safe_close(attr.userns_fd);
3340 safe_close(file1_fd);
3341 safe_close(file1_fd2);
3342 safe_close(open_tree_fd);
3347 static int fscaps_idmapped_mounts_in_userns_separate_userns(void)
3350 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3351 struct mount_attr attr = {
3352 .attr_set = MOUNT_ATTR_IDMAP,
3356 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3358 log_stderr("failure: openat");
3362 /* Skip if vfs caps are unsupported. */
3363 if (set_dummy_vfs_caps(file1_fd, 0, 1000)) {
3364 log_stderr("failure: set_dummy_vfs_caps");
3368 if (fremovexattr(file1_fd, "security.capability")) {
3369 log_stderr("failure: fremovexattr");
3373 /* change ownership of all files to uid 0 */
3374 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3375 log_stderr("failure: chown_r");
3379 /* Changing mount properties on a detached mount. */
3380 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
3381 if (attr.userns_fd < 0) {
3382 log_stderr("failure: get_userns_fd");
3386 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3389 AT_SYMLINK_NOFOLLOW |
3392 if (open_tree_fd < 0) {
3393 log_stderr("failure: sys_open_tree");
3397 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3398 log_stderr("failure: sys_mount_setattr");
3402 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3403 if (file1_fd2 < 0) {
3404 log_stderr("failure: openat");
3410 log_stderr("failure: fork");
3416 userns_fd = get_userns_fd(0, 10000, 10000);
3418 die("failure: get_userns_fd");
3420 if (!switch_userns(userns_fd, 0, 0, false))
3421 die("failure: switch_userns");
3423 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3424 die("failure: set fscaps");
3426 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3427 die("failure: expected_dummy_vfs_caps_uid");
3429 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000) && errno != EOVERFLOW)
3430 die("failure: expected_dummy_vfs_caps_uid");
3435 if (wait_for_pid(pid))
3438 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000)) {
3439 log_stderr("failure: expected_dummy_vfs_caps_uid");
3445 log_stderr("failure: fork");
3451 userns_fd = get_userns_fd(0, 10000, 10000);
3453 die("failure: get_userns_fd");
3455 if (!switch_userns(userns_fd, 0, 0, false))
3456 die("failure: switch_userns");
3458 if (fremovexattr(file1_fd2, "security.capability"))
3459 die("failure: fremovexattr");
3460 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3461 die("failure: expected_dummy_vfs_caps_uid");
3462 if (errno != ENODATA)
3463 die("failure: errno");
3465 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3466 die("failure: set_dummy_vfs_caps");
3468 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3469 die("failure: expected_dummy_vfs_caps_uid");
3471 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000) && errno != EOVERFLOW)
3472 die("failure: expected_dummy_vfs_caps_uid");
3477 if (wait_for_pid(pid))
3480 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000)) {
3481 log_stderr("failure: expected_dummy_vfs_caps_uid");
3486 log_debug("Ran test");
3488 safe_close(attr.userns_fd);
3489 safe_close(file1_fd);
3490 safe_close(file1_fd2);
3491 safe_close(open_tree_fd);
3496 /* Validate that when the IDMAP_MOUNT_TEST_RUN_SETID environment variable is set
3497 * to 1 that we are executed with setid privileges and if set to 0 we are not.
3498 * If the env variable isn't set the tests are not run.
3500 static void __attribute__((constructor)) setuid_rexec(void)
3502 const char *expected_euid_str, *expected_egid_str, *rexec;
3504 rexec = getenv("IDMAP_MOUNT_TEST_RUN_SETID");
3505 /* This is a regular test-suite run. */
3509 expected_euid_str = getenv("EXPECTED_EUID");
3510 expected_egid_str = getenv("EXPECTED_EGID");
3512 if (expected_euid_str && expected_egid_str) {
3513 uid_t expected_euid;
3514 gid_t expected_egid;
3516 expected_euid = atoi(expected_euid_str);
3517 expected_egid = atoi(expected_egid_str);
3519 if (strcmp(rexec, "1") == 0) {
3520 /* we're expecting to run setid */
3521 if ((getuid() != geteuid()) && (expected_euid == geteuid()) &&
3522 (getgid() != getegid()) && (expected_egid == getegid()))
3524 } else if (strcmp(rexec, "0") == 0) {
3525 /* we're expecting to not run setid */
3526 if ((getuid() == geteuid()) && (expected_euid == geteuid()) &&
3527 (getgid() == getegid()) && (expected_egid == getegid()))
3530 die("failure: non-setid");
3537 /* Validate that setid transitions are handled correctly. */
3538 static int setid_binaries(void)
3541 int file1_fd = -EBADF, exec_fd = -EBADF;
3544 /* create a file to be used as setuid binary */
3545 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3547 log_stderr("failure: openat");
3551 /* open our own executable */
3552 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3554 log_stderr("failure: openat");
3558 /* copy our own executable into the file we created */
3559 if (fd_to_fd(exec_fd, file1_fd)) {
3560 log_stderr("failure: fd_to_fd");
3564 /* chown the file to the uid and gid we want to assume */
3565 if (fchown(file1_fd, 5000, 5000)) {
3566 log_stderr("failure: fchown");
3570 /* set the setid bits and grant execute permissions to the group */
3571 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3572 log_stderr("failure: fchmod");
3576 /* Verify that the sid bits got raised. */
3577 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3578 log_stderr("failure: is_setid");
3582 safe_close(exec_fd);
3583 safe_close(file1_fd);
3585 /* Verify we run setid binary as uid and gid 5000 from the original
3590 log_stderr("failure: fork");
3594 static char *envp[] = {
3595 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3596 "EXPECTED_EUID=5000",
3597 "EXPECTED_EGID=5000",
3600 static char *argv[] = {
3604 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 5000, 5000))
3605 die("failure: expected_uid_gid");
3607 sys_execveat(t_dir1_fd, FILE1, argv, envp, 0);
3608 die("failure: sys_execveat");
3612 if (wait_for_pid(pid))
3616 log_debug("Ran test");
3622 /* Validate that setid transitions are handled correctly on idmapped mounts. */
3623 static int setid_binaries_idmapped_mounts(void)
3626 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3627 struct mount_attr attr = {
3628 .attr_set = MOUNT_ATTR_IDMAP,
3632 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3633 log_stderr("failure: mkdirat");
3637 /* create a file to be used as setuid binary */
3638 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3640 log_stderr("failure: openat");
3644 /* open our own executable */
3645 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3647 log_stderr("failure:openat ");
3651 /* copy our own executable into the file we created */
3652 if (fd_to_fd(exec_fd, file1_fd)) {
3653 log_stderr("failure: fd_to_fd");
3657 /* chown the file to the uid and gid we want to assume */
3658 if (fchown(file1_fd, 5000, 5000)) {
3659 log_stderr("failure: fchown");
3663 /* set the setid bits and grant execute permissions to the group */
3664 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3665 log_stderr("failure: fchmod");
3669 /* Verify that the sid bits got raised. */
3670 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3671 log_stderr("failure: is_setid");
3675 safe_close(exec_fd);
3676 safe_close(file1_fd);
3678 /* Changing mount properties on a detached mount. */
3679 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3680 if (attr.userns_fd < 0) {
3681 log_stderr("failure: get_userns_fd");
3685 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3688 AT_SYMLINK_NOFOLLOW |
3691 if (open_tree_fd < 0) {
3692 log_stderr("failure: sys_open_tree");
3696 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3697 log_stderr("failure: sys_mount_setattr");
3701 /* A detached mount will have an anonymous mount namespace attached to
3702 * it. This means that we can't execute setid binaries on a detached
3703 * mount because the mnt_may_suid() helper will fail the check_mount()
3704 * part of its check which compares the caller's mount namespace to the
3705 * detached mount's mount namespace. Since by definition an anonymous
3706 * mount namespace is not equale to any mount namespace currently in
3707 * use this can't work. So attach the mount to the filesystem first
3708 * before performing this check.
3710 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3711 log_stderr("failure: sys_move_mount");
3715 /* Verify we run setid binary as uid and gid 10000 from idmapped mount mount. */
3718 log_stderr("failure: fork");
3722 static char *envp[] = {
3723 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3724 "EXPECTED_EUID=15000",
3725 "EXPECTED_EGID=15000",
3728 static char *argv[] = {
3732 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 15000, 15000))
3733 die("failure: expected_uid_gid");
3735 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3736 die("failure: sys_execveat");
3741 if (wait_for_pid(pid))
3745 log_debug("Ran test");
3747 safe_close(exec_fd);
3748 safe_close(file1_fd);
3749 safe_close(open_tree_fd);
3751 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3752 sys_umount2(t_buf, MNT_DETACH);
3753 rm_r(t_mnt_fd, DIR1);
3758 /* Validate that setid transitions are handled correctly on idmapped mounts
3759 * running in a user namespace where the uid and gid of the setid binary have no
3762 static int setid_binaries_idmapped_mounts_in_userns(void)
3765 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3766 struct mount_attr attr = {
3767 .attr_set = MOUNT_ATTR_IDMAP,
3771 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3772 log_stderr("failure: ");
3776 /* create a file to be used as setuid binary */
3777 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3779 log_stderr("failure: openat");
3783 /* open our own executable */
3784 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3786 log_stderr("failure: openat");
3790 /* copy our own executable into the file we created */
3791 if (fd_to_fd(exec_fd, file1_fd)) {
3792 log_stderr("failure: fd_to_fd");
3796 safe_close(exec_fd);
3798 /* chown the file to the uid and gid we want to assume */
3799 if (fchown(file1_fd, 5000, 5000)) {
3800 log_stderr("failure: fchown");
3804 /* set the setid bits and grant execute permissions to the group */
3805 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3806 log_stderr("failure: fchmod");
3810 /* Verify that the sid bits got raised. */
3811 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3812 log_stderr("failure: is_setid");
3816 safe_close(file1_fd);
3818 /* Changing mount properties on a detached mount. */
3819 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3820 if (attr.userns_fd < 0) {
3821 log_stderr("failure: get_userns_fd");
3825 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3828 AT_SYMLINK_NOFOLLOW |
3831 if (open_tree_fd < 0) {
3832 log_stderr("failure: sys_open_tree");
3836 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3837 log_stderr("failure: sys_mount_setattr");
3841 /* A detached mount will have an anonymous mount namespace attached to
3842 * it. This means that we can't execute setid binaries on a detached
3843 * mount because the mnt_may_suid() helper will fail the check_mount()
3844 * part of its check which compares the caller's mount namespace to the
3845 * detached mount's mount namespace. Since by definition an anonymous
3846 * mount namespace is not equale to any mount namespace currently in
3847 * use this can't work. So attach the mount to the filesystem first
3848 * before performing this check.
3850 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3851 log_stderr("failure: sys_move_mount");
3857 log_stderr("failure: fork");
3861 static char *envp[] = {
3862 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3863 "EXPECTED_EUID=5000",
3864 "EXPECTED_EGID=5000",
3867 static char *argv[] = {
3871 if (!switch_userns(attr.userns_fd, 0, 0, false))
3872 die("failure: switch_userns");
3874 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
3875 die("failure: expected_uid_gid");
3877 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3878 die("failure: sys_execveat");
3883 if (wait_for_pid(pid)) {
3884 log_stderr("failure: wait_for_pid");
3888 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3890 log_stderr("failure: openat");
3894 /* chown the file to the uid and gid we want to assume */
3895 if (fchown(file1_fd, 0, 0)) {
3896 log_stderr("failure: fchown");
3900 /* set the setid bits and grant execute permissions to the group */
3901 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3902 log_stderr("failure: fchmod");
3906 /* Verify that the sid bits got raised. */
3907 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3908 log_stderr("failure: is_setid");
3912 safe_close(file1_fd);
3916 log_stderr("failure: fork");
3920 static char *envp[] = {
3921 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3926 static char *argv[] = {
3930 if (!caps_supported()) {
3931 log_debug("skip: capability library not installed");
3935 if (!switch_userns(attr.userns_fd, 5000, 5000, true))
3936 die("failure: switch_userns");
3938 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
3939 die("failure: expected_uid_gid");
3941 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3942 die("failure: sys_execveat");
3947 if (wait_for_pid(pid)) {
3948 log_stderr("failure: wait_for_pid");
3952 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3954 log_stderr("failure: openat");
3958 /* chown the file to the uid and gid we want to assume */
3959 if (fchown(file1_fd, 30000, 30000)) {
3960 log_stderr("failure: fchown");
3964 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
3965 log_stderr("failure: fchmod");
3969 /* Verify that the sid bits got raised. */
3970 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3971 log_stderr("failure: is_setid");
3975 safe_close(file1_fd);
3977 /* Verify that we can't assume a uid and gid of a setid binary for which
3978 * we have no mapping in our user namespace.
3982 log_stderr("failure: fork");
3986 char expected_euid[100];
3987 char expected_egid[100];
3988 static char *envp[4] = {
3994 static char *argv[] = {
3998 if (!switch_userns(attr.userns_fd, 0, 0, false))
3999 die("failure: switch_userns");
4001 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
4002 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
4003 envp[1] = expected_euid;
4004 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
4005 envp[2] = expected_egid;
4007 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4008 die("failure: expected_uid_gid");
4010 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4011 die("failure: sys_execveat");
4016 if (wait_for_pid(pid)) {
4017 log_stderr("failure: wait_for_pid");
4022 log_debug("Ran test");
4024 safe_close(attr.userns_fd);
4025 safe_close(exec_fd);
4026 safe_close(file1_fd);
4027 safe_close(open_tree_fd);
4029 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4030 sys_umount2(t_buf, MNT_DETACH);
4031 rm_r(t_mnt_fd, DIR1);
4036 /* Validate that setid transitions are handled correctly on idmapped mounts
4037 * running in a user namespace where the uid and gid of the setid binary have no
4040 static int setid_binaries_idmapped_mounts_in_userns_separate_userns(void)
4043 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
4044 struct mount_attr attr = {
4045 .attr_set = MOUNT_ATTR_IDMAP,
4049 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
4050 log_stderr("failure: mkdirat");
4054 /* create a file to be used as setuid binary */
4055 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
4057 log_stderr("failure: openat");
4061 /* open our own executable */
4062 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
4064 log_stderr("failure: openat");
4068 /* copy our own executable into the file we created */
4069 if (fd_to_fd(exec_fd, file1_fd)) {
4070 log_stderr("failure: fd_to_fd");
4074 safe_close(exec_fd);
4076 /* change ownership of all files to uid 0 */
4077 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
4078 log_stderr("failure: chown_r");
4082 /* chown the file to the uid and gid we want to assume */
4083 if (fchown(file1_fd, 25000, 25000)) {
4084 log_stderr("failure: fchown");
4088 /* set the setid bits and grant execute permissions to the group */
4089 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4090 log_stderr("failure: fchmod");
4094 /* Verify that the sid bits got raised. */
4095 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4096 log_stderr("failure: is_setid");
4100 safe_close(file1_fd);
4102 /* Changing mount properties on a detached mount. */
4103 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
4104 if (attr.userns_fd < 0) {
4105 log_stderr("failure: get_userns_fd");
4109 open_tree_fd = sys_open_tree(t_dir1_fd, "",
4112 AT_SYMLINK_NOFOLLOW |
4115 if (open_tree_fd < 0) {
4116 log_stderr("failure: sys_open_tree");
4120 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4121 log_stderr("failure: sys_mount_setattr");
4125 /* A detached mount will have an anonymous mount namespace attached to
4126 * it. This means that we can't execute setid binaries on a detached
4127 * mount because the mnt_may_suid() helper will fail the check_mount()
4128 * part of its check which compares the caller's mount namespace to the
4129 * detached mount's mount namespace. Since by definition an anonymous
4130 * mount namespace is not equale to any mount namespace currently in
4131 * use this can't work. So attach the mount to the filesystem first
4132 * before performing this check.
4134 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
4135 log_stderr("failure: sys_move_mount");
4141 log_stderr("failure: fork");
4146 static char *envp[] = {
4147 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4148 "EXPECTED_EUID=5000",
4149 "EXPECTED_EGID=5000",
4152 static char *argv[] = {
4156 userns_fd = get_userns_fd(0, 10000, 10000);
4158 die("failure: get_userns_fd");
4160 if (!switch_userns(userns_fd, 0, 0, false))
4161 die("failure: switch_userns");
4163 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
4164 die("failure: expected_uid_gid");
4166 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4167 die("failure: sys_execveat");
4172 if (wait_for_pid(pid)) {
4173 log_stderr("failure: wait_for_pid");
4177 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4179 log_stderr("failure: openat");
4183 /* chown the file to the uid and gid we want to assume */
4184 if (fchown(file1_fd, 20000, 20000)) {
4185 log_stderr("failure: fchown");
4189 /* set the setid bits and grant execute permissions to the group */
4190 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4191 log_stderr("failure: fchmod");
4195 /* Verify that the sid bits got raised. */
4196 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4197 log_stderr("failure: is_setid");
4201 safe_close(file1_fd);
4205 log_stderr("failure: fork");
4210 static char *envp[] = {
4211 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4216 static char *argv[] = {
4220 userns_fd = get_userns_fd(0, 10000, 10000);
4222 die("failure: get_userns_fd");
4224 if (!caps_supported()) {
4225 log_debug("skip: capability library not installed");
4229 if (!switch_userns(userns_fd, 1000, 1000, true))
4230 die("failure: switch_userns");
4232 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
4233 die("failure: expected_uid_gid");
4235 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4236 die("failure: sys_execveat");
4240 if (wait_for_pid(pid)) {
4241 log_stderr("failure: wait_for_pid");
4245 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4247 log_stderr("failure: openat");
4251 /* chown the file to the uid and gid we want to assume */
4252 if (fchown(file1_fd, 0, 0)) {
4253 log_stderr("failure: fchown");
4257 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
4258 log_stderr("failure: fchmod");
4262 /* Verify that the sid bits got raised. */
4263 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4264 log_stderr("failure: is_setid");
4268 safe_close(file1_fd);
4270 /* Verify that we can't assume a uid and gid of a setid binary for
4271 * which we have no mapping in our user namespace.
4275 log_stderr("failure: fork");
4280 char expected_euid[100];
4281 char expected_egid[100];
4282 static char *envp[4] = {
4288 static char *argv[] = {
4292 userns_fd = get_userns_fd(0, 10000, 10000);
4294 die("failure: get_userns_fd");
4296 if (!switch_userns(userns_fd, 0, 0, false))
4297 die("failure: switch_userns");
4299 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
4300 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
4301 envp[1] = expected_euid;
4302 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
4303 envp[2] = expected_egid;
4305 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4306 die("failure: expected_uid_gid");
4308 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4309 die("failure: sys_execveat");
4313 if (wait_for_pid(pid)) {
4314 log_stderr("failure: wait_for_pid");
4319 log_debug("Ran test");
4321 safe_close(attr.userns_fd);
4322 safe_close(exec_fd);
4323 safe_close(file1_fd);
4324 safe_close(open_tree_fd);
4326 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4327 sys_umount2(t_buf, MNT_DETACH);
4328 rm_r(t_mnt_fd, DIR1);
4333 static int sticky_bit_unlink(void)
4336 int dir_fd = -EBADF;
4339 if (!caps_supported())
4342 /* create directory */
4343 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4344 log_stderr("failure: mkdirat");
4348 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4350 log_stderr("failure: openat");
4354 if (fchown(dir_fd, 0, 0)) {
4355 log_stderr("failure: fchown");
4359 if (fchmod(dir_fd, 0777)) {
4360 log_stderr("failure: fchmod");
4364 /* create regular file via mknod */
4365 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4366 log_stderr("failure: mknodat");
4369 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4370 log_stderr("failure: fchownat");
4373 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4374 log_stderr("failure: fchmodat");
4378 /* create regular file via mknod */
4379 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4380 log_stderr("failure: mknodat");
4383 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4384 log_stderr("failure: fchownat");
4387 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4388 log_stderr("failure: fchmodat");
4392 /* The sticky bit is not set so we must be able to delete files not
4397 log_stderr("failure: fork");
4401 if (!switch_ids(1000, 1000))
4402 die("failure: switch_ids");
4404 if (unlinkat(dir_fd, FILE1, 0))
4405 die("failure: unlinkat");
4407 if (unlinkat(dir_fd, FILE2, 0))
4408 die("failure: unlinkat");
4412 if (wait_for_pid(pid)) {
4413 log_stderr("failure: wait_for_pid");
4417 /* set sticky bit */
4418 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4419 log_stderr("failure: fchmod");
4423 /* validate sticky bit is set */
4424 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4425 log_stderr("failure: is_sticky");
4429 /* create regular file via mknod */
4430 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4431 log_stderr("failure: mknodat");
4434 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4435 log_stderr("failure: fchownat");
4438 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4439 log_stderr("failure: fchmodat");
4443 /* create regular file via mknod */
4444 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4445 log_stderr("failure: mknodat");
4448 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4449 log_stderr("failure: fchownat");
4452 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4453 log_stderr("failure: fchmodat");
4457 /* The sticky bit is set so we must not be able to delete files not
4462 log_stderr("failure: fork");
4466 if (!switch_ids(1000, 1000))
4467 die("failure: switch_ids");
4469 if (!unlinkat(dir_fd, FILE1, 0))
4470 die("failure: unlinkat");
4472 die("failure: errno");
4474 if (!unlinkat(dir_fd, FILE2, 0))
4475 die("failure: unlinkat");
4477 die("failure: errno");
4481 if (wait_for_pid(pid)) {
4482 log_stderr("failure: wait_for_pid");
4486 /* The sticky bit is set and we own the files so we must be able to
4487 * delete the files now.
4491 log_stderr("failure: fork");
4495 /* change ownership */
4496 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4497 die("failure: fchownat");
4498 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4499 die("failure: expected_uid_gid");
4500 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4501 die("failure: fchownat");
4502 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4503 die("failure: expected_uid_gid");
4505 if (!switch_ids(1000, 1000))
4506 die("failure: switch_ids");
4508 if (unlinkat(dir_fd, FILE1, 0))
4509 die("failure: unlinkat");
4511 if (unlinkat(dir_fd, FILE2, 0))
4512 die("failure: unlinkat");
4516 if (wait_for_pid(pid)) {
4517 log_stderr("failure: wait_for_pid");
4521 /* change uid to unprivileged user */
4522 if (fchown(dir_fd, 1000, -1)) {
4523 log_stderr("failure: fchown");
4526 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4527 log_stderr("failure: fchmod");
4530 /* validate sticky bit is set */
4531 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4532 log_stderr("failure: is_sticky");
4536 /* create regular file via mknod */
4537 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4538 log_stderr("failure: mknodat");
4541 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4542 log_stderr("failure: fchownat");
4545 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4546 log_stderr("failure: fchmodat");
4550 /* create regular file via mknod */
4551 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4552 log_stderr("failure: mknodat");
4555 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4556 log_stderr("failure: fchownat");
4559 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4560 log_stderr("failure: fchmodat");
4564 /* The sticky bit is set and we own the directory so we must be able to
4565 * delete the files now.
4569 log_stderr("failure: fork");
4573 if (!switch_ids(1000, 1000))
4574 die("failure: switch_ids");
4576 if (unlinkat(dir_fd, FILE1, 0))
4577 die("failure: unlinkat");
4579 if (unlinkat(dir_fd, FILE2, 0))
4580 die("failure: unlinkat");
4584 if (wait_for_pid(pid)) {
4585 log_stderr("failure: wait_for_pid");
4590 log_debug("Ran test");
4597 static int sticky_bit_unlink_idmapped_mounts(void)
4600 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4601 struct mount_attr attr = {
4602 .attr_set = MOUNT_ATTR_IDMAP,
4606 if (!caps_supported())
4609 /* create directory */
4610 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4611 log_stderr("failure: mkdirat");
4615 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4617 log_stderr("failure: openat");
4620 if (fchown(dir_fd, 10000, 10000)) {
4621 log_stderr("failure: fchown");
4624 if (fchmod(dir_fd, 0777)) {
4625 log_stderr("failure: fchmod");
4629 /* create regular file via mknod */
4630 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4631 log_stderr("failure: mknodat");
4634 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4635 log_stderr("failure: fchownat");
4638 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4639 log_stderr("failure: fchmodat");
4643 /* create regular file via mknod */
4644 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4645 log_stderr("failure: mknodat");
4648 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4649 log_stderr("failure: fchownat");
4652 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4653 log_stderr("failure: fchmodat");
4657 /* Changing mount properties on a detached mount. */
4658 attr.userns_fd = get_userns_fd(10000, 0, 10000);
4659 if (attr.userns_fd < 0) {
4660 log_stderr("failure: get_userns_fd");
4664 open_tree_fd = sys_open_tree(dir_fd, "",
4667 AT_SYMLINK_NOFOLLOW |
4670 if (open_tree_fd < 0) {
4671 log_stderr("failure: sys_open_tree");
4675 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4676 log_stderr("failure: sys_mount_setattr");
4680 /* The sticky bit is not set so we must be able to delete files not
4685 log_stderr("failure: fork");
4689 if (!switch_ids(1000, 1000))
4690 die("failure: switch_ids");
4692 if (unlinkat(open_tree_fd, FILE1, 0))
4693 die("failure: unlinkat");
4695 if (unlinkat(open_tree_fd, FILE2, 0))
4696 die("failure: unlinkat");
4700 if (wait_for_pid(pid)) {
4701 log_stderr("failure: wait_for_pid");
4705 /* set sticky bit */
4706 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4707 log_stderr("failure: fchmod");
4711 /* validate sticky bit is set */
4712 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4713 log_stderr("failure: is_sticky");
4717 /* create regular file via mknod */
4718 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4719 log_stderr("failure: mknodat");
4722 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4723 log_stderr("failure: fchownat");
4726 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4727 log_stderr("failure: fchmodat");
4731 /* create regular file via mknod */
4732 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4733 log_stderr("failure: mknodat");
4736 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4737 log_stderr("failure: fchownat");
4740 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4741 log_stderr("failure: fchmodat");
4745 /* The sticky bit is set so we must not be able to delete files not
4750 log_stderr("failure: fork");
4754 if (!switch_ids(1000, 1000))
4755 die("failure: switch_ids");
4757 if (!unlinkat(open_tree_fd, FILE1, 0))
4758 die("failure: unlinkat");
4760 die("failure: errno");
4762 if (!unlinkat(open_tree_fd, FILE2, 0))
4763 die("failure: unlinkat");
4765 die("failure: errno");
4769 if (wait_for_pid(pid)) {
4770 log_stderr("failure: wait_for_pid");
4774 /* The sticky bit is set and we own the files so we must be able to
4775 * delete the files now.
4779 log_stderr("failure: fork");
4783 /* change ownership */
4784 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
4785 die("failure: fchownat");
4786 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
4787 die("failure: expected_uid_gid");
4788 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
4789 die("failure: fchownat");
4790 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
4791 die("failure: expected_uid_gid");
4793 if (!switch_ids(1000, 1000))
4794 die("failure: switch_ids");
4796 if (unlinkat(open_tree_fd, FILE1, 0))
4797 die("failure: unlinkat");
4799 if (unlinkat(open_tree_fd, FILE2, 0))
4800 die("failure: unlinkat");
4804 if (wait_for_pid(pid)) {
4805 log_stderr("failure: wait_for_pid");
4809 /* change uid to unprivileged user */
4810 if (fchown(dir_fd, 11000, -1)) {
4811 log_stderr("failure: fchown");
4814 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4815 log_stderr("failure: fchmod");
4818 /* validate sticky bit is set */
4819 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4820 log_stderr("failure: is_sticky");
4824 /* create regular file via mknod */
4825 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4826 log_stderr("failure: mknodat");
4829 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4830 log_stderr("failure: fchownat");
4833 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4834 log_stderr("failure: fchmodat");
4838 /* create regular file via mknod */
4839 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4840 log_stderr("failure: mknodat");
4843 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4844 log_stderr("failure: fchownat");
4847 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4848 log_stderr("failure: fchmodat");
4852 /* The sticky bit is set and we own the directory so we must be able to
4853 * delete the files now.
4857 log_stderr("failure: fork");
4861 if (!switch_ids(1000, 1000))
4862 die("failure: switch_ids");
4864 if (unlinkat(open_tree_fd, FILE1, 0))
4865 die("failure: unlinkat");
4867 if (unlinkat(open_tree_fd, FILE2, 0))
4868 die("failure: unlinkat");
4872 if (wait_for_pid(pid)) {
4873 log_stderr("failure: wait_for_pid");
4878 log_debug("Ran test");
4880 safe_close(attr.userns_fd);
4882 safe_close(open_tree_fd);
4887 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
4888 * operations in a user namespace.
4890 static int sticky_bit_unlink_idmapped_mounts_in_userns(void)
4893 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4894 struct mount_attr attr = {
4895 .attr_set = MOUNT_ATTR_IDMAP,
4899 if (!caps_supported())
4902 /* create directory */
4903 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4904 log_stderr("failure: mkdirat");
4908 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4910 log_stderr("failure: openat");
4913 if (fchown(dir_fd, 0, 0)) {
4914 log_stderr("failure: fchown");
4917 if (fchmod(dir_fd, 0777)) {
4918 log_stderr("failure: fchmod");
4922 /* create regular file via mknod */
4923 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4924 log_stderr("failure: mknodat");
4927 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4928 log_stderr("failure: fchownat");
4931 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4932 log_stderr("failure: fchmodat");
4936 /* create regular file via mknod */
4937 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4938 log_stderr("failure: mknodat");
4941 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4942 log_stderr("failure: fchownat");
4945 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4946 log_stderr("failure: fchmodat");
4950 /* Changing mount properties on a detached mount. */
4951 attr.userns_fd = get_userns_fd(0, 10000, 10000);
4952 if (attr.userns_fd < 0) {
4953 log_stderr("failure: get_userns_fd");
4957 open_tree_fd = sys_open_tree(dir_fd, "",
4960 AT_SYMLINK_NOFOLLOW |
4963 if (open_tree_fd < 0) {
4964 log_stderr("failure: sys_open_tree");
4968 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4969 log_stderr("failure: sys_mount_setattr");
4973 /* The sticky bit is not set so we must be able to delete files not
4978 log_stderr("failure: fork");
4982 if (!caps_supported()) {
4983 log_debug("skip: capability library not installed");
4987 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4988 die("failure: switch_userns");
4990 if (unlinkat(dir_fd, FILE1, 0))
4991 die("failure: unlinkat");
4993 if (unlinkat(dir_fd, FILE2, 0))
4994 die("failure: unlinkat");
4998 if (wait_for_pid(pid)) {
4999 log_stderr("failure: wait_for_pid");
5003 /* set sticky bit */
5004 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5005 log_stderr("failure: fchmod");
5009 /* validate sticky bit is set */
5010 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5011 log_stderr("failure: is_sticky");
5015 /* create regular file via mknod */
5016 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5017 log_stderr("failure: mknodat");
5020 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5021 log_stderr("failure: fchownat");
5024 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5025 log_stderr("failure: fchmodat");
5029 /* create regular file via mknod */
5030 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5031 log_stderr("failure: mknodat");
5034 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5035 log_stderr("failure: fchownat");
5038 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5039 log_stderr("failure: fchmodat");
5043 /* The sticky bit is set so we must not be able to delete files not
5048 log_stderr("failure: fork");
5052 if (!caps_supported()) {
5053 log_debug("skip: capability library not installed");
5057 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5058 die("failure: switch_userns");
5060 if (!unlinkat(dir_fd, FILE1, 0))
5061 die("failure: unlinkat");
5063 die("failure: errno");
5065 if (!unlinkat(dir_fd, FILE2, 0))
5066 die("failure: unlinkat");
5068 die("failure: errno");
5070 if (!unlinkat(open_tree_fd, FILE1, 0))
5071 die("failure: unlinkat");
5073 die("failure: errno");
5075 if (!unlinkat(open_tree_fd, FILE2, 0))
5076 die("failure: unlinkat");
5078 die("failure: errno");
5082 if (wait_for_pid(pid)) {
5083 log_stderr("failure: wait_for_pid");
5087 /* The sticky bit is set and we own the files so we must be able to
5088 * delete the files now.
5092 log_stderr("failure: fork");
5096 /* change ownership */
5097 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5098 die("failure: fchownat");
5099 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5100 die("failure: expected_uid_gid");
5101 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5102 die("failure: fchownat");
5103 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5104 die("failure: expected_uid_gid");
5106 if (!caps_supported()) {
5107 log_debug("skip: capability library not installed");
5111 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5112 die("failure: switch_userns");
5114 if (!unlinkat(dir_fd, FILE1, 0))
5115 die("failure: unlinkat");
5117 die("failure: errno");
5119 if (!unlinkat(dir_fd, FILE2, 0))
5120 die("failure: unlinkat");
5122 die("failure: errno");
5124 if (unlinkat(open_tree_fd, FILE1, 0))
5125 die("failure: unlinkat");
5127 if (unlinkat(open_tree_fd, FILE2, 0))
5128 die("failure: unlinkat");
5132 if (wait_for_pid(pid)) {
5133 log_stderr("failure: wait_for_pid");
5137 /* change uid to unprivileged user */
5138 if (fchown(dir_fd, 1000, -1)) {
5139 log_stderr("failure: fchown");
5142 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5143 log_stderr("failure: fchmod");
5146 /* validate sticky bit is set */
5147 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5148 log_stderr("failure: is_sticky");
5152 /* create regular file via mknod */
5153 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5154 log_stderr("failure: mknodat");
5157 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5158 log_stderr("failure: fchownat");
5161 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5162 log_stderr("failure: fchmodat");
5166 /* create regular file via mknod */
5167 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5168 log_stderr("failure: mknodat");
5171 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5172 log_stderr("failure: fchownat");
5175 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5176 log_stderr("failure: fchmodat");
5180 /* The sticky bit is set and we own the directory so we must be able to
5181 * delete the files now.
5185 log_stderr("failure: fork");
5189 if (!caps_supported()) {
5190 log_debug("skip: capability library not installed");
5194 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5195 die("failure: switch_userns");
5197 /* we don't own the directory from the original mount */
5198 if (!unlinkat(dir_fd, FILE1, 0))
5199 die("failure: unlinkat");
5201 die("failure: errno");
5203 if (!unlinkat(dir_fd, FILE2, 0))
5204 die("failure: unlinkat");
5206 die("failure: errno");
5208 /* we own the file from the idmapped mount */
5209 if (unlinkat(open_tree_fd, FILE1, 0))
5210 die("failure: unlinkat");
5211 if (unlinkat(open_tree_fd, FILE2, 0))
5212 die("failure: unlinkat");
5216 if (wait_for_pid(pid)) {
5217 log_stderr("failure: wait_for_pid");
5222 log_debug("Ran test");
5224 safe_close(attr.userns_fd);
5226 safe_close(open_tree_fd);
5231 static int sticky_bit_rename(void)
5234 int dir_fd = -EBADF;
5237 if (!caps_supported())
5240 /* create directory */
5241 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5242 log_stderr("failure: mkdirat");
5246 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5248 log_stderr("failure: openat");
5251 if (fchown(dir_fd, 0, 0)) {
5252 log_stderr("failure: fchown");
5255 if (fchmod(dir_fd, 0777)) {
5256 log_stderr("failure: fchmod");
5260 /* create regular file via mknod */
5261 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5262 log_stderr("failure: mknodat");
5265 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5266 log_stderr("failure: fchownat");
5269 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5270 log_stderr("failure: fchmodat");
5274 /* create regular file via mknod */
5275 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5276 log_stderr("failure: mknodat");
5279 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5280 log_stderr("failure: fchownat");
5283 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5284 log_stderr("failure: fchmodat");
5288 /* The sticky bit is not set so we must be able to delete files not
5293 log_stderr("failure: fork");
5297 if (!switch_ids(1000, 1000))
5298 die("failure: switch_ids");
5300 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5301 die("failure: renameat");
5303 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5304 die("failure: renameat");
5306 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5307 die("failure: renameat");
5309 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5310 die("failure: renameat");
5314 if (wait_for_pid(pid)) {
5315 log_stderr("failure: wait_for_pid");
5319 /* set sticky bit */
5320 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5321 log_stderr("failure: fchmod");
5325 /* validate sticky bit is set */
5326 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5327 log_stderr("failure: is_sticky");
5331 /* The sticky bit is set so we must not be able to delete files not
5336 log_stderr("failure: fork");
5340 if (!switch_ids(1000, 1000))
5341 die("failure: switch_ids");
5343 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5344 die("failure: renameat");
5346 die("failure: errno");
5348 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5349 die("failure: renameat");
5351 die("failure: errno");
5355 if (wait_for_pid(pid)) {
5356 log_stderr("failure: wait_for_pid");
5360 /* The sticky bit is set and we own the files so we must be able to
5361 * delete the files now.
5365 log_stderr("failure: fork");
5369 /* change ownership */
5370 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5371 die("failure: fchownat");
5372 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5373 die("failure: expected_uid_gid");
5374 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5375 die("failure: fchownat");
5376 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5377 die("failure: expected_uid_gid");
5379 if (!switch_ids(1000, 1000))
5380 die("failure: switch_ids");
5382 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5383 die("failure: renameat");
5385 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5386 die("failure: renameat");
5388 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5389 die("failure: renameat");
5391 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5392 die("failure: renameat");
5396 if (wait_for_pid(pid)) {
5397 log_stderr("failure: wait_for_pid");
5401 /* change uid to unprivileged user */
5402 if (fchown(dir_fd, 1000, -1)) {
5403 log_stderr("failure: fchown");
5406 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5407 log_stderr("failure: fchmod");
5410 /* validate sticky bit is set */
5411 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5412 log_stderr("failure: is_sticky");
5417 /* The sticky bit is set and we own the directory so we must be able to
5418 * delete the files now.
5422 log_stderr("failure: fork");
5426 if (!switch_ids(1000, 1000))
5427 die("failure: switch_ids");
5429 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5430 die("failure: renameat");
5432 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5433 die("failure: renameat");
5435 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5436 die("failure: renameat");
5438 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5439 die("failure: renameat");
5443 if (wait_for_pid(pid)) {
5444 log_stderr("failure: wait_for_pid");
5449 log_debug("Ran test");
5456 static int sticky_bit_rename_idmapped_mounts(void)
5459 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5460 struct mount_attr attr = {
5461 .attr_set = MOUNT_ATTR_IDMAP,
5465 if (!caps_supported())
5468 /* create directory */
5469 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5470 log_stderr("failure: mkdirat");
5474 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5476 log_stderr("failure: openat");
5480 if (fchown(dir_fd, 10000, 10000)) {
5481 log_stderr("failure: fchown");
5485 if (fchmod(dir_fd, 0777)) {
5486 log_stderr("failure: fchmod");
5490 /* create regular file via mknod */
5491 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5492 log_stderr("failure: mknodat");
5495 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
5496 log_stderr("failure: fchownat");
5499 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5500 log_stderr("failure: fchmodat");
5504 /* create regular file via mknod */
5505 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5506 log_stderr("failure: mknodat");
5509 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
5510 log_stderr("failure: fchownat");
5513 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5514 log_stderr("failure: fchmodat");
5518 /* Changing mount properties on a detached mount. */
5519 attr.userns_fd = get_userns_fd(10000, 0, 10000);
5520 if (attr.userns_fd < 0) {
5521 log_stderr("failure: get_userns_fd");
5525 open_tree_fd = sys_open_tree(dir_fd, "",
5528 AT_SYMLINK_NOFOLLOW |
5531 if (open_tree_fd < 0) {
5532 log_stderr("failure: sys_open_tree");
5536 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5537 log_stderr("failure: sys_mount_setattr");
5541 /* The sticky bit is not set so we must be able to delete files not
5546 log_stderr("failure: fork");
5550 if (!switch_ids(1000, 1000))
5551 die("failure: switch_ids");
5553 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5554 die("failure: renameat");
5556 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5557 die("failure: renameat");
5559 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5560 die("failure: renameat");
5562 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5563 die("failure: renameat");
5567 if (wait_for_pid(pid)) {
5568 log_stderr("failure: wait_for_pid");
5572 /* set sticky bit */
5573 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5574 log_stderr("failure: fchmod");
5578 /* validate sticky bit is set */
5579 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5580 log_stderr("failure: is_sticky");
5584 /* The sticky bit is set so we must not be able to delete files not
5589 log_stderr("failure: fork");
5593 if (!switch_ids(1000, 1000))
5594 die("failure: switch_ids");
5596 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5597 die("failure: renameat");
5599 die("failure: errno");
5601 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5602 die("failure: renameat");
5604 die("failure: errno");
5608 if (wait_for_pid(pid)) {
5609 log_stderr("failure: wait_for_pid");
5613 /* The sticky bit is set and we own the files so we must be able to
5614 * delete the files now.
5618 log_stderr("failure: fork");
5622 /* change ownership */
5623 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
5624 die("failure: fchownat");
5625 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
5626 die("failure: expected_uid_gid");
5627 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
5628 die("failure: fchownat");
5629 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
5630 die("failure: expected_uid_gid");
5632 if (!switch_ids(1000, 1000))
5633 die("failure: switch_ids");
5635 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5636 die("failure: renameat");
5638 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5639 die("failure: renameat");
5641 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5642 die("failure: renameat");
5644 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5645 die("failure: renameat");
5649 if (wait_for_pid(pid)) {
5650 log_stderr("failure: wait_for_pid");
5654 /* change uid to unprivileged user */
5655 if (fchown(dir_fd, 11000, -1)) {
5656 log_stderr("failure: fchown");
5659 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5660 log_stderr("failure: fchmod");
5663 /* validate sticky bit is set */
5664 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5665 log_stderr("failure: is_sticky");
5669 /* The sticky bit is set and we own the directory so we must be able to
5670 * delete the files now.
5674 log_stderr("failure: fork");
5678 if (!switch_ids(1000, 1000))
5679 die("failure: switch_ids");
5681 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5682 die("failure: renameat");
5684 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5685 die("failure: renameat");
5687 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5688 die("failure: renameat");
5690 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5691 die("failure: renameat");
5695 if (wait_for_pid(pid)) {
5696 log_stderr("failure: wait_for_pid");
5701 log_debug("Ran test");
5703 safe_close(attr.userns_fd);
5705 safe_close(open_tree_fd);
5710 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
5711 * operations in a user namespace.
5713 static int sticky_bit_rename_idmapped_mounts_in_userns(void)
5716 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5717 struct mount_attr attr = {
5718 .attr_set = MOUNT_ATTR_IDMAP,
5722 if (!caps_supported())
5725 /* create directory */
5726 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5727 log_stderr("failure: mkdirat");
5731 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5733 log_stderr("failure: openat");
5736 if (fchown(dir_fd, 0, 0)) {
5737 log_stderr("failure: fchown");
5740 if (fchmod(dir_fd, 0777)) {
5741 log_stderr("failure: fchmod");
5745 /* create regular file via mknod */
5746 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5747 log_stderr("failure: mknodat");
5750 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5751 log_stderr("failure: fchownat");
5754 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5755 log_stderr("failure: fchmodat");
5759 /* create regular file via mknod */
5760 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5761 log_stderr("failure: mknodat");
5764 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5765 log_stderr("failure: fchownat");
5768 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5769 log_stderr("failure: fchmodat");
5773 /* Changing mount properties on a detached mount. */
5774 attr.userns_fd = get_userns_fd(0, 10000, 10000);
5775 if (attr.userns_fd < 0) {
5776 log_stderr("failure: get_userns_fd");
5780 open_tree_fd = sys_open_tree(dir_fd, "",
5783 AT_SYMLINK_NOFOLLOW |
5786 if (open_tree_fd < 0) {
5787 log_stderr("failure: sys_open_tree");
5791 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5792 log_stderr("failure: sys_mount_setattr");
5796 /* The sticky bit is not set so we must be able to delete files not
5801 log_stderr("failure: fork");
5805 if (!caps_supported()) {
5806 log_debug("skip: capability library not installed");
5810 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5811 die("failure: switch_userns");
5813 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5814 die("failure: renameat");
5816 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5817 die("failure: renameat");
5819 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5820 die("failure: renameat");
5822 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5823 die("failure: renameat");
5827 if (wait_for_pid(pid)) {
5828 log_stderr("failure: wait_for_pid");
5832 /* set sticky bit */
5833 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5834 log_stderr("failure: fchmod");
5838 /* validate sticky bit is set */
5839 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5840 log_stderr("failure: is_sticky");
5844 /* The sticky bit is set so we must not be able to delete files not
5849 log_stderr("failure: fork");
5853 if (!caps_supported()) {
5854 log_debug("skip: capability library not installed");
5858 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5859 die("failure: switch_userns");
5861 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5862 die("failure: renameat");
5864 die("failure: errno");
5866 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5867 die("failure: renameat");
5869 die("failure: errno");
5871 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5872 die("failure: renameat");
5874 die("failure: errno");
5876 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5877 die("failure: renameat");
5879 die("failure: errno");
5883 if (wait_for_pid(pid)) {
5884 log_stderr("failure: wait_for_pid");
5888 /* The sticky bit is set and we own the files so we must be able to
5889 * delete the files now.
5893 log_stderr("failure: fork");
5897 /* change ownership */
5898 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5899 die("failure: fchownat");
5900 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5901 die("failure: expected_uid_gid");
5902 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5903 die("failure: fchownat");
5904 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5905 die("failure: expected_uid_gid");
5907 if (!caps_supported()) {
5908 log_debug("skip: capability library not installed");
5912 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5913 die("failure: switch_userns");
5915 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5916 die("failure: renameat");
5918 die("failure: errno");
5920 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5921 die("failure: renameat");
5923 die("failure: errno");
5925 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5926 die("failure: renameat");
5928 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5929 die("failure: renameat");
5931 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5932 die("failure: renameat");
5934 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5935 die("failure: renameat");
5939 if (wait_for_pid(pid)) {
5940 log_stderr("failure: wait_for_pid");
5944 /* change uid to unprivileged user */
5945 if (fchown(dir_fd, 1000, -1)) {
5946 log_stderr("failure: fchown");
5949 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5950 log_stderr("failure: fchmod");
5953 /* validate sticky bit is set */
5954 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5955 log_stderr("failure: is_sticky");
5959 /* The sticky bit is set and we own the directory so we must be able to
5960 * delete the files now.
5964 log_stderr("failure: fork");
5968 if (!caps_supported()) {
5969 log_debug("skip: capability library not installed");
5973 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5974 die("failure: switch_userns");
5976 /* we don't own the directory from the original mount */
5977 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5978 die("failure: renameat");
5980 die("failure: errno");
5982 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5983 die("failure: renameat");
5985 die("failure: errno");
5987 /* we own the file from the idmapped mount */
5988 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5989 die("failure: renameat");
5991 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5992 die("failure: renameat");
5994 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5995 die("failure: renameat");
5997 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5998 die("failure: renameat");
6002 if (wait_for_pid(pid)) {
6003 log_stderr("failure: wait_for_pid");
6008 log_debug("Ran test");
6010 safe_close(open_tree_fd);
6011 safe_close(attr.userns_fd);
6017 /* Validate that protected symlinks work correctly. */
6018 static int protected_symlinks(void)
6021 int dir_fd = -EBADF, fd = -EBADF;
6024 if (!protected_symlinks_enabled())
6027 if (!caps_supported())
6030 /* create directory */
6031 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6032 log_stderr("failure: mkdirat");
6036 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6038 log_stderr("failure: openat");
6041 if (fchown(dir_fd, 0, 0)) {
6042 log_stderr("failure: fchown");
6045 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6046 log_stderr("failure: fchmod");
6049 /* validate sticky bit is set */
6050 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6051 log_stderr("failure: is_sticky");
6055 /* create regular file via mknod */
6056 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6057 log_stderr("failure: mknodat");
6060 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6061 log_stderr("failure: fchownat");
6064 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6065 log_stderr("failure: fchmodat");
6069 /* create symlinks */
6070 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6071 log_stderr("failure: symlinkat");
6074 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6075 log_stderr("failure: fchownat");
6078 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6079 log_stderr("failure: expected_uid_gid");
6082 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6083 log_stderr("failure: expected_uid_gid");
6087 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6088 log_stderr("failure: symlinkat");
6091 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6092 log_stderr("failure: fchownat");
6095 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6096 log_stderr("failure: expected_uid_gid");
6099 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6100 log_stderr("failure: expected_uid_gid");
6104 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6105 log_stderr("failure: symlinkat");
6108 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6109 log_stderr("failure: fchownat");
6112 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6113 log_stderr("failure: expected_uid_gid");
6116 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6117 log_stderr("failure: expected_uid_gid");
6121 /* validate file can be directly read */
6122 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6124 log_stderr("failure: openat");
6129 /* validate file can be read through own symlink */
6130 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6132 log_stderr("failure: openat");
6139 log_stderr("failure: fork");
6143 if (!switch_ids(1000, 1000))
6144 die("failure: switch_ids");
6146 /* validate file can be directly read */
6147 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6149 die("failure: openat");
6152 /* validate file can be read through own symlink */
6153 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6155 die("failure: openat");
6158 /* validate file can be read through root symlink */
6159 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6161 die("failure: openat");
6164 /* validate file can't be read through other users symlink */
6165 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6167 die("failure: openat");
6168 if (errno != EACCES)
6169 die("failure: errno");
6173 if (wait_for_pid(pid)) {
6174 log_stderr("failure: wait_for_pid");
6180 log_stderr("failure: fork");
6184 if (!switch_ids(2000, 2000))
6185 die("failure: switch_ids");
6187 /* validate file can be directly read */
6188 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6190 die("failure: openat");
6193 /* validate file can be read through own symlink */
6194 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6196 die("failure: openat");
6199 /* validate file can be read through root symlink */
6200 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6202 die("failure: openat");
6205 /* validate file can't be read through other users symlink */
6206 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6208 die("failure: openat");
6209 if (errno != EACCES)
6210 die("failure: errno");
6214 if (wait_for_pid(pid)) {
6215 log_stderr("failure: wait_for_pid");
6220 log_debug("Ran test");
6228 /* Validate that protected symlinks work correctly on idmapped mounts. */
6229 static int protected_symlinks_idmapped_mounts(void)
6232 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6233 struct mount_attr attr = {
6234 .attr_set = MOUNT_ATTR_IDMAP,
6238 if (!protected_symlinks_enabled())
6241 if (!caps_supported())
6244 /* create directory */
6245 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6246 log_stderr("failure: mkdirat");
6250 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6252 log_stderr("failure: openat");
6255 if (fchown(dir_fd, 10000, 10000)) {
6256 log_stderr("failure: fchown");
6259 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6260 log_stderr("failure: fchmod");
6263 /* validate sticky bit is set */
6264 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6265 log_stderr("failure: is_sticky");
6269 /* create regular file via mknod */
6270 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6271 log_stderr("failure: mknodat");
6274 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
6275 log_stderr("failure: fchownat");
6278 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6279 log_stderr("failure: fchmodat");
6283 /* create symlinks */
6284 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6285 log_stderr("failure: symlinkat");
6288 if (fchownat(dir_fd, SYMLINK_USER1, 10000, 10000, AT_SYMLINK_NOFOLLOW)) {
6289 log_stderr("failure: fchownat");
6292 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
6293 log_stderr("failure: expected_uid_gid");
6296 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6297 log_stderr("failure: expected_uid_gid");
6301 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6302 log_stderr("failure: symlinkat");
6305 if (fchownat(dir_fd, SYMLINK_USER2, 11000, 11000, AT_SYMLINK_NOFOLLOW)) {
6306 log_stderr("failure: fchownat");
6309 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 11000, 11000)) {
6310 log_stderr("failure: expected_uid_gid");
6313 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6314 log_stderr("failure: expected_uid_gid");
6318 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6319 log_stderr("failure: symlinkat");
6322 if (fchownat(dir_fd, SYMLINK_USER3, 12000, 12000, AT_SYMLINK_NOFOLLOW)) {
6323 log_stderr("failure: fchownat");
6326 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
6327 log_stderr("failure: expected_uid_gid");
6330 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6331 log_stderr("failure: expected_uid_gid");
6335 /* Changing mount properties on a detached mount. */
6336 attr.userns_fd = get_userns_fd(10000, 0, 10000);
6337 if (attr.userns_fd < 0) {
6338 log_stderr("failure: get_userns_fd");
6342 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6345 AT_SYMLINK_NOFOLLOW |
6348 if (open_tree_fd < 0) {
6349 log_stderr("failure: open_tree_fd");
6353 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6354 log_stderr("failure: sys_mount_setattr");
6358 /* validate file can be directly read */
6359 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6361 log_stderr("failure: openat");
6366 /* validate file can be read through own symlink */
6367 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6369 log_stderr("failure: openat");
6376 log_stderr("failure: fork");
6380 if (!switch_ids(1000, 1000))
6381 die("failure: switch_ids");
6383 /* validate file can be directly read */
6384 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6386 die("failure: openat");
6389 /* validate file can be read through own symlink */
6390 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6392 die("failure: openat");
6395 /* validate file can be read through root symlink */
6396 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6398 die("failure: openat");
6401 /* validate file can't be read through other users symlink */
6402 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6404 die("failure: openat");
6405 if (errno != EACCES)
6406 die("failure: errno");
6410 if (wait_for_pid(pid)) {
6411 log_stderr("failure: wait_for_pid");
6417 log_stderr("failure: fork");
6421 if (!switch_ids(2000, 2000))
6422 die("failure: switch_ids");
6424 /* validate file can be directly read */
6425 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6427 die("failure: openat");
6430 /* validate file can be read through own symlink */
6431 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6433 die("failure: openat");
6436 /* validate file can be read through root symlink */
6437 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6439 die("failure: openat");
6442 /* validate file can't be read through other users symlink */
6443 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6445 die("failure: openat");
6446 if (errno != EACCES)
6447 die("failure: errno");
6451 if (wait_for_pid(pid)) {
6452 log_stderr("failure: wait_for_pid");
6457 log_debug("Ran test");
6459 safe_close(attr.userns_fd);
6462 safe_close(open_tree_fd);
6467 /* Validate that protected symlinks work correctly on idmapped mounts inside a
6470 static int protected_symlinks_idmapped_mounts_in_userns(void)
6473 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6474 struct mount_attr attr = {
6475 .attr_set = MOUNT_ATTR_IDMAP,
6479 if (!protected_symlinks_enabled())
6482 if (!caps_supported())
6485 /* create directory */
6486 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6487 log_stderr("failure: mkdirat");
6491 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6493 log_stderr("failure: openat");
6496 if (fchown(dir_fd, 0, 0)) {
6497 log_stderr("failure: fchown");
6500 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6501 log_stderr("failure: fchmod");
6504 /* validate sticky bit is set */
6505 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6506 log_stderr("failure: is_sticky");
6510 /* create regular file via mknod */
6511 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6512 log_stderr("failure: mknodat");
6515 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6516 log_stderr("failure: fchownat");
6519 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6520 log_stderr("failure: fchmodat");
6524 /* create symlinks */
6525 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6526 log_stderr("failure: symlinkat");
6529 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6530 log_stderr("failure: fchownat");
6533 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6534 log_stderr("failure: expected_uid_gid");
6537 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6538 log_stderr("failure: expected_uid_gid");
6542 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6543 log_stderr("failure: symlinkat");
6546 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6547 log_stderr("failure: fchownat");
6550 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6551 log_stderr("failure: expected_uid_gid");
6554 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6555 log_stderr("failure: expected_uid_gid");
6559 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6560 log_stderr("failure: symlinkat");
6563 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6564 log_stderr("failure: fchownat");
6567 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6568 log_stderr("failure: expected_uid_gid");
6571 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6572 log_stderr("failure: expected_uid_gid");
6576 /* Changing mount properties on a detached mount. */
6577 attr.userns_fd = get_userns_fd(0, 10000, 10000);
6578 if (attr.userns_fd < 0) {
6579 log_stderr("failure: get_userns_fd");
6583 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6586 AT_SYMLINK_NOFOLLOW |
6589 if (open_tree_fd < 0) {
6590 log_stderr("failure: sys_open_tree");
6594 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6595 log_stderr("failure: sys_mount_setattr");
6599 /* validate file can be directly read */
6600 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6602 log_stderr("failure: openat");
6607 /* validate file can be read through own symlink */
6608 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6610 log_stderr("failure: openat");
6617 log_stderr("failure: fork");
6621 if (!caps_supported()) {
6622 log_debug("skip: capability library not installed");
6626 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
6627 die("failure: switch_userns");
6629 /* validate file can be directly read */
6630 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6632 die("failure: openat");
6635 /* validate file can be read through own symlink */
6636 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6638 die("failure: openat");
6641 /* validate file can be read through root symlink */
6642 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6644 die("failure: openat");
6647 /* validate file can't be read through other users symlink */
6648 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6650 die("failure: openat");
6651 if (errno != EACCES)
6652 die("failure: errno");
6656 if (wait_for_pid(pid)) {
6657 log_stderr("failure: wait_for_pid");
6663 log_stderr("failure: fork");
6667 if (!caps_supported()) {
6668 log_debug("skip: capability library not installed");
6672 if (!switch_userns(attr.userns_fd, 2000, 2000, true))
6673 die("failure: switch_userns");
6675 /* validate file can be directly read */
6676 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6678 die("failure: openat");
6681 /* validate file can be read through own symlink */
6682 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6684 die("failure: openat");
6687 /* validate file can be read through root symlink */
6688 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6690 die("failure: openat");
6693 /* validate file can't be read through other users symlink */
6694 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6696 die("failure: openat");
6697 if (errno != EACCES)
6698 die("failure: errno");
6702 if (wait_for_pid(pid)) {
6703 log_stderr("failure: wait_for_pid");
6708 log_debug("Ran test");
6711 safe_close(open_tree_fd);
6712 safe_close(attr.userns_fd);
6717 static int acls(void)
6720 int dir1_fd = -EBADF, open_tree_fd = -EBADF;
6721 struct mount_attr attr = {
6722 .attr_set = MOUNT_ATTR_IDMAP,
6726 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
6727 log_stderr("failure: mkdirat");
6730 if (fchmodat(t_dir1_fd, DIR1, 0777, 0)) {
6731 log_stderr("failure: fchmodat");
6735 if (mkdirat(t_dir1_fd, DIR2, 0777)) {
6736 log_stderr("failure: mkdirat");
6739 if (fchmodat(t_dir1_fd, DIR2, 0777, 0)) {
6740 log_stderr("failure: fchmodat");
6744 /* Changing mount properties on a detached mount. */
6745 attr.userns_fd = get_userns_fd(100010, 100020, 5);
6746 if (attr.userns_fd < 0) {
6747 log_stderr("failure: get_userns_fd");
6751 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
6753 AT_SYMLINK_NOFOLLOW |
6756 if (open_tree_fd < 0) {
6757 log_stderr("failure: sys_open_tree");
6761 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6762 log_stderr("failure: sys_mount_setattr");
6766 if (sys_move_mount(open_tree_fd, "", t_dir1_fd, DIR2, MOVE_MOUNT_F_EMPTY_PATH)) {
6767 log_stderr("failure: sys_move_mount");
6771 dir1_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6773 log_stderr("failure: openat");
6777 if (mkdirat(dir1_fd, DIR3, 0000)) {
6778 log_stderr("failure: mkdirat");
6781 if (fchown(dir1_fd, 100010, 100010)) {
6782 log_stderr("failure: fchown");
6785 if (fchmod(dir1_fd, 0777)) {
6786 log_stderr("failure: fchmod");
6790 snprintf(t_buf, sizeof(t_buf), "setfacl -m u:100010:rwx %s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6791 if (system(t_buf)) {
6792 log_stderr("failure: system");
6796 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100010:rwx", t_mountpoint, T_DIR1, DIR1, DIR3);
6797 if (system(t_buf)) {
6798 log_stderr("failure: system");
6802 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100020:rwx", t_mountpoint, T_DIR1, DIR2, DIR3);
6803 if (system(t_buf)) {
6804 log_stderr("failure: system");
6810 log_stderr("failure: fork");
6814 if (!caps_supported()) {
6815 log_debug("skip: capability library not installed");
6819 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6820 die("failure: switch_userns");
6822 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6823 t_mountpoint, T_DIR1, DIR1, DIR3, 4294967295LU);
6825 die("failure: system");
6829 if (wait_for_pid(pid)) {
6830 log_stderr("failure: wait_for_pid");
6836 log_stderr("failure: fork");
6840 if (!caps_supported()) {
6841 log_debug("skip: capability library not installed");
6845 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6846 die("failure: switch_userns");
6848 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6849 t_mountpoint, T_DIR1, DIR2, DIR3, 100010LU);
6851 die("failure: system");
6855 if (wait_for_pid(pid)) {
6856 log_stderr("failure: wait_for_pid");
6860 /* Now, dir is owned by someone else in the user namespace, but we can
6861 * still read it because of acls.
6863 if (fchown(dir1_fd, 100012, 100012)) {
6864 log_stderr("failure: fchown");
6870 log_stderr("failure: fork");
6876 if (!caps_supported()) {
6877 log_debug("skip: capability library not installed");
6881 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6882 die("failure: switch_userns");
6884 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6886 die("failure: openat");
6890 if (wait_for_pid(pid)) {
6891 log_stderr("failure: wait_for_pid");
6895 /* if we delete the acls, the ls should fail because it's 700. */
6896 snprintf(t_buf, sizeof(t_buf), "%s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6897 if (removexattr(t_buf, "system.posix_acl_access")) {
6898 log_stderr("failure: removexattr");
6904 log_stderr("failure: fork");
6910 if (!caps_supported()) {
6911 log_debug("skip: capability library not installed");
6915 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6916 die("failure: switch_userns");
6918 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6920 die("failure: openat");
6924 if (wait_for_pid(pid)) {
6925 log_stderr("failure: wait_for_pid");
6929 snprintf(t_buf, sizeof(t_buf), "%s/" T_DIR1 "/" DIR2, t_mountpoint);
6930 sys_umount2(t_buf, MNT_DETACH);
6933 log_debug("Ran test");
6935 safe_close(attr.userns_fd);
6936 safe_close(dir1_fd);
6937 safe_close(open_tree_fd);
6942 #ifdef HAVE_LIBURING_H
6943 static int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, int cred_id,
6944 bool with_link, int *ret_cqe)
6946 struct io_uring_cqe *cqe;
6947 struct io_uring_sqe *sqe;
6948 int ret, i, to_submit = 1;
6951 sqe = io_uring_get_sqe(ring);
6953 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6954 io_uring_prep_nop(sqe);
6955 sqe->flags |= IOSQE_IO_LINK;
6960 sqe = io_uring_get_sqe(ring);
6962 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6963 io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0);
6967 sqe->personality = cred_id;
6969 ret = io_uring_submit(ring);
6970 if (ret != to_submit) {
6971 log_stderr("failure: io_uring_submit");
6975 for (i = 0; i < to_submit; i++) {
6976 ret = io_uring_wait_cqe(ring, &cqe);
6978 log_stderr("failure: io_uring_wait_cqe");
6984 * Make sure caller can identify that this is a proper io_uring
6985 * failure and not some earlier error.
6989 io_uring_cqe_seen(ring, cqe);
6991 log_debug("Ran test");
6996 static int io_uring(void)
6999 int file1_fd = -EBADF;
7000 struct io_uring *ring;
7001 int cred_id, ret, ret_cqe;
7004 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7005 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7007 return log_errno(-1, "failure: io_uring_queue_init");
7009 ret = io_uring_queue_init(8, ring, 0);
7011 log_stderr("failure: io_uring_queue_init");
7015 ret = io_uring_register_personality(ring);
7018 goto out_unmap; /* personalities not supported */
7022 /* create file only owner can open */
7023 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7025 log_stderr("failure: openat");
7028 if (fchown(file1_fd, 0, 0)) {
7029 log_stderr("failure: fchown");
7032 if (fchmod(file1_fd, 0600)) {
7033 log_stderr("failure: fchmod");
7036 safe_close(file1_fd);
7040 log_stderr("failure: fork");
7044 /* Verify we can open it with our current credentials. */
7045 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7048 die("failure: io_uring_open_file");
7052 if (wait_for_pid(pid)) {
7053 log_stderr("failure: wait_for_pid");
7059 log_stderr("failure: fork");
7063 if (!switch_ids(1000, 1000))
7064 die("failure: switch_ids");
7066 /* Verify we can't open it with our current credentials. */
7068 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7069 -1, false, &ret_cqe);
7071 die("failure: io_uring_open_file");
7073 die("failure: non-open() related io_uring_open_file failure %d", ret_cqe);
7074 if (ret_cqe != -EACCES)
7075 die("failure: errno(%d)", abs(ret_cqe));
7079 if (wait_for_pid(pid)) {
7080 log_stderr("failure: wait_for_pid");
7086 log_stderr("failure: fork");
7090 if (!switch_ids(1000, 1000))
7091 die("failure: switch_ids");
7093 /* Verify we can open it with the registered credentials. */
7094 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7095 cred_id, false, NULL);
7097 die("failure: io_uring_open_file");
7099 /* Verify we can open it with the registered credentials and as
7102 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7103 cred_id, true, NULL);
7105 die("failure: io_uring_open_file");
7109 if (wait_for_pid(pid)) {
7110 log_stderr("failure: wait_for_pid");
7115 log_debug("Ran test");
7117 ret = io_uring_unregister_personality(ring, cred_id);
7119 log_stderr("failure: io_uring_unregister_personality");
7122 munmap(ring, sizeof(struct io_uring));
7124 safe_close(file1_fd);
7129 static int io_uring_userns(void)
7132 int file1_fd = -EBADF, userns_fd = -EBADF;
7133 struct io_uring *ring;
7134 int cred_id, ret, ret_cqe;
7137 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7138 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7140 return log_errno(-1, "failure: io_uring_queue_init");
7142 ret = io_uring_queue_init(8, ring, 0);
7144 log_stderr("failure: io_uring_queue_init");
7148 ret = io_uring_register_personality(ring);
7151 goto out_unmap; /* personalities not supported */
7155 /* create file only owner can open */
7156 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7158 log_stderr("failure: openat");
7161 if (fchown(file1_fd, 0, 0)) {
7162 log_stderr("failure: fchown");
7165 if (fchmod(file1_fd, 0600)) {
7166 log_stderr("failure: fchmod");
7169 safe_close(file1_fd);
7171 userns_fd = get_userns_fd(0, 10000, 10000);
7172 if (userns_fd < 0) {
7173 log_stderr("failure: get_userns_fd");
7179 log_stderr("failure: fork");
7183 /* Verify we can open it with our current credentials. */
7184 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7187 die("failure: io_uring_open_file");
7191 if (wait_for_pid(pid)) {
7192 log_stderr("failure: wait_for_pid");
7198 log_stderr("failure: fork");
7202 if (!switch_userns(userns_fd, 0, 0, false))
7203 die("failure: switch_userns");
7205 /* Verify we can't open it with our current credentials. */
7207 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7208 -1, false, &ret_cqe);
7210 die("failure: io_uring_open_file");
7212 die("failure: non-open() related io_uring_open_file failure");
7213 if (ret_cqe != -EACCES)
7214 die("failure: errno(%d)", abs(ret_cqe));
7218 if (wait_for_pid(pid)) {
7219 log_stderr("failure: wait_for_pid");
7225 log_stderr("failure: fork");
7229 if (!switch_userns(userns_fd, 0, 0, false))
7230 die("failure: switch_userns");
7232 /* Verify we can open it with the registered credentials. */
7233 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7234 cred_id, false, NULL);
7236 die("failure: io_uring_open_file");
7238 /* Verify we can open it with the registered credentials and as
7241 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7242 cred_id, true, NULL);
7244 die("failure: io_uring_open_file");
7248 if (wait_for_pid(pid)) {
7249 log_stderr("failure: wait_for_pid");
7254 log_debug("Ran test");
7256 ret = io_uring_unregister_personality(ring, cred_id);
7258 log_stderr("failure: io_uring_unregister_personality");
7261 munmap(ring, sizeof(struct io_uring));
7263 safe_close(file1_fd);
7264 safe_close(userns_fd);
7269 static int io_uring_idmapped(void)
7272 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7273 struct io_uring *ring;
7274 struct mount_attr attr = {
7275 .attr_set = MOUNT_ATTR_IDMAP,
7280 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7281 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7283 return log_errno(-1, "failure: io_uring_queue_init");
7285 ret = io_uring_queue_init(8, ring, 0);
7287 log_stderr("failure: io_uring_queue_init");
7291 ret = io_uring_register_personality(ring);
7294 goto out_unmap; /* personalities not supported */
7298 /* create file only owner can open */
7299 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7301 log_stderr("failure: openat");
7304 if (fchown(file1_fd, 0, 0)) {
7305 log_stderr("failure: fchown");
7308 if (fchmod(file1_fd, 0600)) {
7309 log_stderr("failure: fchmod");
7312 safe_close(file1_fd);
7314 /* Changing mount properties on a detached mount. */
7315 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7316 if (attr.userns_fd < 0)
7317 return log_errno(-1, "failure: create user namespace");
7319 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7322 AT_SYMLINK_NOFOLLOW |
7325 if (open_tree_fd < 0)
7326 return log_errno(-1, "failure: create detached mount");
7328 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7329 return log_errno(-1, "failure: set mount attributes");
7333 log_stderr("failure: fork");
7337 if (!switch_ids(10000, 10000))
7338 die("failure: switch_ids");
7340 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7343 die("failure: io_uring_open_file");
7347 if (wait_for_pid(pid)) {
7348 log_stderr("failure: wait_for_pid");
7354 log_stderr("failure: fork");
7358 if (!switch_ids(10001, 10001))
7359 die("failure: switch_ids");
7361 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7362 cred_id, false, NULL);
7364 die("failure: io_uring_open_file");
7366 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7367 cred_id, true, NULL);
7369 die("failure: io_uring_open_file");
7373 if (wait_for_pid(pid)) {
7374 log_stderr("failure: wait_for_pid");
7379 log_debug("Ran test");
7381 ret = io_uring_unregister_personality(ring, cred_id);
7383 log_stderr("failure: io_uring_unregister_personality");
7386 munmap(ring, sizeof(struct io_uring));
7388 safe_close(attr.userns_fd);
7389 safe_close(file1_fd);
7390 safe_close(open_tree_fd);
7396 * Create an idmapped mount where the we leave the owner of the file unmapped.
7397 * In no circumstances, even with recorded credentials can it be allowed to
7400 static int io_uring_idmapped_unmapped(void)
7403 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7404 struct io_uring *ring;
7405 struct mount_attr attr = {
7406 .attr_set = MOUNT_ATTR_IDMAP,
7408 int cred_id, ret, ret_cqe;
7411 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7412 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7414 return log_errno(-1, "failure: io_uring_queue_init");
7416 ret = io_uring_queue_init(8, ring, 0);
7418 log_stderr("failure: io_uring_queue_init");
7422 ret = io_uring_register_personality(ring);
7425 goto out_unmap; /* personalities not supported */
7429 /* create file only owner can open */
7430 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7432 log_stderr("failure: openat");
7435 if (fchown(file1_fd, 0, 0)) {
7436 log_stderr("failure: fchown");
7439 if (fchmod(file1_fd, 0600)) {
7440 log_stderr("failure: fchmod");
7443 safe_close(file1_fd);
7445 /* Changing mount properties on a detached mount. */
7446 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7447 if (attr.userns_fd < 0)
7448 return log_errno(-1, "failure: create user namespace");
7450 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7453 AT_SYMLINK_NOFOLLOW |
7456 if (open_tree_fd < 0)
7457 return log_errno(-1, "failure: create detached mount");
7459 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7460 return log_errno(-1, "failure: set mount attributes");
7464 log_stderr("failure: fork");
7468 if (!switch_ids(10000, 10000))
7469 die("failure: switch_ids");
7472 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7473 cred_id, false, &ret_cqe);
7475 die("failure: io_uring_open_file");
7477 die("failure: non-open() related io_uring_open_file failure");
7478 if (ret_cqe != -EACCES)
7479 die("failure: errno(%d)", abs(ret_cqe));
7482 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7483 cred_id, true, &ret_cqe);
7485 die("failure: io_uring_open_file");
7487 die("failure: non-open() related io_uring_open_file failure");
7488 if (ret_cqe != -EACCES)
7489 die("failure: errno(%d)", abs(ret_cqe));
7493 if (wait_for_pid(pid)) {
7494 log_stderr("failure: wait_for_pid");
7499 log_debug("Ran test");
7501 ret = io_uring_unregister_personality(ring, cred_id);
7503 log_stderr("failure: io_uring_unregister_personality");
7506 munmap(ring, sizeof(struct io_uring));
7508 safe_close(attr.userns_fd);
7509 safe_close(file1_fd);
7510 safe_close(open_tree_fd);
7515 static int io_uring_idmapped_userns(void)
7518 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7519 struct io_uring *ring;
7520 struct mount_attr attr = {
7521 .attr_set = MOUNT_ATTR_IDMAP,
7523 int cred_id, ret, ret_cqe;
7526 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7527 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7529 return log_errno(-1, "failure: io_uring_queue_init");
7531 ret = io_uring_queue_init(8, ring, 0);
7533 log_stderr("failure: io_uring_queue_init");
7537 ret = io_uring_register_personality(ring);
7540 goto out_unmap; /* personalities not supported */
7544 /* create file only owner can open */
7545 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7547 log_stderr("failure: openat");
7550 if (fchown(file1_fd, 0, 0)) {
7551 log_stderr("failure: fchown");
7554 if (fchmod(file1_fd, 0600)) {
7555 log_stderr("failure: fchmod");
7558 safe_close(file1_fd);
7560 /* Changing mount properties on a detached mount. */
7561 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7562 if (attr.userns_fd < 0)
7563 return log_errno(-1, "failure: create user namespace");
7565 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7568 AT_SYMLINK_NOFOLLOW |
7571 if (open_tree_fd < 0)
7572 return log_errno(-1, "failure: create detached mount");
7574 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7575 return log_errno(-1, "failure: set mount attributes");
7579 log_stderr("failure: fork");
7583 if (!switch_userns(attr.userns_fd, 0, 0, false))
7584 die("failure: switch_userns");
7586 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7589 die("failure: io_uring_open_file");
7593 if (wait_for_pid(pid)) {
7594 log_stderr("failure: wait_for_pid");
7600 log_stderr("failure: fork");
7604 if (!caps_supported()) {
7605 log_debug("skip: capability library not installed");
7609 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
7610 die("failure: switch_userns");
7613 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7614 -1, false, &ret_cqe);
7616 die("failure: io_uring_open_file");
7618 die("failure: non-open() related io_uring_open_file failure");
7619 if (ret_cqe != -EACCES)
7620 die("failure: errno(%d)", abs(ret_cqe));
7623 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7624 -1, true, &ret_cqe);
7626 die("failure: io_uring_open_file");
7628 die("failure: non-open() related io_uring_open_file failure");
7629 if (ret_cqe != -EACCES)
7630 die("failure: errno(%d)", abs(ret_cqe));
7633 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7634 -1, false, &ret_cqe);
7636 die("failure: io_uring_open_file");
7638 die("failure: non-open() related io_uring_open_file failure");
7639 if (ret_cqe != -EACCES)
7640 die("failure: errno(%d)", abs(ret_cqe));
7643 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7644 -1, true, &ret_cqe);
7646 die("failure: io_uring_open_file");
7648 die("failure: non-open() related io_uring_open_file failure");
7649 if (ret_cqe != -EACCES)
7650 die("failure: errno(%d)", abs(ret_cqe));
7652 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7653 cred_id, false, NULL);
7655 die("failure: io_uring_open_file");
7657 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7658 cred_id, true, NULL);
7660 die("failure: io_uring_open_file");
7664 if (wait_for_pid(pid)) {
7665 log_stderr("failure: wait_for_pid");
7670 log_debug("Ran test");
7672 ret = io_uring_unregister_personality(ring, cred_id);
7674 log_stderr("failure: io_uring_unregister_personality");
7677 munmap(ring, sizeof(struct io_uring));
7679 safe_close(attr.userns_fd);
7680 safe_close(file1_fd);
7681 safe_close(open_tree_fd);
7686 static int io_uring_idmapped_unmapped_userns(void)
7689 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7690 struct io_uring *ring;
7691 struct mount_attr attr = {
7692 .attr_set = MOUNT_ATTR_IDMAP,
7694 int cred_id, ret, ret_cqe;
7697 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7698 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7700 return log_errno(-1, "failure: io_uring_queue_init");
7702 ret = io_uring_queue_init(8, ring, 0);
7704 log_stderr("failure: io_uring_queue_init");
7708 ret = io_uring_register_personality(ring);
7711 goto out_unmap; /* personalities not supported */
7715 /* create file only owner can open */
7716 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7718 log_stderr("failure: openat");
7721 if (fchown(file1_fd, 0, 0)) {
7722 log_stderr("failure: fchown");
7725 if (fchmod(file1_fd, 0600)) {
7726 log_stderr("failure: fchmod");
7729 safe_close(file1_fd);
7731 /* Changing mount properties on a detached mount. */
7732 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7733 if (attr.userns_fd < 0)
7734 return log_errno(-1, "failure: create user namespace");
7736 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7739 AT_SYMLINK_NOFOLLOW |
7742 if (open_tree_fd < 0)
7743 return log_errno(-1, "failure: create detached mount");
7745 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7746 return log_errno(-1, "failure: set mount attributes");
7750 log_stderr("failure: fork");
7754 if (!caps_supported()) {
7755 log_debug("skip: capability library not installed");
7759 if (!switch_userns(attr.userns_fd, 10000, 10000, true))
7760 die("failure: switch_ids");
7763 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7764 cred_id, false, &ret_cqe);
7766 die("failure: io_uring_open_file");
7768 die("failure: non-open() related io_uring_open_file failure");
7769 if (ret_cqe != -EACCES)
7770 die("failure: errno(%d)", abs(ret_cqe));
7773 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7774 cred_id, true, &ret_cqe);
7776 die("failure: io_uring_open_file");
7778 die("failure: non-open() related io_uring_open_file failure");
7779 if (ret_cqe != -EACCES)
7780 die("failure: errno(%d)", abs(ret_cqe));
7784 if (wait_for_pid(pid)) {
7785 log_stderr("failure: wait_for_pid");
7790 log_debug("Ran test");
7792 ret = io_uring_unregister_personality(ring, cred_id);
7794 log_stderr("failure: io_uring_unregister_personality");
7797 munmap(ring, sizeof(struct io_uring));
7799 safe_close(attr.userns_fd);
7800 safe_close(file1_fd);
7801 safe_close(open_tree_fd);
7805 #endif /* HAVE_LIBURING_H */
7807 /* The following tests are concerned with setgid inheritance. These can be
7808 * filesystem type specific. For xfs, if a new file or directory is created
7809 * within a setgid directory and irix_sgid_inhiert is set then inherit the
7810 * setgid bit if the caller is in the group of the directory.
7812 static int setgid_create(void)
7815 int file1_fd = -EBADF;
7818 if (!caps_supported())
7821 if (fchmod(t_dir1_fd, S_IRUSR |
7831 log_stderr("failure: fchmod");
7835 /* Verify that the setgid bit got raised. */
7836 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7837 log_stderr("failure: is_setgid");
7843 log_stderr("failure: fork");
7847 /* create regular file via open() */
7848 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7850 die("failure: create");
7852 /* We're capable_wrt_inode_uidgid() and also our fsgid matches
7853 * the directories gid.
7855 if (!is_setgid(t_dir1_fd, FILE1, 0))
7856 die("failure: is_setgid");
7858 /* create directory */
7859 if (mkdirat(t_dir1_fd, DIR1, 0000))
7860 die("failure: create");
7862 /* Directories always inherit the setgid bit. */
7863 if (!is_setgid(t_dir1_fd, DIR1, 0))
7864 die("failure: is_setgid");
7866 if (unlinkat(t_dir1_fd, FILE1, 0))
7867 die("failure: delete");
7869 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7870 die("failure: delete");
7874 if (wait_for_pid(pid))
7879 log_stderr("failure: fork");
7883 if (!switch_ids(0, 10000))
7884 die("failure: switch_ids");
7887 die("failure: caps_down");
7889 /* create regular file via open() */
7890 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7892 die("failure: create");
7894 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7895 * bit needs to be stripped.
7897 if (is_setgid(t_dir1_fd, FILE1, 0))
7898 die("failure: is_setgid");
7900 /* create directory */
7901 if (mkdirat(t_dir1_fd, DIR1, 0000))
7902 die("failure: create");
7904 if (xfs_irix_sgid_inherit_enabled()) {
7905 /* We're not in_group_p(). */
7906 if (is_setgid(t_dir1_fd, DIR1, 0))
7907 die("failure: is_setgid");
7909 /* Directories always inherit the setgid bit. */
7910 if (!is_setgid(t_dir1_fd, DIR1, 0))
7911 die("failure: is_setgid");
7916 if (wait_for_pid(pid))
7920 log_debug("Ran test");
7922 safe_close(file1_fd);
7927 static int setgid_create_idmapped(void)
7930 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7931 struct mount_attr attr = {
7932 .attr_set = MOUNT_ATTR_IDMAP,
7936 if (!caps_supported())
7939 if (fchmod(t_dir1_fd, S_IRUSR |
7949 log_stderr("failure: fchmod");
7953 /* Verify that the sid bits got raised. */
7954 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7955 log_stderr("failure: is_setgid");
7959 /* Changing mount properties on a detached mount. */
7960 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7961 if (attr.userns_fd < 0) {
7962 log_stderr("failure: get_userns_fd");
7966 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7969 AT_SYMLINK_NOFOLLOW |
7972 if (open_tree_fd < 0) {
7973 log_stderr("failure: sys_open_tree");
7977 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7978 log_stderr("failure: sys_mount_setattr");
7984 log_stderr("failure: fork");
7988 if (!switch_ids(10000, 11000))
7989 die("failure: switch fsids");
7991 /* create regular file via open() */
7992 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7994 die("failure: create");
7996 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7997 * bit needs to be stripped.
7999 if (is_setgid(open_tree_fd, FILE1, 0))
8000 die("failure: is_setgid");
8002 /* create directory */
8003 if (mkdirat(open_tree_fd, DIR1, 0000))
8004 die("failure: create");
8006 if (xfs_irix_sgid_inherit_enabled()) {
8007 /* We're not in_group_p(). */
8008 if (is_setgid(open_tree_fd, DIR1, 0))
8009 die("failure: is_setgid");
8011 /* Directories always inherit the setgid bit. */
8012 if (!is_setgid(open_tree_fd, DIR1, 0))
8013 die("failure: is_setgid");
8018 if (wait_for_pid(pid))
8022 log_debug("Ran test");
8024 safe_close(attr.userns_fd);
8025 safe_close(file1_fd);
8026 safe_close(open_tree_fd);
8031 static int setgid_create_idmapped_in_userns(void)
8034 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8035 struct mount_attr attr = {
8036 .attr_set = MOUNT_ATTR_IDMAP,
8040 if (!caps_supported())
8043 if (fchmod(t_dir1_fd, S_IRUSR |
8053 log_stderr("failure: fchmod");
8057 /* Verify that the sid bits got raised. */
8058 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
8059 log_stderr("failure: is_setgid");
8063 /* Changing mount properties on a detached mount. */
8064 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8065 if (attr.userns_fd < 0) {
8066 log_stderr("failure: get_userns_fd");
8070 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8073 AT_SYMLINK_NOFOLLOW |
8076 if (open_tree_fd < 0) {
8077 log_stderr("failure: sys_open_tree");
8081 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8082 log_stderr("failure: sys_mount_setattr");
8088 log_stderr("failure: fork");
8092 if (!switch_userns(attr.userns_fd, 0, 0, false))
8093 die("failure: switch_userns");
8095 /* create regular file via open() */
8096 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8098 die("failure: create");
8100 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
8101 * bit needs to be set.
8103 if (!is_setgid(open_tree_fd, FILE1, 0))
8104 die("failure: is_setgid");
8106 /* create directory */
8107 if (mkdirat(open_tree_fd, DIR1, 0000))
8108 die("failure: create");
8110 /* Directories always inherit the setgid bit. */
8111 if (!is_setgid(open_tree_fd, DIR1, 0))
8112 die("failure: is_setgid");
8114 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8115 die("failure: check ownership");
8117 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8118 die("failure: check ownership");
8120 if (unlinkat(open_tree_fd, FILE1, 0))
8121 die("failure: delete");
8123 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8124 die("failure: delete");
8128 if (wait_for_pid(pid))
8131 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8132 log_stderr("failure: fchownat");
8138 log_stderr("failure: fork");
8142 if (!caps_supported()) {
8143 log_debug("skip: capability library not installed");
8147 if (!switch_userns(attr.userns_fd, 0, 0, true))
8148 die("failure: switch_userns");
8150 /* create regular file via open() */
8151 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8153 die("failure: create");
8155 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8156 * bit needs to be stripped.
8158 if (is_setgid(open_tree_fd, FILE1, 0))
8159 die("failure: is_setgid");
8161 /* create directory */
8162 if (mkdirat(open_tree_fd, DIR1, 0000))
8163 die("failure: create");
8165 if (xfs_irix_sgid_inherit_enabled()) {
8166 /* We're not in_group_p(). */
8167 if (is_setgid(open_tree_fd, DIR1, 0))
8168 die("failure: is_setgid");
8170 /* Directories always inherit the setgid bit. */
8171 if (!is_setgid(open_tree_fd, DIR1, 0))
8172 die("failure: is_setgid");
8175 /* Files and directories created in setgid directories inherit
8176 * the i_gid of the parent directory.
8178 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8179 die("failure: check ownership");
8181 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8182 die("failure: check ownership");
8184 if (unlinkat(open_tree_fd, FILE1, 0))
8185 die("failure: delete");
8187 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8188 die("failure: delete");
8192 if (wait_for_pid(pid))
8195 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8196 log_stderr("failure: fchownat");
8200 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8201 log_stderr("failure: fchownat");
8207 log_stderr("failure: fork");
8211 if (!caps_supported()) {
8212 log_debug("skip: capability library not installed");
8216 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8217 die("failure: switch_userns");
8219 /* create regular file via open() */
8220 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8222 die("failure: create");
8224 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8225 * bit needs to be stripped.
8227 if (is_setgid(open_tree_fd, FILE1, 0))
8228 die("failure: is_setgid");
8230 /* create directory */
8231 if (mkdirat(open_tree_fd, DIR1, 0000))
8232 die("failure: create");
8234 /* Directories always inherit the setgid bit. */
8235 if (xfs_irix_sgid_inherit_enabled()) {
8236 /* We're not in_group_p(). */
8237 if (is_setgid(open_tree_fd, DIR1, 0))
8238 die("failure: is_setgid");
8240 /* Directories always inherit the setgid bit. */
8241 if (!is_setgid(open_tree_fd, DIR1, 0))
8242 die("failure: is_setgid");
8245 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8246 die("failure: check ownership");
8248 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8249 die("failure: check ownership");
8253 if (wait_for_pid(pid))
8257 log_debug("Ran test");
8259 safe_close(attr.userns_fd);
8260 safe_close(file1_fd);
8261 safe_close(open_tree_fd);
8266 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8267 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8269 static void *idmapped_mount_create_cb(void *data)
8271 int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8272 struct mount_attr attr = {
8273 .attr_set = MOUNT_ATTR_IDMAP,
8276 /* Changing mount properties on a detached mount. */
8277 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8278 if (attr.userns_fd < 0) {
8279 log_stderr("failure: get_userns_fd");
8283 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8284 log_stderr("failure: sys_mount_setattr");
8288 fret = EXIT_SUCCESS;
8291 safe_close(attr.userns_fd);
8292 pthread_exit(INT_TO_PTR(fret));
8295 /* This tries to verify that we never see an inconistent ownership on-disk and
8296 * can't write invalid ids to disk. To do this we create a race between
8297 * idmapping a mount and creating files on it.
8298 * Note, while it is perfectly fine to see overflowuid and overflowgid as owner
8299 * if we create files through the open_tree_fd before the mount is idmapped but
8300 * look at the files after the mount has been idmapped in this test it can never
8301 * be the case that we see overflowuid and overflowgid when we access the file
8302 * through a non-idmapped mount (in the initial user namespace).
8304 static void *idmapped_mount_operations_cb(void *data)
8306 int file1_fd = -EBADF, file2_fd = -EBADF, dir1_fd = -EBADF,
8307 dir1_fd2 = -EBADF, fret = EXIT_FAILURE,
8308 open_tree_fd = PTR_TO_INT(data);
8310 if (!switch_fsids(10000, 10000)) {
8311 log_stderr("failure: switch fsids");
8315 file1_fd = openat(open_tree_fd, FILE1,
8316 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8318 log_stderr("failure: openat");
8322 file2_fd = openat(open_tree_fd, FILE2,
8323 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8325 log_stderr("failure: openat");
8329 if (mkdirat(open_tree_fd, DIR1, 0777)) {
8330 log_stderr("failure: mkdirat");
8334 dir1_fd = openat(open_tree_fd, DIR1,
8335 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8337 log_stderr("failure: openat");
8341 if (!__expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0, false) &&
8342 !__expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000, false) &&
8343 !__expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid, false)) {
8344 log_stderr("failure: expected_uid_gid");
8348 if (!__expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0, false) &&
8349 !__expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000, false) &&
8350 !__expected_uid_gid(open_tree_fd, FILE2, 0, t_overflowuid, t_overflowgid, false)) {
8351 log_stderr("failure: expected_uid_gid");
8355 if (!__expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0, false) &&
8356 !__expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000, false) &&
8357 !__expected_uid_gid(open_tree_fd, DIR1, 0, t_overflowuid, t_overflowgid, false)) {
8358 log_stderr("failure: expected_uid_gid");
8362 if (!__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 0, 0, false) &&
8363 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 10000, 10000, false) &&
8364 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, t_overflowuid, t_overflowgid, false)) {
8365 log_stderr("failure: expected_uid_gid");
8369 dir1_fd2 = openat(t_dir1_fd, DIR1,
8370 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8372 log_stderr("failure: openat");
8376 if (!__expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0, false) &&
8377 !__expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000, false)) {
8378 log_stderr("failure: expected_uid_gid");
8382 if (!__expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0, false) &&
8383 !__expected_uid_gid(t_dir1_fd, FILE2, 0, 10000, 10000, false)) {
8384 log_stderr("failure: expected_uid_gid");
8388 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8389 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8390 log_stderr("failure: expected_uid_gid");
8394 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8395 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8396 log_stderr("failure: expected_uid_gid");
8400 if (!__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 0, 0, false) &&
8401 !__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 10000, 10000, false)) {
8402 log_stderr("failure: expected_uid_gid");
8406 fret = EXIT_SUCCESS;
8409 safe_close(file1_fd);
8410 safe_close(file2_fd);
8411 safe_close(dir1_fd);
8412 safe_close(dir1_fd2);
8414 pthread_exit(INT_TO_PTR(fret));
8417 static int threaded_idmapped_mount_interactions(void)
8422 pthread_attr_t thread_attr;
8423 pthread_t threads[2];
8425 pthread_attr_init(&thread_attr);
8427 for (i = 0; i < 1000; i++) {
8428 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8432 log_stderr("failure: fork");
8436 int open_tree_fd = -EBADF;
8438 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8441 AT_SYMLINK_NOFOLLOW |
8444 if (open_tree_fd < 0)
8445 die("failure: sys_open_tree");
8447 if (pthread_create(&threads[0], &thread_attr,
8448 idmapped_mount_create_cb,
8449 INT_TO_PTR(open_tree_fd)))
8450 die("failure: pthread_create");
8452 if (pthread_create(&threads[1], &thread_attr,
8453 idmapped_mount_operations_cb,
8454 INT_TO_PTR(open_tree_fd)))
8455 die("failure: pthread_create");
8457 ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8458 ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8462 die("failure: pthread_join");
8467 die("failure: pthread_join");
8477 if (wait_for_pid(pid)) {
8478 log_stderr("failure: iteration %d", i);
8482 rm_r(t_dir1_fd, ".");
8487 log_debug("Ran test");
8493 static int setattr_truncate(void)
8496 int file1_fd = -EBADF;
8498 /* create regular file via open() */
8499 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8501 log_stderr("failure: create");
8505 if (ftruncate(file1_fd, 10000)) {
8506 log_stderr("failure: ftruncate");
8510 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8511 log_stderr("failure: check ownership");
8515 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8516 log_stderr("failure: expected_file_size");
8520 if (ftruncate(file1_fd, 0)) {
8521 log_stderr("failure: ftruncate");
8525 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8526 log_stderr("failure: check ownership");
8530 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8531 log_stderr("failure: expected_file_size");
8535 if (unlinkat(t_dir1_fd, FILE1, 0)) {
8536 log_stderr("failure: remove");
8541 log_debug("Ran test");
8543 safe_close(file1_fd);
8548 static int setattr_truncate_idmapped(void)
8551 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8553 struct mount_attr attr = {
8554 .attr_set = MOUNT_ATTR_IDMAP,
8557 /* Changing mount properties on a detached mount. */
8558 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8559 if (attr.userns_fd < 0) {
8560 log_stderr("failure: get_userns_fd");
8564 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8567 AT_SYMLINK_NOFOLLOW |
8570 if (open_tree_fd < 0) {
8571 log_stderr("failure: sys_open_tree");
8575 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8576 log_stderr("failure: sys_mount_setattr");
8582 log_stderr("failure: fork");
8586 if (!switch_ids(10000, 10000))
8587 die("failure: switch_ids");
8589 /* create regular file via open() */
8590 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8592 die("failure: create");
8594 if (ftruncate(file1_fd, 10000))
8595 die("failure: ftruncate");
8597 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8598 die("failure: check ownership");
8600 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8601 die("failure: expected_file_size");
8603 if (ftruncate(file1_fd, 0))
8604 die("failure: ftruncate");
8606 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8607 die("failure: check ownership");
8609 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8610 die("failure: expected_file_size");
8614 if (wait_for_pid(pid))
8619 log_stderr("failure: fork");
8623 int file1_fd2 = -EBADF;
8625 /* create regular file via open() */
8626 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8628 die("failure: create");
8630 if (ftruncate(file1_fd2, 10000))
8631 die("failure: ftruncate");
8633 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8634 die("failure: check ownership");
8636 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8637 die("failure: expected_file_size");
8639 if (ftruncate(file1_fd2, 0))
8640 die("failure: ftruncate");
8642 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8643 die("failure: check ownership");
8645 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8646 die("failure: expected_file_size");
8650 if (wait_for_pid(pid))
8654 log_debug("Ran test");
8656 safe_close(file1_fd);
8657 safe_close(open_tree_fd);
8662 static int setattr_truncate_idmapped_in_userns(void)
8665 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8666 struct mount_attr attr = {
8667 .attr_set = MOUNT_ATTR_IDMAP,
8671 /* Changing mount properties on a detached mount. */
8672 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8673 if (attr.userns_fd < 0) {
8674 log_stderr("failure: get_userns_fd");
8678 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8681 AT_SYMLINK_NOFOLLOW |
8684 if (open_tree_fd < 0) {
8685 log_stderr("failure: sys_open_tree");
8689 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8690 log_stderr("failure: sys_mount_setattr");
8696 log_stderr("failure: fork");
8700 if (!switch_userns(attr.userns_fd, 0, 0, false))
8701 die("failure: switch_userns");
8703 /* create regular file via open() */
8704 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8706 die("failure: create");
8708 if (ftruncate(file1_fd, 10000))
8709 die("failure: ftruncate");
8711 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8712 die("failure: check ownership");
8714 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8715 die("failure: expected_file_size");
8717 if (ftruncate(file1_fd, 0))
8718 die("failure: ftruncate");
8720 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8721 die("failure: check ownership");
8723 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8724 die("failure: expected_file_size");
8726 if (unlinkat(open_tree_fd, FILE1, 0))
8727 die("failure: delete");
8731 if (wait_for_pid(pid))
8734 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8735 log_stderr("failure: fchownat");
8739 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8740 log_stderr("failure: fchownat");
8746 log_stderr("failure: fork");
8750 if (!caps_supported()) {
8751 log_debug("skip: capability library not installed");
8755 if (!switch_userns(attr.userns_fd, 0, 0, true))
8756 die("failure: switch_userns");
8758 /* create regular file via open() */
8759 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8761 die("failure: create");
8763 if (ftruncate(file1_fd, 10000))
8764 die("failure: ftruncate");
8766 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8767 die("failure: check ownership");
8769 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8770 die("failure: expected_file_size");
8772 if (ftruncate(file1_fd, 0))
8773 die("failure: ftruncate");
8775 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8776 die("failure: check ownership");
8778 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8779 die("failure: expected_file_size");
8781 if (unlinkat(open_tree_fd, FILE1, 0))
8782 die("failure: delete");
8786 if (wait_for_pid(pid))
8789 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8790 log_stderr("failure: fchownat");
8794 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8795 log_stderr("failure: fchownat");
8801 log_stderr("failure: fork");
8805 if (!caps_supported()) {
8806 log_debug("skip: capability library not installed");
8810 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8811 die("failure: switch_userns");
8813 /* create regular file via open() */
8814 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8816 die("failure: create");
8818 if (ftruncate(file1_fd, 10000))
8819 die("failure: ftruncate");
8821 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8822 die("failure: check ownership");
8824 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8825 die("failure: expected_file_size");
8827 if (ftruncate(file1_fd, 0))
8828 die("failure: ftruncate");
8830 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8831 die("failure: check ownership");
8833 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8834 die("failure: expected_file_size");
8836 if (unlinkat(open_tree_fd, FILE1, 0))
8837 die("failure: delete");
8841 if (wait_for_pid(pid))
8845 log_debug("Ran test");
8847 safe_close(attr.userns_fd);
8848 safe_close(file1_fd);
8849 safe_close(open_tree_fd);
8854 static int nested_userns(void)
8860 struct list *it, *next;
8861 struct userns_hierarchy hierarchy[] = {
8862 { .level = 1, .fd_userns = -EBADF, },
8863 { .level = 2, .fd_userns = -EBADF, },
8864 { .level = 3, .fd_userns = -EBADF, },
8865 { .level = 4, .fd_userns = -EBADF, },
8866 /* Dummy entry that marks the end. */
8867 { .level = MAX_USERNS_LEVEL, .fd_userns = -EBADF, },
8869 struct mount_attr attr_level1 = {
8870 .attr_set = MOUNT_ATTR_IDMAP,
8871 .userns_fd = -EBADF,
8873 struct mount_attr attr_level2 = {
8874 .attr_set = MOUNT_ATTR_IDMAP,
8875 .userns_fd = -EBADF,
8877 struct mount_attr attr_level3 = {
8878 .attr_set = MOUNT_ATTR_IDMAP,
8879 .userns_fd = -EBADF,
8881 struct mount_attr attr_level4 = {
8882 .attr_set = MOUNT_ATTR_IDMAP,
8883 .userns_fd = -EBADF,
8885 int fd_dir1 = -EBADF,
8886 fd_open_tree_level1 = -EBADF,
8887 fd_open_tree_level2 = -EBADF,
8888 fd_open_tree_level3 = -EBADF,
8889 fd_open_tree_level4 = -EBADF;
8890 const unsigned int id_file_range = 10000;
8892 list_init(&hierarchy[0].id_map);
8893 list_init(&hierarchy[1].id_map);
8894 list_init(&hierarchy[2].id_map);
8895 list_init(&hierarchy[3].id_map);
8898 * Give a large map to the outermost user namespace so we can create
8899 * comfortable nested maps.
8901 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_UID);
8903 log_stderr("failure: adding uidmap for userns at level 1");
8907 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_GID);
8909 log_stderr("failure: adding gidmap for userns at level 1");
8913 /* This is uid:0->2000000:100000000 in init userns. */
8914 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_UID);
8916 log_stderr("failure: adding uidmap for userns at level 2");
8920 /* This is gid:0->2000000:100000000 in init userns. */
8921 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_GID);
8923 log_stderr("failure: adding gidmap for userns at level 2");
8927 /* This is uid:0->3000000:999 in init userns. */
8928 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_UID);
8930 log_stderr("failure: adding uidmap for userns at level 3");
8934 /* This is gid:0->3000000:999 in the init userns. */
8935 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_GID);
8937 log_stderr("failure: adding gidmap for userns at level 3");
8941 /* id 999 will remain unmapped. */
8943 /* This is uid:1000->2001000:1 in init userns. */
8944 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_UID);
8946 log_stderr("failure: adding uidmap for userns at level 3");
8950 /* This is gid:1000->2001000:1 in init userns. */
8951 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_GID);
8953 log_stderr("failure: adding gidmap for userns at level 3");
8957 /* This is uid:1001->3001001:10000 in init userns. */
8958 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_UID);
8960 log_stderr("failure: adding uidmap for userns at level 3");
8964 /* This is gid:1001->3001001:10000 in init userns. */
8965 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_GID);
8967 log_stderr("failure: adding gidmap for userns at level 3");
8971 /* Don't write a mapping in the 4th userns. */
8972 list_empty(&hierarchy[4].id_map);
8974 /* Create the actual userns hierarchy. */
8975 ret = create_userns_hierarchy(hierarchy);
8977 log_stderr("failure: create userns hierarchy");
8981 attr_level1.userns_fd = hierarchy[0].fd_userns;
8982 attr_level2.userns_fd = hierarchy[1].fd_userns;
8983 attr_level3.userns_fd = hierarchy[2].fd_userns;
8984 attr_level4.userns_fd = hierarchy[3].fd_userns;
8987 * Create one directory where we create files for each uid/gid within
8990 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
8991 log_stderr("failure: mkdirat");
8995 fd_dir1 = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
8997 log_stderr("failure: openat");
9001 for (id = 0; id <= id_file_range; id++) {
9004 snprintf(file, sizeof(file), DIR1 "/" FILE1 "_%u", id);
9006 if (mknodat(t_dir1_fd, file, S_IFREG | 0644, 0)) {
9007 log_stderr("failure: create %s", file);
9011 if (fchownat(t_dir1_fd, file, id, id, AT_SYMLINK_NOFOLLOW)) {
9012 log_stderr("failure: fchownat %s", file);
9016 if (!expected_uid_gid(t_dir1_fd, file, 0, id, id)) {
9017 log_stderr("failure: check ownership %s", file);
9022 /* Create detached mounts for all the user namespaces. */
9023 fd_open_tree_level1 = sys_open_tree(t_dir1_fd, DIR1,
9025 AT_SYMLINK_NOFOLLOW |
9028 if (fd_open_tree_level1 < 0) {
9029 log_stderr("failure: sys_open_tree");
9033 fd_open_tree_level2 = sys_open_tree(t_dir1_fd, DIR1,
9035 AT_SYMLINK_NOFOLLOW |
9038 if (fd_open_tree_level2 < 0) {
9039 log_stderr("failure: sys_open_tree");
9043 fd_open_tree_level3 = sys_open_tree(t_dir1_fd, DIR1,
9045 AT_SYMLINK_NOFOLLOW |
9048 if (fd_open_tree_level3 < 0) {
9049 log_stderr("failure: sys_open_tree");
9053 fd_open_tree_level4 = sys_open_tree(t_dir1_fd, DIR1,
9055 AT_SYMLINK_NOFOLLOW |
9058 if (fd_open_tree_level4 < 0) {
9059 log_stderr("failure: sys_open_tree");
9063 /* Turn detached mounts into detached idmapped mounts. */
9064 if (sys_mount_setattr(fd_open_tree_level1, "", AT_EMPTY_PATH,
9065 &attr_level1, sizeof(attr_level1))) {
9066 log_stderr("failure: sys_mount_setattr");
9070 if (sys_mount_setattr(fd_open_tree_level2, "", AT_EMPTY_PATH,
9071 &attr_level2, sizeof(attr_level2))) {
9072 log_stderr("failure: sys_mount_setattr");
9076 if (sys_mount_setattr(fd_open_tree_level3, "", AT_EMPTY_PATH,
9077 &attr_level3, sizeof(attr_level3))) {
9078 log_stderr("failure: sys_mount_setattr");
9082 if (sys_mount_setattr(fd_open_tree_level4, "", AT_EMPTY_PATH,
9083 &attr_level4, sizeof(attr_level4))) {
9084 log_stderr("failure: sys_mount_setattr");
9088 /* Verify that ownership looks correct for callers in the init userns. */
9089 for (id = 0; id <= id_file_range; id++) {
9091 unsigned int id_level1, id_level2, id_level3;
9094 snprintf(file, sizeof(file), FILE1 "_%u", id);
9096 id_level1 = id + 1000000;
9097 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) {
9098 log_stderr("failure: check ownership %s", file);
9102 id_level2 = id + 2000000;
9103 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) {
9104 log_stderr("failure: check ownership %s", file);
9109 /* This id is unmapped. */
9110 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9111 } else if (id == 1000) {
9112 id_level3 = id + 2000000; /* We punched a hole in the map at 1000. */
9113 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9115 id_level3 = id + 3000000; /* Rest is business as usual. */
9116 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9119 log_stderr("failure: check ownership %s", file);
9123 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid)) {
9124 log_stderr("failure: check ownership %s", file);
9129 /* Verify that ownership looks correct for callers in the first userns. */
9132 log_stderr("failure: fork");
9136 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9137 die("failure: switch_userns");
9139 for (id = 0; id <= id_file_range; id++) {
9141 unsigned int id_level1, id_level2, id_level3;
9144 snprintf(file, sizeof(file), FILE1 "_%u", id);
9147 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9148 die("failure: check ownership %s", file);
9150 id_level2 = id + 1000000;
9151 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9152 die("failure: check ownership %s", file);
9155 /* This id is unmapped. */
9156 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9157 } else if (id == 1000) {
9158 id_level3 = id + 1000000; /* We punched a hole in the map at 1000. */
9159 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9161 id_level3 = id + 2000000; /* Rest is business as usual. */
9162 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9165 die("failure: check ownership %s", file);
9167 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9168 die("failure: check ownership %s", file);
9173 if (wait_for_pid(pid))
9176 /* Verify that ownership looks correct for callers in the second userns. */
9179 log_stderr("failure: fork");
9183 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9184 die("failure: switch_userns");
9186 for (id = 0; id <= id_file_range; id++) {
9188 unsigned int id_level2, id_level3;
9191 snprintf(file, sizeof(file), FILE1 "_%u", id);
9193 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9194 die("failure: check ownership %s", file);
9197 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9198 die("failure: check ownership %s", file);
9201 /* This id is unmapped. */
9202 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9203 } else if (id == 1000) {
9204 id_level3 = id; /* We punched a hole in the map at 1000. */
9205 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9207 id_level3 = id + 1000000; /* Rest is business as usual. */
9208 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9211 die("failure: check ownership %s", file);
9213 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9214 die("failure: check ownership %s", file);
9219 if (wait_for_pid(pid))
9222 /* Verify that ownership looks correct for callers in the third userns. */
9225 log_stderr("failure: fork");
9229 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9230 die("failure: switch_userns");
9232 for (id = 0; id <= id_file_range; id++) {
9234 unsigned int id_level2, id_level3;
9237 snprintf(file, sizeof(file), FILE1 "_%u", id);
9239 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9240 die("failure: check ownership %s", file);
9244 * The idmapping of the third userns has a hole
9245 * at uid/gid 1000. That means:
9246 * - 1000->userns_0(2000000) // init userns
9247 * - 1000->userns_1(2000000) // level 1
9248 * - 1000->userns_2(1000000) // level 2
9249 * - 1000->userns_3(1000) // level 3 (because level 3 has a hole)
9252 bret = expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2);
9254 bret = expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid);
9257 die("failure: check ownership %s", file);
9261 /* This id is unmapped. */
9262 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9264 id_level3 = id; /* Rest is business as usual. */
9265 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9268 die("failure: check ownership %s", file);
9270 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9271 die("failure: check ownership %s", file);
9276 if (wait_for_pid(pid))
9279 /* Verify that ownership looks correct for callers in the fourth userns. */
9282 log_stderr("failure: fork");
9286 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9287 die("failure: switch_userns");
9289 for (id = 0; id <= id_file_range; id++) {
9292 snprintf(file, sizeof(file), FILE1 "_%u", id);
9294 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9295 die("failure: check ownership %s", file);
9297 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9298 die("failure: check ownership %s", file);
9300 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9301 die("failure: check ownership %s", file);
9303 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9304 die("failure: check ownership %s", file);
9309 if (wait_for_pid(pid))
9312 /* Verify that chown works correctly for callers in the first userns. */
9315 log_stderr("failure: fork");
9319 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9320 die("failure: switch_userns");
9322 for (id = 0; id <= id_file_range; id++) {
9324 unsigned int id_level1, id_level2, id_level3, id_new;
9327 snprintf(file, sizeof(file), FILE1 "_%u", id);
9330 if (fchownat(fd_open_tree_level1, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9331 die("failure: fchownat %s", file);
9334 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9335 die("failure: check ownership %s", file);
9337 id_level2 = id_new + 1000000;
9338 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9339 die("failure: check ownership %s", file);
9341 if (id_new == 999) {
9342 /* This id is unmapped. */
9343 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9344 } else if (id_new == 1000) {
9345 id_level3 = id_new + 1000000; /* We punched a hole in the map at 1000. */
9346 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9348 id_level3 = id_new + 2000000; /* Rest is business as usual. */
9349 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9352 die("failure: check ownership %s", file);
9354 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9355 die("failure: check ownership %s", file);
9357 /* Revert ownership. */
9358 if (fchownat(fd_open_tree_level1, file, id, id, AT_SYMLINK_NOFOLLOW))
9359 die("failure: fchownat %s", file);
9364 if (wait_for_pid(pid))
9367 /* Verify that chown works correctly for callers in the second userns. */
9370 log_stderr("failure: fork");
9374 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9375 die("failure: switch_userns");
9377 for (id = 0; id <= id_file_range; id++) {
9379 unsigned int id_level2, id_level3, id_new;
9382 snprintf(file, sizeof(file), FILE1 "_%u", id);
9385 if (fchownat(fd_open_tree_level2, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9386 die("failure: fchownat %s", file);
9388 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9389 die("failure: check ownership %s", file);
9392 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9393 die("failure: check ownership %s", file);
9395 if (id_new == 999) {
9396 /* This id is unmapped. */
9397 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9398 } else if (id_new == 1000) {
9399 id_level3 = id_new; /* We punched a hole in the map at 1000. */
9400 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9402 id_level3 = id_new + 1000000; /* Rest is business as usual. */
9403 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9406 die("failure: check ownership %s", file);
9408 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9409 die("failure: check ownership %s", file);
9411 /* Revert ownership. */
9412 if (fchownat(fd_open_tree_level2, file, id, id, AT_SYMLINK_NOFOLLOW))
9413 die("failure: fchownat %s", file);
9418 if (wait_for_pid(pid))
9421 /* Verify that chown works correctly for callers in the third userns. */
9424 log_stderr("failure: fork");
9428 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9429 die("failure: switch_userns");
9431 for (id = 0; id <= id_file_range; id++) {
9432 unsigned int id_new;
9435 snprintf(file, sizeof(file), FILE1 "_%u", id);
9438 if (id_new == 999 || id_new == 1000) {
9440 * We can't change ownership as we can't
9441 * chown from or to an unmapped id.
9443 if (!fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9444 die("failure: fchownat %s", file);
9446 if (fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9447 die("failure: fchownat %s", file);
9450 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9451 die("failure: check ownership %s", file);
9453 /* There's no id 1000 anymore as we changed ownership for id 1000 to 1001 above. */
9454 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9455 die("failure: check ownership %s", file);
9457 if (id_new == 999) {
9459 * We did not change ownership as we can't
9460 * chown to an unmapped id.
9462 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id, id))
9463 die("failure: check ownership %s", file);
9464 } else if (id_new == 1000) {
9466 * We did not change ownership as we can't
9467 * chown from an unmapped id.
9469 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9470 die("failure: check ownership %s", file);
9472 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id_new, id_new))
9473 die("failure: check ownership %s", file);
9476 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9477 die("failure: check ownership %s", file);
9479 /* Revert ownership. */
9480 if (id_new != 999 && id_new != 1000) {
9481 if (fchownat(fd_open_tree_level3, file, id, id, AT_SYMLINK_NOFOLLOW))
9482 die("failure: fchownat %s", file);
9488 if (wait_for_pid(pid))
9491 /* Verify that chown works correctly for callers in the fourth userns. */
9494 log_stderr("failure: fork");
9498 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9499 die("failure: switch_userns");
9501 for (id = 0; id <= id_file_range; id++) {
9503 unsigned long id_new;
9505 snprintf(file, sizeof(file), FILE1 "_%u", id);
9508 if (!fchownat(fd_open_tree_level4, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9509 die("failure: fchownat %s", file);
9511 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9512 die("failure: check ownership %s", file);
9514 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9515 die("failure: check ownership %s", file);
9517 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9518 die("failure: check ownership %s", file);
9520 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9521 die("failure: check ownership %s", file);
9527 if (wait_for_pid(pid))
9531 log_debug("Ran test");
9534 list_for_each_safe(it, &hierarchy[0].id_map, next) {
9540 list_for_each_safe(it, &hierarchy[1].id_map, next) {
9546 list_for_each_safe(it, &hierarchy[2].id_map, next) {
9552 safe_close(hierarchy[0].fd_userns);
9553 safe_close(hierarchy[1].fd_userns);
9554 safe_close(hierarchy[2].fd_userns);
9555 safe_close(fd_dir1);
9556 safe_close(fd_open_tree_level1);
9557 safe_close(fd_open_tree_level2);
9558 safe_close(fd_open_tree_level3);
9559 safe_close(fd_open_tree_level4);
9563 #ifndef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS
9565 #ifndef BTRFS_PATH_NAME_MAX
9566 #define BTRFS_PATH_NAME_MAX 4087
9569 struct btrfs_ioctl_vol_args {
9571 char name[BTRFS_PATH_NAME_MAX + 1];
9575 #ifndef HAVE_STRUCT_BTRFS_QGROUP_LIMIT
9576 struct btrfs_qgroup_limit {
9585 #ifndef HAVE_STRUCT_BTRFS_QGROUP_INHERIT
9586 struct btrfs_qgroup_inherit {
9589 __u64 num_ref_copies;
9590 __u64 num_excl_copies;
9591 struct btrfs_qgroup_limit lim;
9596 #if !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2) || !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2_SUBVOLID)
9598 #ifndef BTRFS_SUBVOL_NAME_MAX
9599 #define BTRFS_SUBVOL_NAME_MAX 4039
9602 struct btrfs_ioctl_vol_args_v2 {
9609 struct btrfs_qgroup_inherit *qgroup_inherit;
9614 char name[BTRFS_SUBVOL_NAME_MAX + 1];
9621 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_ARGS
9623 #ifndef BTRFS_INO_LOOKUP_PATH_MAX
9624 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
9626 struct btrfs_ioctl_ino_lookup_args {
9629 char name[BTRFS_INO_LOOKUP_PATH_MAX];
9633 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_USER_ARGS
9635 #ifndef BTRFS_VOL_NAME_MAX
9636 #define BTRFS_VOL_NAME_MAX 255
9639 #ifndef BTRFS_INO_LOOKUP_USER_PATH_MAX
9640 #define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1)
9643 struct btrfs_ioctl_ino_lookup_user_args {
9646 char name[BTRFS_VOL_NAME_MAX + 1];
9647 char path[BTRFS_INO_LOOKUP_USER_PATH_MAX];
9651 #ifndef HAVE_STRUCT_BTRFS_IOCTL_GET_SUBVOL_ROOTREF_ARGS
9653 #ifndef BTRFS_MAX_ROOTREF_BUFFER_NUM
9654 #define BTRFS_MAX_ROOTREF_BUFFER_NUM 255
9657 struct btrfs_ioctl_get_subvol_rootref_args {
9662 } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
9668 #ifndef BTRFS_IOCTL_MAGIC
9669 #define BTRFS_IOCTL_MAGIC 0x94
9672 #ifndef BTRFS_IOC_SNAP_DESTROY
9673 #define BTRFS_IOC_SNAP_DESTROY \
9674 _IOW(BTRFS_IOCTL_MAGIC, 15, struct btrfs_ioctl_vol_args)
9677 #ifndef BTRFS_IOC_SNAP_DESTROY_V2
9678 #define BTRFS_IOC_SNAP_DESTROY_V2 \
9679 _IOW(BTRFS_IOCTL_MAGIC, 63, struct btrfs_ioctl_vol_args_v2)
9682 #ifndef BTRFS_IOC_SNAP_CREATE_V2
9683 #define BTRFS_IOC_SNAP_CREATE_V2 \
9684 _IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
9687 #ifndef BTRFS_IOC_SUBVOL_CREATE_V2
9688 #define BTRFS_IOC_SUBVOL_CREATE_V2 \
9689 _IOW(BTRFS_IOCTL_MAGIC, 24, struct btrfs_ioctl_vol_args_v2)
9692 #ifndef BTRFS_IOC_SUBVOL_GETFLAGS
9693 #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
9696 #ifndef BTRFS_IOC_SUBVOL_SETFLAGS
9697 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
9700 #ifndef BTRFS_IOC_INO_LOOKUP
9701 #define BTRFS_IOC_INO_LOOKUP \
9702 _IOWR(BTRFS_IOCTL_MAGIC, 18, struct btrfs_ioctl_ino_lookup_args)
9705 #ifndef BTRFS_IOC_INO_LOOKUP_USER
9706 #define BTRFS_IOC_INO_LOOKUP_USER \
9707 _IOWR(BTRFS_IOCTL_MAGIC, 62, struct btrfs_ioctl_ino_lookup_user_args)
9710 #ifndef BTRFS_IOC_GET_SUBVOL_ROOTREF
9711 #define BTRFS_IOC_GET_SUBVOL_ROOTREF \
9712 _IOWR(BTRFS_IOCTL_MAGIC, 61, struct btrfs_ioctl_get_subvol_rootref_args)
9715 #ifndef BTRFS_SUBVOL_RDONLY
9716 #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
9719 #ifndef BTRFS_SUBVOL_SPEC_BY_ID
9720 #define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4)
9723 #ifndef BTRFS_FIRST_FREE_OBJECTID
9724 #define BTRFS_FIRST_FREE_OBJECTID 256ULL
9727 static int btrfs_delete_subvolume(int parent_fd, const char *name)
9729 struct btrfs_ioctl_vol_args args = {};
9734 if (len >= sizeof(args.name))
9735 return -ENAMETOOLONG;
9737 memcpy(args.name, name, len);
9738 args.name[len] = '\0';
9740 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY, &args);
9747 static int btrfs_delete_subvolume_id(int parent_fd, uint64_t subvolid)
9749 struct btrfs_ioctl_vol_args_v2 args = {};
9752 args.flags = BTRFS_SUBVOL_SPEC_BY_ID;
9753 args.subvolid = subvolid;
9755 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY_V2, &args);
9762 static int btrfs_create_subvolume(int parent_fd, const char *name)
9764 struct btrfs_ioctl_vol_args_v2 args = {};
9769 if (len >= sizeof(args.name))
9770 return -ENAMETOOLONG;
9772 memcpy(args.name, name, len);
9773 args.name[len] = '\0';
9775 ret = ioctl(parent_fd, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
9782 static int btrfs_create_snapshot(int fd, int parent_fd, const char *name,
9785 struct btrfs_ioctl_vol_args_v2 args = {
9791 if (flags & ~BTRFS_SUBVOL_RDONLY)
9795 if (len >= sizeof(args.name))
9796 return -ENAMETOOLONG;
9797 memcpy(args.name, name, len);
9798 args.name[len] = '\0';
9800 if (flags & BTRFS_SUBVOL_RDONLY)
9801 args.flags |= BTRFS_SUBVOL_RDONLY;
9802 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_CREATE_V2, &args);
9809 static int btrfs_get_subvolume_ro(int fd, bool *read_only_ret)
9814 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9818 *read_only_ret = flags & BTRFS_SUBVOL_RDONLY;
9822 static int btrfs_set_subvolume_ro(int fd, bool read_only)
9827 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9832 flags |= BTRFS_SUBVOL_RDONLY;
9834 flags &= ~BTRFS_SUBVOL_RDONLY;
9836 ret = ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
9843 static int btrfs_get_subvolume_id(int fd, uint64_t *id_ret)
9845 struct btrfs_ioctl_ino_lookup_args args = {
9847 .objectid = BTRFS_FIRST_FREE_OBJECTID,
9851 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
9855 *id_ret = args.treeid;
9861 * The following helpers are adapted from the btrfsutils library. We can't use
9862 * the library directly since we need full control over how the subvolume
9863 * iteration happens. We need to be able to check whether unprivileged
9864 * subvolume iteration is possible, i.e. whether BTRFS_IOC_INO_LOOKUP_USER is
9865 * available and also ensure that it is actually used when looking up paths.
9867 struct btrfs_stack {
9869 struct btrfs_ioctl_get_subvol_rootref_args rootref_args;
9878 struct btrfs_stack *search_stack;
9880 size_t stack_capacity;
9883 size_t cur_path_capacity;
9886 static struct btrfs_stack *top_stack_entry(struct btrfs_iter *iter)
9888 return &iter->search_stack[iter->stack_len - 1];
9891 static int pop_stack(struct btrfs_iter *iter)
9893 struct btrfs_stack *top, *parent;
9897 if (iter->stack_len == 1) {
9902 top = top_stack_entry(iter);
9904 parent = top_stack_entry(iter);
9907 for (i = parent->path_len; i < top->path_len; i++) {
9908 if (i == 0 || iter->cur_path[i] == '/') {
9909 parent_fd = openat(fd, "..", O_RDONLY);
9910 if (fd != iter->cur_fd)
9912 if (parent_fd == -1)
9917 if (iter->cur_fd != iter->fd)
9918 close(iter->cur_fd);
9924 static int append_stack(struct btrfs_iter *iter, uint64_t tree_id, size_t path_len)
9926 struct btrfs_stack *entry;
9928 if (iter->stack_len >= iter->stack_capacity) {
9929 size_t new_capacity = iter->stack_capacity * 2;
9930 struct btrfs_stack *new_search_stack;
9931 #ifdef HAVE_REALLOCARRAY
9932 new_search_stack = reallocarray(iter->search_stack, new_capacity,
9933 sizeof(*iter->search_stack));
9935 new_search_stack = realloc(iter->search_stack, new_capacity * sizeof(*iter->search_stack));
9937 if (!new_search_stack)
9940 iter->stack_capacity = new_capacity;
9941 iter->search_stack = new_search_stack;
9944 entry = &iter->search_stack[iter->stack_len];
9946 memset(entry, 0, sizeof(*entry));
9947 entry->path_len = path_len;
9948 entry->tree_id = tree_id;
9950 if (iter->stack_len) {
9951 struct btrfs_stack *top;
9955 top = top_stack_entry(iter);
9956 path = &iter->cur_path[top->path_len];
9959 fd = openat(iter->cur_fd, path, O_RDONLY);
9963 close(iter->cur_fd);
9972 static int btrfs_iterator_start(int fd, uint64_t top, struct btrfs_iter **ret)
9974 struct btrfs_iter *iter;
9977 iter = malloc(sizeof(*iter));
9984 iter->stack_len = 0;
9985 iter->stack_capacity = 4;
9986 iter->search_stack = malloc(sizeof(*iter->search_stack) *
9987 iter->stack_capacity);
9988 if (!iter->search_stack) {
9993 iter->cur_path_capacity = 256;
9994 iter->cur_path = malloc(iter->cur_path_capacity);
9995 if (!iter->cur_path) {
9997 goto out_search_stack;
10000 err = append_stack(iter, top, 0);
10009 free(iter->cur_path);
10011 free(iter->search_stack);
10017 static void btrfs_iterator_end(struct btrfs_iter *iter)
10020 free(iter->cur_path);
10021 free(iter->search_stack);
10022 if (iter->cur_fd != iter->fd)
10023 close(iter->cur_fd);
10029 static int __append_path(struct btrfs_iter *iter, const char *name,
10030 size_t name_len, const char *dir, size_t dir_len,
10031 size_t *path_len_ret)
10033 struct btrfs_stack *top = top_stack_entry(iter);
10037 path_len = top->path_len;
10039 * We need a joining slash if we have a current path and a subdirectory.
10041 if (top->path_len && dir_len)
10043 path_len += dir_len;
10045 * We need another joining slash if we have a current path and a name,
10046 * but not if we have a subdirectory, because the lookup ioctl includes
10047 * a trailing slash.
10049 if (top->path_len && !dir_len && name_len)
10051 path_len += name_len;
10053 /* We need one extra character for the NUL terminator. */
10054 if (path_len + 1 > iter->cur_path_capacity) {
10055 char *tmp = realloc(iter->cur_path, path_len + 1);
10059 iter->cur_path = tmp;
10060 iter->cur_path_capacity = path_len + 1;
10063 p = iter->cur_path + top->path_len;
10064 if (top->path_len && dir_len)
10066 memcpy(p, dir, dir_len);
10068 if (top->path_len && !dir_len && name_len)
10070 memcpy(p, name, name_len);
10074 *path_len_ret = path_len;
10079 static int get_subvolume_path(struct btrfs_iter *iter, uint64_t treeid,
10080 uint64_t dirid, size_t *path_len_ret)
10082 struct btrfs_ioctl_ino_lookup_user_args args = {
10088 ret = ioctl(iter->cur_fd, BTRFS_IOC_INO_LOOKUP_USER, &args);
10092 return __append_path(iter, args.name, strlen(args.name), args.path,
10093 strlen(args.path), path_len_ret);
10096 static int btrfs_iterator_next(struct btrfs_iter *iter, char **path_ret,
10099 struct btrfs_stack *top;
10100 uint64_t treeid, dirid;
10106 if (iter->stack_len == 0)
10109 top = top_stack_entry(iter);
10110 if (top->items_pos < top->rootref_args.num_items) {
10113 ret = ioctl(iter->cur_fd,
10114 BTRFS_IOC_GET_SUBVOL_ROOTREF,
10115 &top->rootref_args);
10116 if (ret == -1 && errno != EOVERFLOW)
10118 top->items_pos = 0;
10120 if (top->rootref_args.num_items == 0) {
10121 err = pop_stack(iter);
10128 treeid = top->rootref_args.rootref[top->items_pos].treeid;
10129 dirid = top->rootref_args.rootref[top->items_pos].dirid;
10131 err = get_subvolume_path(iter, treeid, dirid, &path_len);
10133 /* Skip the subvolume if we can't access it. */
10134 if (errno == EACCES)
10139 err = append_stack(iter, treeid, path_len);
10142 * Skip the subvolume if it does not exist (which can
10143 * happen if there is another filesystem mounted over a
10144 * parent directory) or we don't have permission to
10147 if (errno == ENOENT || errno == EACCES)
10152 top = top_stack_entry(iter);
10158 *path_ret = malloc(top->path_len + 1);
10161 memcpy(*path_ret, iter->cur_path, top->path_len);
10162 (*path_ret)[top->path_len] = '\0';
10165 *id_ret = top->tree_id;
10169 #define BTRFS_SUBVOLUME1 "subvol1"
10170 #define BTRFS_SUBVOLUME1_SNAPSHOT1 "subvol1_snapshot1"
10171 #define BTRFS_SUBVOLUME1_SNAPSHOT1_RO "subvol1_snapshot1_ro"
10172 #define BTRFS_SUBVOLUME1_RENAME "subvol1_rename"
10173 #define BTRFS_SUBVOLUME2 "subvol2"
10175 static int btrfs_subvolumes_fsids_mapped(void)
10178 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10179 struct mount_attr attr = {
10180 .attr_set = MOUNT_ATTR_IDMAP,
10184 if (!caps_supported())
10187 /* Changing mount properties on a detached mount. */
10188 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10189 if (attr.userns_fd < 0) {
10190 log_stderr("failure: get_userns_fd");
10194 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10197 AT_SYMLINK_NOFOLLOW |
10198 OPEN_TREE_CLOEXEC |
10200 if (open_tree_fd < 0) {
10201 log_stderr("failure: sys_open_tree");
10205 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10206 log_stderr("failure: sys_mount_setattr");
10211 * The open_tree() syscall returns an O_PATH file descriptor which we
10212 * can't use with ioctl(). So let's reopen it as a proper file
10215 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10217 log_stderr("failure: openat");
10223 log_stderr("failure: fork");
10227 if (!switch_fsids(10000, 10000))
10228 die("failure: switch fsids");
10231 die("failure: raise caps");
10234 * The caller's fsids now have mappings in the idmapped mount so
10235 * any file creation must succeed.
10238 /* create subvolume */
10239 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10240 die("failure: btrfs_create_subvolume");
10242 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10243 die("failure: check ownership");
10245 /* remove subvolume */
10246 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10247 die("failure: btrfs_delete_subvolume");
10249 /* create subvolume */
10250 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10251 die("failure: btrfs_create_subvolume");
10253 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10254 die("failure: check ownership");
10257 die("failure: lower caps");
10260 * The filesystem is not mounted with user_subvol_rm_allowed so
10261 * subvolume deletion must fail.
10263 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10264 die("failure: btrfs_delete_subvolume");
10265 if (errno != EPERM)
10266 die("failure: errno");
10268 exit(EXIT_SUCCESS);
10270 if (wait_for_pid(pid))
10273 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10274 die("failure: check ownership");
10276 /* remove subvolume */
10277 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10278 log_stderr("failure: btrfs_delete_subvolume");
10283 log_debug("Ran test");
10285 safe_close(attr.userns_fd);
10286 safe_close(open_tree_fd);
10287 safe_close(tree_fd);
10292 static int btrfs_subvolumes_fsids_mapped_userns(void)
10295 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10296 struct mount_attr attr = {
10297 .attr_set = MOUNT_ATTR_IDMAP,
10301 if (!caps_supported())
10304 /* Changing mount properties on a detached mount. */
10305 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10306 if (attr.userns_fd < 0) {
10307 log_stderr("failure: get_userns_fd");
10311 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10314 AT_SYMLINK_NOFOLLOW |
10315 OPEN_TREE_CLOEXEC |
10317 if (open_tree_fd < 0) {
10318 log_stderr("failure: sys_open_tree");
10322 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10323 log_stderr("failure: sys_mount_setattr");
10328 * The open_tree() syscall returns an O_PATH file descriptor which we
10329 * can't use with ioctl(). So let's reopen it as a proper file
10332 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10334 log_stderr("failure: openat");
10340 log_stderr("failure: fork");
10344 if (!switch_userns(attr.userns_fd, 0, 0, false))
10345 die("failure: switch_userns");
10347 /* The caller's fsids now have mappings in the idmapped mount so
10348 * any file creation must fail.
10351 /* create subvolume */
10352 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10353 die("failure: btrfs_create_subvolume");
10355 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10356 die("failure: check ownership");
10358 /* remove subvolume */
10359 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10360 die("failure: btrfs_delete_subvolume");
10362 exit(EXIT_SUCCESS);
10364 if (wait_for_pid(pid))
10367 /* remove subvolume */
10368 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10369 log_stderr("failure: btrfs_delete_subvolume");
10374 log_debug("Ran test");
10376 safe_close(attr.userns_fd);
10377 safe_close(open_tree_fd);
10378 safe_close(tree_fd);
10383 static int btrfs_subvolumes_fsids_unmapped(void)
10386 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10387 struct mount_attr attr = {
10388 .attr_set = MOUNT_ATTR_IDMAP,
10391 /* create directory for rename test */
10392 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10393 log_stderr("failure: btrfs_create_subvolume");
10397 /* change ownership of all files to uid 0 */
10398 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10399 log_stderr("failure: fchownat");
10403 /* Changing mount properties on a detached mount. */
10404 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10405 if (attr.userns_fd < 0) {
10406 log_stderr("failure: get_userns_fd");
10410 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10413 AT_SYMLINK_NOFOLLOW |
10414 OPEN_TREE_CLOEXEC |
10416 if (open_tree_fd < 0) {
10417 log_stderr("failure: sys_open_tree");
10421 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10422 log_stderr("failure: sys_mount_setattr");
10426 if (!switch_fsids(0, 0)) {
10427 log_stderr("failure: switch_fsids");
10432 * The caller's fsids don't have a mappings in the idmapped mount so
10433 * any file creation must fail.
10437 * The open_tree() syscall returns an O_PATH file descriptor which we
10438 * can't use with ioctl(). So let's reopen it as a proper file
10441 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10443 log_stderr("failure: openat");
10447 /* create subvolume */
10448 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2)) {
10449 log_stderr("failure: btrfs_create_subvolume");
10452 if (errno != EOVERFLOW) {
10453 log_stderr("failure: errno");
10457 /* try to rename a subvolume */
10458 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10459 BTRFS_SUBVOLUME1_RENAME)) {
10460 log_stderr("failure: renameat");
10463 if (errno != EOVERFLOW) {
10464 log_stderr("failure: errno");
10468 /* The caller is privileged over the inode so file deletion must work. */
10470 /* remove subvolume */
10471 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10472 log_stderr("failure: btrfs_delete_subvolume");
10477 log_debug("Ran test");
10479 safe_close(attr.userns_fd);
10480 safe_close(open_tree_fd);
10481 safe_close(tree_fd);
10486 static int btrfs_subvolumes_fsids_unmapped_userns(void)
10489 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
10490 struct mount_attr attr = {
10491 .attr_set = MOUNT_ATTR_IDMAP,
10495 /* create directory for rename test */
10496 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10497 log_stderr("failure: btrfs_create_subvolume");
10501 /* change ownership of all files to uid 0 */
10502 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10503 log_stderr("failure: fchownat");
10507 /* Changing mount properties on a detached mount. */
10508 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10509 if (attr.userns_fd < 0) {
10510 log_stderr("failure: get_userns_fd");
10514 /* Changing mount properties on a detached mount. */
10515 userns_fd = get_userns_fd(0, 30000, 10000);
10516 if (userns_fd < 0) {
10517 log_stderr("failure: get_userns_fd");
10521 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10524 AT_SYMLINK_NOFOLLOW |
10525 OPEN_TREE_CLOEXEC |
10527 if (open_tree_fd < 0) {
10528 log_stderr("failure: sys_open_tree");
10532 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10533 log_stderr("failure: sys_mount_setattr");
10538 * The open_tree() syscall returns an O_PATH file descriptor which we
10539 * can't use with ioctl(). So let's reopen it as a proper file
10542 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10544 log_stderr("failure: openat");
10550 log_stderr("failure: fork");
10554 if (!switch_userns(userns_fd, 0, 0, false))
10555 die("failure: switch_userns");
10557 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
10558 t_overflowuid, t_overflowgid))
10559 die("failure: expected_uid_gid");
10561 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
10562 t_overflowuid, t_overflowgid))
10563 die("failure: expected_uid_gid");
10566 * The caller's fsids don't have a mappings in the idmapped mount so
10567 * any file creation must fail.
10570 /* create subvolume */
10571 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
10572 die("failure: btrfs_create_subvolume");
10573 if (errno != EOVERFLOW)
10574 die("failure: errno");
10576 /* try to rename a subvolume */
10577 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10578 BTRFS_SUBVOLUME1_RENAME))
10579 die("failure: renameat");
10580 if (errno != EOVERFLOW)
10581 die("failure: errno");
10584 * The caller is not privileged over the inode so subvolume
10585 * deletion must fail.
10588 /* remove subvolume */
10589 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10590 die("failure: btrfs_delete_subvolume");
10592 exit(EXIT_SUCCESS);
10594 if (wait_for_pid(pid))
10597 /* remove subvolume */
10598 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10599 log_stderr("failure: btrfs_delete_subvolume");
10604 log_debug("Ran test");
10606 safe_close(attr.userns_fd);
10607 safe_close(open_tree_fd);
10608 safe_close(tree_fd);
10609 safe_close(userns_fd);
10614 static int btrfs_snapshots_fsids_mapped(void)
10617 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10618 struct mount_attr attr = {
10619 .attr_set = MOUNT_ATTR_IDMAP,
10623 if (!caps_supported())
10626 /* Changing mount properties on a detached mount. */
10627 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10628 if (attr.userns_fd < 0) {
10629 log_stderr("failure: get_userns_fd");
10633 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10636 AT_SYMLINK_NOFOLLOW |
10637 OPEN_TREE_CLOEXEC |
10639 if (open_tree_fd < 0) {
10640 log_stderr("failure: sys_open_tree");
10644 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10645 log_stderr("failure: sys_mount_setattr");
10650 * The open_tree() syscall returns an O_PATH file descriptor which we
10651 * can't use with ioctl(). So let's reopen it as a proper file
10654 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10656 log_stderr("failure: openat");
10662 log_stderr("failure: fork");
10666 int subvolume_fd = -EBADF;
10668 if (!switch_fsids(10000, 10000))
10669 die("failure: switch fsids");
10672 die("failure: raise caps");
10674 /* The caller's fsids now have mappings in the idmapped mount so
10675 * any file creation must fail.
10678 /* create subvolume */
10679 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10680 die("failure: btrfs_create_subvolume");
10682 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10683 die("failure: expected_uid_gid");
10685 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10686 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10687 if (subvolume_fd < 0)
10688 die("failure: openat");
10690 /* create read-write snapshot */
10691 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10692 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10693 die("failure: btrfs_create_snapshot");
10695 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10696 die("failure: expected_uid_gid");
10698 /* create read-only snapshot */
10699 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10700 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10701 BTRFS_SUBVOL_RDONLY))
10702 die("failure: btrfs_create_snapshot");
10704 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10705 die("failure: expected_uid_gid");
10707 safe_close(subvolume_fd);
10709 /* remove subvolume */
10710 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10711 die("failure: btrfs_delete_subvolume");
10713 /* remove read-write snapshot */
10714 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
10715 die("failure: btrfs_delete_subvolume");
10717 /* remove read-only snapshot */
10718 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
10719 die("failure: btrfs_delete_subvolume");
10721 /* create directory */
10722 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10723 die("failure: btrfs_create_subvolume");
10725 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10726 die("failure: expected_uid_gid");
10728 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10729 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10730 if (subvolume_fd < 0)
10731 die("failure: openat");
10733 /* create read-write snapshot */
10734 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10735 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10736 die("failure: btrfs_create_snapshot");
10738 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10739 die("failure: expected_uid_gid");
10741 /* create read-only snapshot */
10742 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10743 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10744 BTRFS_SUBVOL_RDONLY))
10745 die("failure: btrfs_create_snapshot");
10747 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10748 die("failure: expected_uid_gid");
10750 safe_close(subvolume_fd);
10752 exit(EXIT_SUCCESS);
10754 if (wait_for_pid(pid))
10757 /* remove directory */
10758 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10759 log_stderr("failure: btrfs_delete_subvolume");
10763 /* remove read-write snapshot */
10764 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10765 log_stderr("failure: btrfs_delete_subvolume");
10769 /* remove read-only snapshot */
10770 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10771 log_stderr("failure: btrfs_delete_subvolume");
10776 log_debug("Ran test");
10778 safe_close(attr.userns_fd);
10779 safe_close(open_tree_fd);
10780 safe_close(tree_fd);
10785 static int btrfs_snapshots_fsids_mapped_userns(void)
10788 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10789 struct mount_attr attr = {
10790 .attr_set = MOUNT_ATTR_IDMAP,
10794 if (!caps_supported())
10797 /* Changing mount properties on a detached mount. */
10798 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10799 if (attr.userns_fd < 0) {
10800 log_stderr("failure: get_userns_fd");
10804 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10807 AT_SYMLINK_NOFOLLOW |
10808 OPEN_TREE_CLOEXEC |
10810 if (open_tree_fd < 0) {
10811 log_stderr("failure: sys_open_tree");
10815 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10816 log_stderr("failure: sys_mount_setattr");
10821 * The open_tree() syscall returns an O_PATH file descriptor which we
10822 * can't use with ioctl(). So let's reopen it as a proper file
10825 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10827 log_stderr("failure: openat");
10833 log_stderr("failure: fork");
10837 int subvolume_fd = -EBADF;
10839 if (!switch_userns(attr.userns_fd, 0, 0, false))
10840 die("failure: switch_userns");
10842 /* create subvolume */
10843 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10844 die("failure: btrfs_create_subvolume");
10846 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10847 die("failure: expected_uid_gid");
10849 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10850 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10851 if (subvolume_fd < 0)
10852 die("failure: openat");
10854 /* create read-write snapshot */
10855 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10856 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10857 die("failure: btrfs_create_snapshot");
10859 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
10860 die("failure: expected_uid_gid");
10862 /* create read-only snapshot */
10863 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10864 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10865 BTRFS_SUBVOL_RDONLY))
10866 die("failure: btrfs_create_snapshot");
10868 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
10869 die("failure: expected_uid_gid");
10871 safe_close(subvolume_fd);
10873 exit(EXIT_SUCCESS);
10875 if (wait_for_pid(pid))
10878 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10879 die("failure: expected_uid_gid");
10881 /* remove directory */
10882 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10883 log_stderr("failure: btrfs_delete_subvolume");
10887 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10888 die("failure: expected_uid_gid");
10890 /* remove read-write snapshot */
10891 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10892 log_stderr("failure: btrfs_delete_subvolume");
10896 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10897 die("failure: expected_uid_gid");
10899 /* remove read-only snapshot */
10900 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10901 log_stderr("failure: btrfs_delete_subvolume");
10906 log_debug("Ran test");
10908 safe_close(attr.userns_fd);
10909 safe_close(open_tree_fd);
10910 safe_close(tree_fd);
10915 static int btrfs_snapshots_fsids_unmapped(void)
10918 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10919 struct mount_attr attr = {
10920 .attr_set = MOUNT_ATTR_IDMAP,
10924 if (!caps_supported())
10927 /* create directory for rename test */
10928 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10929 log_stderr("failure: btrfs_create_subvolume");
10933 /* change ownership of all files to uid 0 */
10934 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10935 log_stderr("failure: fchownat");
10939 /* Changing mount properties on a detached mount. */
10940 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10941 if (attr.userns_fd < 0) {
10942 log_stderr("failure: get_userns_fd");
10946 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10949 AT_SYMLINK_NOFOLLOW |
10950 OPEN_TREE_CLOEXEC |
10952 if (open_tree_fd < 0) {
10953 log_stderr("failure: sys_open_tree");
10957 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
10959 log_stderr("failure: sys_mount_setattr");
10965 log_stderr("failure: fork");
10969 int subvolume_fd = -EBADF;
10971 if (!switch_fsids(0, 0)) {
10972 log_stderr("failure: switch_fsids");
10977 * The caller's fsids don't have a mappings in the idmapped
10978 * mount so any file creation must fail.
10982 * The open_tree() syscall returns an O_PATH file descriptor
10983 * which we can't use with ioctl(). So let's reopen it as a
10984 * proper file descriptor.
10986 tree_fd = openat(open_tree_fd, ".",
10987 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10989 die("failure: openat");
10991 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10992 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10993 if (subvolume_fd < 0)
10994 die("failure: openat");
10996 /* create directory */
10997 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
10998 die("failure: btrfs_create_subvolume");
10999 if (errno != EOVERFLOW)
11000 die("failure: errno");
11002 /* create read-write snapshot */
11003 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11004 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11005 die("failure: btrfs_create_snapshot");
11006 if (errno != EOVERFLOW)
11007 die("failure: errno");
11009 /* create read-only snapshot */
11010 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11011 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11012 BTRFS_SUBVOL_RDONLY))
11013 die("failure: btrfs_create_snapshot");
11014 if (errno != EOVERFLOW)
11015 die("failure: errno");
11017 /* try to rename a directory */
11018 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11019 BTRFS_SUBVOLUME1_RENAME))
11020 die("failure: renameat");
11021 if (errno != EOVERFLOW)
11022 die("failure: errno");
11025 die("failure: caps_down");
11027 /* create read-write snapshot */
11028 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11029 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11030 die("failure: btrfs_create_snapshot");
11031 if (errno != EPERM)
11032 die("failure: errno");
11034 /* create read-only snapshot */
11035 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11036 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11037 BTRFS_SUBVOL_RDONLY))
11038 die("failure: btrfs_create_snapshot");
11039 if (errno != EPERM)
11040 die("failure: errno");
11043 * The caller is not privileged over the inode so subvolume
11044 * deletion must fail.
11047 /* remove directory */
11048 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11049 die("failure: btrfs_delete_subvolume");
11050 if (errno != EPERM)
11051 die("failure: errno");
11054 die("failure: caps_down");
11057 * The caller is privileged over the inode so subvolume
11058 * deletion must work.
11061 /* remove directory */
11062 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11063 die("failure: btrfs_delete_subvolume");
11065 exit(EXIT_SUCCESS);
11067 if (wait_for_pid(pid))
11071 log_debug("Ran test");
11073 safe_close(attr.userns_fd);
11074 safe_close(open_tree_fd);
11075 safe_close(tree_fd);
11080 static int btrfs_snapshots_fsids_unmapped_userns(void)
11083 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
11084 userns_fd = -EBADF;
11085 struct mount_attr attr = {
11086 .attr_set = MOUNT_ATTR_IDMAP,
11090 if (!caps_supported())
11093 /* create directory for rename test */
11094 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
11095 log_stderr("failure: btrfs_create_subvolume");
11099 /* change ownership of all files to uid 0 */
11100 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
11101 log_stderr("failure: fchownat");
11105 /* Changing mount properties on a detached mount. */
11106 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11107 if (attr.userns_fd < 0) {
11108 log_stderr("failure: get_userns_fd");
11112 /* Changing mount properties on a detached mount. */
11113 userns_fd = get_userns_fd(0, 30000, 10000);
11114 if (userns_fd < 0) {
11115 log_stderr("failure: get_userns_fd");
11119 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11122 AT_SYMLINK_NOFOLLOW |
11123 OPEN_TREE_CLOEXEC |
11125 if (open_tree_fd < 0) {
11126 log_stderr("failure: sys_open_tree");
11130 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
11132 log_stderr("failure: sys_mount_setattr");
11137 * The open_tree() syscall returns an O_PATH file descriptor
11138 * which we can't use with ioctl(). So let's reopen it as a
11139 * proper file descriptor.
11141 tree_fd = openat(open_tree_fd, ".",
11142 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11144 log_stderr("failure: openat");
11148 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11149 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11150 if (subvolume_fd < 0) {
11151 log_stderr("failure: openat");
11157 log_stderr("failure: fork");
11161 if (!switch_userns(userns_fd, 0, 0, false))
11162 die("failure: switch_userns");
11164 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
11165 t_overflowuid, t_overflowgid))
11166 die("failure: expected_uid_gid");
11168 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
11169 t_overflowuid, t_overflowgid))
11170 die("failure: expected_uid_gid");
11173 * The caller's fsids don't have a mappings in the idmapped
11174 * mount so any file creation must fail.
11177 /* create directory */
11178 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
11179 die("failure: btrfs_create_subvolume");
11180 if (errno != EOVERFLOW)
11181 die("failure: errno");
11183 /* create read-write snapshot */
11184 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11185 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11186 die("failure: btrfs_create_snapshot");
11187 if (errno != EPERM)
11188 die("failure: errno");
11190 /* create read-only snapshot */
11191 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11192 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11193 BTRFS_SUBVOL_RDONLY))
11194 die("failure: btrfs_create_snapshot");
11195 if (errno != EPERM)
11196 die("failure: errno");
11198 /* try to rename a directory */
11199 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11200 BTRFS_SUBVOLUME1_RENAME))
11201 die("failure: renameat");
11202 if (errno != EOVERFLOW)
11203 die("failure: errno");
11206 * The caller is not privileged over the inode so subvolume
11207 * deletion must fail.
11210 /* remove directory */
11211 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11212 die("failure: btrfs_delete_subvolume");
11213 if (errno != EPERM)
11214 die("failure: errno");
11216 exit(EXIT_SUCCESS);
11218 if (wait_for_pid(pid))
11221 /* remove directory */
11222 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11223 die("failure: btrfs_delete_subvolume");
11226 log_debug("Ran test");
11228 safe_close(attr.userns_fd);
11229 safe_close(open_tree_fd);
11230 safe_close(subvolume_fd);
11231 safe_close(tree_fd);
11236 static int btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed(void)
11239 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11240 struct mount_attr attr = {
11241 .attr_set = MOUNT_ATTR_IDMAP,
11245 if (!caps_supported())
11248 /* Changing mount properties on a detached mount. */
11249 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11250 if (attr.userns_fd < 0) {
11251 log_stderr("failure: get_userns_fd");
11255 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11258 AT_SYMLINK_NOFOLLOW |
11259 OPEN_TREE_CLOEXEC |
11261 if (open_tree_fd < 0) {
11262 log_stderr("failure: sys_open_tree");
11266 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11267 log_stderr("failure: sys_mount_setattr");
11272 * The open_tree() syscall returns an O_PATH file descriptor which we
11273 * can't use with ioctl(). So let's reopen it as a proper file
11276 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11278 log_stderr("failure: openat");
11284 log_stderr("failure: fork");
11288 if (!switch_fsids(10000, 10000))
11289 die("failure: switch fsids");
11292 die("failure: raise caps");
11295 * The caller's fsids now have mappings in the idmapped mount so
11296 * any file creation must succedd.
11299 /* create subvolume */
11300 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11301 die("failure: btrfs_create_subvolume");
11303 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11304 die("failure: check ownership");
11307 * The scratch device is mounted with user_subvol_rm_allowed so
11308 * subvolume deletion must succeed.
11310 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11311 die("failure: btrfs_delete_subvolume");
11313 exit(EXIT_SUCCESS);
11315 if (wait_for_pid(pid))
11319 log_debug("Ran test");
11321 safe_close(attr.userns_fd);
11322 safe_close(open_tree_fd);
11323 safe_close(tree_fd);
11328 static int btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed(void)
11331 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11332 struct mount_attr attr = {
11333 .attr_set = MOUNT_ATTR_IDMAP,
11337 if (!caps_supported())
11340 /* Changing mount properties on a detached mount. */
11341 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11342 if (attr.userns_fd < 0) {
11343 log_stderr("failure: get_userns_fd");
11347 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11350 AT_SYMLINK_NOFOLLOW |
11351 OPEN_TREE_CLOEXEC |
11353 if (open_tree_fd < 0) {
11354 log_stderr("failure: sys_open_tree");
11358 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11359 log_stderr("failure: sys_mount_setattr");
11364 * The open_tree() syscall returns an O_PATH file descriptor which we
11365 * can't use with ioctl(). So let's reopen it as a proper file
11368 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11370 log_stderr("failure: openat");
11376 log_stderr("failure: fork");
11380 if (!switch_userns(attr.userns_fd, 0, 0, false))
11381 die("failure: switch_userns");
11383 /* The caller's fsids now have mappings in the idmapped mount so
11384 * any file creation must fail.
11387 /* create subvolume */
11388 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11389 die("failure: btrfs_create_subvolume");
11391 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11392 die("failure: check ownership");
11395 * The scratch device is mounted with user_subvol_rm_allowed so
11396 * subvolume deletion must succeed.
11398 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11399 die("failure: btrfs_delete_subvolume");
11401 exit(EXIT_SUCCESS);
11403 if (wait_for_pid(pid))
11407 log_debug("Ran test");
11409 safe_close(attr.userns_fd);
11410 safe_close(open_tree_fd);
11411 safe_close(tree_fd);
11416 static int btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed(void)
11419 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11420 struct mount_attr attr = {
11421 .attr_set = MOUNT_ATTR_IDMAP,
11425 if (!caps_supported())
11428 /* Changing mount properties on a detached mount. */
11429 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11430 if (attr.userns_fd < 0) {
11431 log_stderr("failure: get_userns_fd");
11435 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11438 AT_SYMLINK_NOFOLLOW |
11439 OPEN_TREE_CLOEXEC |
11441 if (open_tree_fd < 0) {
11442 log_stderr("failure: sys_open_tree");
11446 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11447 log_stderr("failure: sys_mount_setattr");
11452 * The open_tree() syscall returns an O_PATH file descriptor which we
11453 * can't use with ioctl(). So let's reopen it as a proper file
11456 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11458 log_stderr("failure: openat");
11464 log_stderr("failure: fork");
11468 int subvolume_fd = -EBADF;
11470 if (!switch_fsids(10000, 10000))
11471 die("failure: switch fsids");
11474 die("failure: raise caps");
11477 * The caller's fsids now have mappings in the idmapped mount so
11478 * any file creation must succeed.
11481 /* create subvolume */
11482 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11483 die("failure: btrfs_create_subvolume");
11485 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11486 die("failure: expected_uid_gid");
11488 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11489 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11490 if (subvolume_fd < 0)
11491 die("failure: openat");
11493 /* create read-write snapshot */
11494 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11495 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11496 die("failure: btrfs_create_snapshot");
11498 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
11499 die("failure: expected_uid_gid");
11501 /* create read-only snapshot */
11502 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11503 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11504 BTRFS_SUBVOL_RDONLY))
11505 die("failure: btrfs_create_snapshot");
11507 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
11508 die("failure: expected_uid_gid");
11510 safe_close(subvolume_fd);
11512 /* remove subvolume */
11513 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11514 die("failure: btrfs_delete_subvolume");
11516 /* remove read-write snapshot */
11517 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11518 die("failure: btrfs_delete_subvolume");
11520 /* remove read-only snapshot */
11521 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11522 die("failure: btrfs_delete_subvolume");
11524 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11525 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11526 if (subvolume_fd < 0)
11527 die("failure: openat");
11529 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11530 die("failure: btrfs_set_subvolume_ro");
11532 safe_close(subvolume_fd);
11534 /* remove read-only snapshot */
11535 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11536 die("failure: btrfs_delete_subvolume");
11538 exit(EXIT_SUCCESS);
11540 if (wait_for_pid(pid))
11544 log_debug("Ran test");
11546 safe_close(attr.userns_fd);
11547 safe_close(open_tree_fd);
11548 safe_close(tree_fd);
11553 static int btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed(void)
11556 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11557 struct mount_attr attr = {
11558 .attr_set = MOUNT_ATTR_IDMAP,
11562 if (!caps_supported())
11565 /* Changing mount properties on a detached mount. */
11566 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11567 if (attr.userns_fd < 0) {
11568 log_stderr("failure: get_userns_fd");
11572 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11575 AT_SYMLINK_NOFOLLOW |
11576 OPEN_TREE_CLOEXEC |
11578 if (open_tree_fd < 0) {
11579 log_stderr("failure: sys_open_tree");
11583 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11584 log_stderr("failure: sys_mount_setattr");
11589 * The open_tree() syscall returns an O_PATH file descriptor which we
11590 * can't use with ioctl(). So let's reopen it as a proper file
11593 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11595 log_stderr("failure: openat");
11601 log_stderr("failure: fork");
11605 int subvolume_fd = -EBADF;
11607 if (!switch_userns(attr.userns_fd, 0, 0, false))
11608 die("failure: switch_userns");
11610 /* create subvolume */
11611 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11612 die("failure: btrfs_create_subvolume");
11614 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11615 die("failure: expected_uid_gid");
11617 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11618 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11619 if (subvolume_fd < 0)
11620 die("failure: openat");
11622 /* create read-write snapshot */
11623 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11624 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11625 die("failure: btrfs_create_snapshot");
11627 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11628 die("failure: expected_uid_gid");
11630 /* create read-only snapshot */
11631 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11632 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11633 BTRFS_SUBVOL_RDONLY))
11634 die("failure: btrfs_create_snapshot");
11636 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11637 die("failure: expected_uid_gid");
11639 /* remove directory */
11640 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11641 die("failure: btrfs_delete_subvolume");
11643 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11644 die("failure: expected_uid_gid");
11646 /* remove read-write snapshot */
11647 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11648 die("failure: btrfs_delete_subvolume");
11650 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11651 die("failure: expected_uid_gid");
11653 /* remove read-only snapshot */
11654 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11655 die("failure: btrfs_delete_subvolume");
11657 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11658 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11659 if (subvolume_fd < 0)
11660 die("failure: openat");
11662 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11663 die("failure: btrfs_set_subvolume_ro");
11665 safe_close(subvolume_fd);
11667 /* remove read-only snapshot */
11668 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11669 die("failure: btrfs_delete_subvolume");
11671 exit(EXIT_SUCCESS);
11673 if (wait_for_pid(pid))
11677 log_debug("Ran test");
11679 safe_close(attr.userns_fd);
11680 safe_close(open_tree_fd);
11681 safe_close(tree_fd);
11686 static int btrfs_delete_by_spec_id(void)
11689 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
11690 uint64_t subvolume_id1 = -EINVAL, subvolume_id2 = -EINVAL;
11691 struct mount_attr attr = {
11692 .attr_set = MOUNT_ATTR_IDMAP,
11696 /* Changing mount properties on a detached mount. */
11697 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11698 if (attr.userns_fd < 0) {
11699 log_stderr("failure: get_userns_fd");
11703 /* create subvolume */
11704 if (btrfs_create_subvolume(t_mnt_scratch_fd, "A")) {
11705 log_stderr("failure: btrfs_create_subvolume");
11709 /* create subvolume */
11710 if (btrfs_create_subvolume(t_mnt_scratch_fd, "B")) {
11711 log_stderr("failure: btrfs_create_subvolume");
11715 subvolume_fd = openat(t_mnt_scratch_fd, "B", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11716 if (subvolume_fd < 0) {
11717 log_stderr("failure: openat");
11721 /* create subvolume */
11722 if (btrfs_create_subvolume(subvolume_fd, "C")) {
11723 log_stderr("failure: btrfs_create_subvolume");
11727 safe_close(subvolume_fd);
11729 subvolume_fd = openat(t_mnt_scratch_fd, "A", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11730 if (subvolume_fd < 0) {
11731 log_stderr("failure: openat");
11735 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id1)) {
11736 log_stderr("failure: btrfs_get_subvolume_id");
11740 subvolume_fd = openat(t_mnt_scratch_fd, "B/C", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11741 if (subvolume_fd < 0) {
11742 log_stderr("failure: openat");
11746 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id2)) {
11747 log_stderr("failure: btrfs_get_subvolume_id");
11751 if (sys_mount(t_device_scratch, t_mountpoint, "btrfs", 0, "subvol=B/C")) {
11752 log_stderr("failure: mount");
11756 open_tree_fd = sys_open_tree(-EBADF, t_mountpoint,
11758 AT_SYMLINK_NOFOLLOW |
11759 OPEN_TREE_CLOEXEC |
11761 if (open_tree_fd < 0) {
11762 log_stderr("failure: sys_open_tree");
11766 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11767 log_stderr("failure: sys_mount_setattr");
11772 * The open_tree() syscall returns an O_PATH file descriptor which we
11773 * can't use with ioctl(). So let's reopen it as a proper file
11776 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11778 log_stderr("failure: openat");
11784 log_stderr("failure: fork");
11789 * The subvolume isn't exposed in the idmapped mount so
11790 * delation via spec id must fail.
11792 if (!btrfs_delete_subvolume_id(tree_fd, subvolume_id1))
11793 die("failure: btrfs_delete_subvolume_id");
11794 if (errno != EOPNOTSUPP)
11795 die("failure: errno");
11797 if (btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id1))
11798 die("failure: btrfs_delete_subvolume_id");
11800 exit(EXIT_SUCCESS);
11802 if (wait_for_pid(pid))
11806 log_debug("Ran test");
11808 safe_close(attr.userns_fd);
11809 safe_close(open_tree_fd);
11810 safe_close(tree_fd);
11811 sys_umount2(t_mountpoint, MNT_DETACH);
11812 btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id2);
11813 btrfs_delete_subvolume(t_mnt_scratch_fd, "B");
11818 static int btrfs_subvolumes_setflags_fsids_mapped(void)
11821 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11822 struct mount_attr attr = {
11823 .attr_set = MOUNT_ATTR_IDMAP,
11827 if (!caps_supported())
11830 /* Changing mount properties on a detached mount. */
11831 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11832 if (attr.userns_fd < 0) {
11833 log_stderr("failure: get_userns_fd");
11837 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11840 AT_SYMLINK_NOFOLLOW |
11841 OPEN_TREE_CLOEXEC |
11843 if (open_tree_fd < 0) {
11844 log_stderr("failure: sys_open_tree");
11848 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11849 log_stderr("failure: sys_mount_setattr");
11854 * The open_tree() syscall returns an O_PATH file descriptor which we
11855 * can't use with ioctl(). So let's reopen it as a proper file
11858 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11860 log_stderr("failure: openat");
11866 log_stderr("failure: fork");
11870 int subvolume_fd = -EBADF;
11871 bool read_only = false;
11873 if (!switch_fsids(10000, 10000))
11874 die("failure: switch fsids");
11877 die("failure: raise caps");
11879 /* The caller's fsids now have mappings in the idmapped mount so
11880 * any file creation must fail.
11883 /* create subvolume */
11884 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11885 die("failure: btrfs_create_subvolume");
11887 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11888 die("failure: expected_uid_gid");
11890 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11891 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11892 if (subvolume_fd < 0)
11893 die("failure: openat");
11895 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11896 die("failure: btrfs_get_subvolume_ro");
11899 die("failure: read_only");
11901 if (btrfs_set_subvolume_ro(subvolume_fd, true))
11902 die("failure: btrfs_set_subvolume_ro");
11904 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11905 die("failure: btrfs_get_subvolume_ro");
11908 die("failure: not read_only");
11910 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11911 die("failure: btrfs_set_subvolume_ro");
11913 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11914 die("failure: btrfs_get_subvolume_ro");
11917 die("failure: read_only");
11919 safe_close(subvolume_fd);
11921 exit(EXIT_SUCCESS);
11923 if (wait_for_pid(pid))
11926 /* remove directory */
11927 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
11928 log_stderr("failure: btrfs_delete_subvolume");
11933 log_debug("Ran test");
11935 safe_close(attr.userns_fd);
11936 safe_close(open_tree_fd);
11937 safe_close(tree_fd);
11942 static int btrfs_subvolumes_setflags_fsids_mapped_userns(void)
11945 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11946 struct mount_attr attr = {
11947 .attr_set = MOUNT_ATTR_IDMAP,
11951 if (!caps_supported())
11954 /* Changing mount properties on a detached mount. */
11955 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11956 if (attr.userns_fd < 0) {
11957 log_stderr("failure: get_userns_fd");
11961 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11964 AT_SYMLINK_NOFOLLOW |
11965 OPEN_TREE_CLOEXEC |
11967 if (open_tree_fd < 0) {
11968 log_stderr("failure: sys_open_tree");
11972 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11973 log_stderr("failure: sys_mount_setattr");
11978 * The open_tree() syscall returns an O_PATH file descriptor which we
11979 * can't use with ioctl(). So let's reopen it as a proper file
11982 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11984 log_stderr("failure: openat");
11990 log_stderr("failure: fork");
11994 int subvolume_fd = -EBADF;
11995 bool read_only = false;
11997 if (!switch_userns(attr.userns_fd, 0, 0, false))
11998 die("failure: switch_userns");
12000 /* The caller's fsids now have mappings in the idmapped mount so
12001 * any file creation must fail.
12004 /* create subvolume */
12005 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12006 die("failure: btrfs_create_subvolume");
12008 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
12009 die("failure: expected_uid_gid");
12011 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12012 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12013 if (subvolume_fd < 0)
12014 die("failure: openat");
12016 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12017 die("failure: btrfs_get_subvolume_ro");
12020 die("failure: read_only");
12022 if (btrfs_set_subvolume_ro(subvolume_fd, true))
12023 die("failure: btrfs_set_subvolume_ro");
12025 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12026 die("failure: btrfs_get_subvolume_ro");
12029 die("failure: not read_only");
12031 if (btrfs_set_subvolume_ro(subvolume_fd, false))
12032 die("failure: btrfs_set_subvolume_ro");
12034 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12035 die("failure: btrfs_get_subvolume_ro");
12038 die("failure: read_only");
12040 safe_close(subvolume_fd);
12042 exit(EXIT_SUCCESS);
12044 if (wait_for_pid(pid))
12047 /* remove directory */
12048 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12049 log_stderr("failure: btrfs_delete_subvolume");
12054 log_debug("Ran test");
12056 safe_close(attr.userns_fd);
12057 safe_close(open_tree_fd);
12058 safe_close(tree_fd);
12063 static int btrfs_subvolumes_setflags_fsids_unmapped(void)
12066 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12067 struct mount_attr attr = {
12068 .attr_set = MOUNT_ATTR_IDMAP,
12072 if (!caps_supported())
12075 /* Changing mount properties on a detached mount. */
12076 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12077 if (attr.userns_fd < 0) {
12078 log_stderr("failure: get_userns_fd");
12082 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12085 AT_SYMLINK_NOFOLLOW |
12086 OPEN_TREE_CLOEXEC |
12088 if (open_tree_fd < 0) {
12089 log_stderr("failure: sys_open_tree");
12093 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12094 log_stderr("failure: sys_mount_setattr");
12099 * The open_tree() syscall returns an O_PATH file descriptor which we
12100 * can't use with ioctl(). So let's reopen it as a proper file
12103 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12105 log_stderr("failure: openat");
12109 /* create subvolume */
12110 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12111 log_stderr("failure: btrfs_create_subvolume");
12115 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12116 log_stderr("failure: expected_uid_gid");
12120 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12121 log_stderr("failure: expected_uid_gid");
12127 log_stderr("failure: fork");
12131 int subvolume_fd = -EBADF;
12132 bool read_only = false;
12134 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12135 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12136 if (subvolume_fd < 0)
12137 die("failure: openat");
12139 if (!switch_fsids(0, 0))
12140 die("failure: switch fsids");
12143 die("failure: raise caps");
12146 * The caller's fsids don't have mappings in the idmapped mount
12147 * so any file creation must fail.
12150 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12151 die("failure: btrfs_get_subvolume_ro");
12154 die("failure: read_only");
12156 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12157 die("failure: btrfs_set_subvolume_ro");
12158 if (errno != EPERM)
12159 die("failure: errno");
12161 safe_close(subvolume_fd);
12163 exit(EXIT_SUCCESS);
12165 if (wait_for_pid(pid))
12168 /* remove directory */
12169 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12170 log_stderr("failure: btrfs_delete_subvolume");
12175 log_debug("Ran test");
12177 safe_close(attr.userns_fd);
12178 safe_close(open_tree_fd);
12179 safe_close(tree_fd);
12184 static int btrfs_subvolumes_setflags_fsids_unmapped_userns(void)
12187 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
12188 struct mount_attr attr = {
12189 .attr_set = MOUNT_ATTR_IDMAP,
12193 if (!caps_supported())
12196 /* Changing mount properties on a detached mount. */
12197 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12198 if (attr.userns_fd < 0) {
12199 log_stderr("failure: get_userns_fd");
12203 /* Changing mount properties on a detached mount. */
12204 userns_fd = get_userns_fd(0, 30000, 10000);
12205 if (userns_fd < 0) {
12206 log_stderr("failure: get_userns_fd");
12210 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12213 AT_SYMLINK_NOFOLLOW |
12214 OPEN_TREE_CLOEXEC |
12216 if (open_tree_fd < 0) {
12217 log_stderr("failure: sys_open_tree");
12221 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12222 log_stderr("failure: sys_mount_setattr");
12227 * The open_tree() syscall returns an O_PATH file descriptor which we
12228 * can't use with ioctl(). So let's reopen it as a proper file
12231 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12233 log_stderr("failure: openat");
12237 /* create subvolume */
12238 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12239 log_stderr("failure: btrfs_create_subvolume");
12243 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12244 log_stderr("failure: expected_uid_gid");
12248 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12249 log_stderr("failure: expected_uid_gid");
12255 log_stderr("failure: fork");
12259 int subvolume_fd = -EBADF;
12260 bool read_only = false;
12263 * The caller's fsids don't have mappings in the idmapped mount
12264 * so any file creation must fail.
12267 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12268 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12269 if (subvolume_fd < 0)
12270 die("failure: openat");
12272 if (!switch_userns(userns_fd, 0, 0, false))
12273 die("failure: switch_userns");
12275 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12276 t_overflowuid, t_overflowgid))
12277 die("failure: expected_uid_gid");
12279 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12280 t_overflowuid, t_overflowgid))
12281 die("failure: expected_uid_gid");
12283 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12284 die("failure: btrfs_get_subvolume_ro");
12287 die("failure: read_only");
12289 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12290 die("failure: btrfs_set_subvolume_ro");
12291 if (errno != EPERM)
12292 die("failure: errno");
12294 safe_close(subvolume_fd);
12296 exit(EXIT_SUCCESS);
12298 if (wait_for_pid(pid))
12301 /* remove directory */
12302 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12303 log_stderr("failure: btrfs_delete_subvolume");
12308 log_debug("Ran test");
12310 safe_close(attr.userns_fd);
12311 safe_close(open_tree_fd);
12312 safe_close(tree_fd);
12313 safe_close(userns_fd);
12318 static int btrfs_snapshots_setflags_fsids_mapped(void)
12321 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12322 struct mount_attr attr = {
12323 .attr_set = MOUNT_ATTR_IDMAP,
12327 if (!caps_supported())
12330 /* Changing mount properties on a detached mount. */
12331 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12332 if (attr.userns_fd < 0) {
12333 log_stderr("failure: get_userns_fd");
12337 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12340 AT_SYMLINK_NOFOLLOW |
12341 OPEN_TREE_CLOEXEC |
12343 if (open_tree_fd < 0) {
12344 log_stderr("failure: sys_open_tree");
12348 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12349 log_stderr("failure: sys_mount_setattr");
12354 * The open_tree() syscall returns an O_PATH file descriptor which we
12355 * can't use with ioctl(). So let's reopen it as a proper file
12358 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12360 log_stderr("failure: openat");
12366 log_stderr("failure: fork");
12370 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12371 bool read_only = false;
12373 if (!switch_fsids(10000, 10000))
12374 die("failure: switch fsids");
12377 die("failure: raise caps");
12380 * The caller's fsids now have mappings in the idmapped mount
12381 * so any file creation must succeed.
12384 /* create subvolume */
12385 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12386 die("failure: btrfs_create_subvolume");
12388 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
12389 die("failure: expected_uid_gid");
12391 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12392 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12393 if (subvolume_fd < 0)
12394 die("failure: openat");
12396 /* create read-write snapshot */
12397 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12398 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12399 die("failure: btrfs_create_snapshot");
12401 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
12402 die("failure: expected_uid_gid");
12404 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12405 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12406 if (snapshot_fd < 0)
12407 die("failure: openat");
12409 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12410 die("failure: btrfs_get_subvolume_ro");
12413 die("failure: read_only");
12415 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12416 die("failure: btrfs_set_subvolume_ro");
12418 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12419 die("failure: btrfs_get_subvolume_ro");
12422 die("failure: not read_only");
12424 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12425 die("failure: btrfs_set_subvolume_ro");
12427 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12428 die("failure: btrfs_get_subvolume_ro");
12431 die("failure: read_only");
12433 safe_close(snapshot_fd);
12434 safe_close(subvolume_fd);
12436 exit(EXIT_SUCCESS);
12438 if (wait_for_pid(pid))
12441 /* remove directory */
12442 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12443 log_stderr("failure: btrfs_delete_subvolume");
12447 /* remove directory */
12448 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12449 log_stderr("failure: btrfs_delete_subvolume");
12454 log_debug("Ran test");
12456 safe_close(attr.userns_fd);
12457 safe_close(open_tree_fd);
12458 safe_close(tree_fd);
12463 static int btrfs_snapshots_setflags_fsids_mapped_userns(void)
12466 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12467 struct mount_attr attr = {
12468 .attr_set = MOUNT_ATTR_IDMAP,
12472 if (!caps_supported())
12475 /* Changing mount properties on a detached mount. */
12476 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12477 if (attr.userns_fd < 0) {
12478 log_stderr("failure: get_userns_fd");
12482 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12485 AT_SYMLINK_NOFOLLOW |
12486 OPEN_TREE_CLOEXEC |
12488 if (open_tree_fd < 0) {
12489 log_stderr("failure: sys_open_tree");
12493 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12494 log_stderr("failure: sys_mount_setattr");
12499 * The open_tree() syscall returns an O_PATH file descriptor which we
12500 * can't use with ioctl(). So let's reopen it as a proper file
12503 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12505 log_stderr("failure: openat");
12511 log_stderr("failure: fork");
12515 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12516 bool read_only = false;
12518 if (!switch_userns(attr.userns_fd, 0, 0, false))
12519 die("failure: switch_userns");
12522 * The caller's fsids now have mappings in the idmapped mount so
12523 * any file creation must succeed.
12526 /* create subvolume */
12527 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12528 die("failure: btrfs_create_subvolume");
12530 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
12531 die("failure: expected_uid_gid");
12533 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12534 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12535 if (subvolume_fd < 0)
12536 die("failure: openat");
12538 /* create read-write snapshot */
12539 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12540 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12541 die("failure: btrfs_create_snapshot");
12543 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
12544 die("failure: expected_uid_gid");
12546 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12547 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12548 if (snapshot_fd < 0)
12549 die("failure: openat");
12551 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12552 die("failure: btrfs_get_subvolume_ro");
12555 die("failure: read_only");
12557 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12558 die("failure: btrfs_set_subvolume_ro");
12560 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12561 die("failure: btrfs_get_subvolume_ro");
12564 die("failure: not read_only");
12566 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12567 die("failure: btrfs_set_subvolume_ro");
12569 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12570 die("failure: btrfs_get_subvolume_ro");
12573 die("failure: read_only");
12575 safe_close(snapshot_fd);
12576 safe_close(subvolume_fd);
12578 exit(EXIT_SUCCESS);
12580 if (wait_for_pid(pid))
12583 /* remove directory */
12584 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12585 log_stderr("failure: btrfs_delete_subvolume");
12589 /* remove directory */
12590 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12591 log_stderr("failure: btrfs_delete_subvolume");
12596 log_debug("Ran test");
12598 safe_close(attr.userns_fd);
12599 safe_close(open_tree_fd);
12600 safe_close(tree_fd);
12605 static int btrfs_snapshots_setflags_fsids_unmapped(void)
12608 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
12609 struct mount_attr attr = {
12610 .attr_set = MOUNT_ATTR_IDMAP,
12614 if (!caps_supported())
12617 /* Changing mount properties on a detached mount. */
12618 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12619 if (attr.userns_fd < 0) {
12620 log_stderr("failure: get_userns_fd");
12624 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12627 AT_SYMLINK_NOFOLLOW |
12628 OPEN_TREE_CLOEXEC |
12630 if (open_tree_fd < 0) {
12631 log_stderr("failure: sys_open_tree");
12635 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12636 log_stderr("failure: sys_mount_setattr");
12641 * The open_tree() syscall returns an O_PATH file descriptor which we
12642 * can't use with ioctl(). So let's reopen it as a proper file
12645 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12647 log_stderr("failure: openat");
12651 /* create subvolume */
12652 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12653 log_stderr("failure: btrfs_create_subvolume");
12657 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12658 log_stderr("failure: expected_uid_gid");
12662 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12663 log_stderr("failure: expected_uid_gid");
12667 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12668 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12669 if (subvolume_fd < 0) {
12670 log_stderr("failure: openat");
12674 /* create read-write snapshot */
12675 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12676 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12677 log_stderr("failure: btrfs_create_snapshot");
12681 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12682 log_stderr("failure: expected_uid_gid");
12686 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12687 log_stderr("failure: expected_uid_gid");
12693 log_stderr("failure: fork");
12697 int snapshot_fd = -EBADF;
12698 bool read_only = false;
12700 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12701 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12702 if (snapshot_fd < 0)
12703 die("failure: openat");
12705 if (!switch_fsids(0, 0))
12706 die("failure: switch fsids");
12709 die("failure: raise caps");
12712 * The caller's fsids don't have mappings in the idmapped mount
12713 * so any file creation must fail.
12716 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12717 die("failure: btrfs_get_subvolume_ro");
12720 die("failure: read_only");
12722 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12723 die("failure: btrfs_set_subvolume_ro");
12724 if (errno != EPERM)
12725 die("failure: errno");
12727 safe_close(snapshot_fd);
12729 exit(EXIT_SUCCESS);
12731 if (wait_for_pid(pid))
12734 /* remove directory */
12735 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12736 log_stderr("failure: btrfs_delete_subvolume");
12740 /* remove directory */
12741 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12742 log_stderr("failure: btrfs_delete_subvolume");
12747 log_debug("Ran test");
12749 safe_close(attr.userns_fd);
12750 safe_close(open_tree_fd);
12751 safe_close(subvolume_fd);
12752 safe_close(tree_fd);
12757 static int btrfs_snapshots_setflags_fsids_unmapped_userns(void)
12760 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
12761 userns_fd = -EBADF;
12762 struct mount_attr attr = {
12763 .attr_set = MOUNT_ATTR_IDMAP,
12767 if (!caps_supported())
12770 /* Changing mount properties on a detached mount. */
12771 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12772 if (attr.userns_fd < 0) {
12773 log_stderr("failure: get_userns_fd");
12777 /* Changing mount properties on a detached mount. */
12778 userns_fd = get_userns_fd(0, 30000, 10000);
12779 if (userns_fd < 0) {
12780 log_stderr("failure: get_userns_fd");
12784 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12787 AT_SYMLINK_NOFOLLOW |
12788 OPEN_TREE_CLOEXEC |
12790 if (open_tree_fd < 0) {
12791 log_stderr("failure: sys_open_tree");
12795 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12796 log_stderr("failure: sys_mount_setattr");
12801 * The open_tree() syscall returns an O_PATH file descriptor which we
12802 * can't use with ioctl(). So let's reopen it as a proper file
12805 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12807 log_stderr("failure: openat");
12811 /* create subvolume */
12812 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12813 log_stderr("failure: btrfs_create_subvolume");
12817 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12818 log_stderr("failure: expected_uid_gid");
12822 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12823 log_stderr("failure: expected_uid_gid");
12827 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12828 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12829 if (subvolume_fd < 0) {
12830 log_stderr("failure: openat");
12834 /* create read-write snapshot */
12835 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12836 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12837 log_stderr("failure: btrfs_create_snapshot");
12841 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12842 log_stderr("failure: expected_uid_gid");
12846 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12847 log_stderr("failure: expected_uid_gid");
12853 log_stderr("failure: fork");
12857 int snapshot_fd = -EBADF;
12858 bool read_only = false;
12861 * The caller's fsids don't have mappings in the idmapped mount
12862 * so any file creation must fail.
12865 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12866 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12867 if (snapshot_fd < 0)
12868 die("failure: openat");
12871 if (!switch_userns(userns_fd, 0, 0, false))
12872 die("failure: switch_userns");
12874 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12875 t_overflowuid, t_overflowgid))
12876 die("failure: expected_uid_gid");
12878 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12879 t_overflowuid, t_overflowgid))
12880 die("failure: expected_uid_gid");
12883 * The caller's fsids don't have mappings in the idmapped mount
12884 * so any file creation must fail.
12887 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12888 die("failure: btrfs_get_subvolume_ro");
12891 die("failure: read_only");
12893 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12894 die("failure: btrfs_set_subvolume_ro");
12895 if (errno != EPERM)
12896 die("failure: errno");
12898 safe_close(snapshot_fd);
12900 exit(EXIT_SUCCESS);
12902 if (wait_for_pid(pid))
12905 /* remove directory */
12906 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12907 log_stderr("failure: btrfs_delete_subvolume");
12911 /* remove directory */
12912 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12913 log_stderr("failure: btrfs_delete_subvolume");
12918 log_debug("Ran test");
12920 safe_close(attr.userns_fd);
12921 safe_close(open_tree_fd);
12922 safe_close(subvolume_fd);
12923 safe_close(tree_fd);
12924 safe_close(userns_fd);
12929 #define BTRFS_SUBVOLUME_SUBVOL1 "subvol1"
12930 #define BTRFS_SUBVOLUME_SUBVOL2 "subvol2"
12931 #define BTRFS_SUBVOLUME_SUBVOL3 "subvol3"
12932 #define BTRFS_SUBVOLUME_SUBVOL4 "subvol4"
12934 #define BTRFS_SUBVOLUME_SUBVOL1_ID 0
12935 #define BTRFS_SUBVOLUME_SUBVOL2_ID 1
12936 #define BTRFS_SUBVOLUME_SUBVOL3_ID 2
12937 #define BTRFS_SUBVOLUME_SUBVOL4_ID 3
12939 #define BTRFS_SUBVOLUME_DIR1 "dir1"
12940 #define BTRFS_SUBVOLUME_DIR2 "dir2"
12942 #define BTRFS_SUBVOLUME_MNT "mnt_subvolume1"
12944 #define BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3 "subvol1/subvol3"
12945 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2 "subvol1/dir1/dir2"
12946 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4 "subvol1/dir1/dir2/subvol4"
12949 * We create the following mount layout to test lookup:
12951 * |-/mnt/test /dev/loop0 btrfs rw,relatime,space_cache,subvolid=5,subvol=/
12952 * | |-/mnt/test/mnt1 /dev/loop1[/subvol1] btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=268,subvol=/subvol1
12953 * '-/mnt/scratch /dev/loop1 btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=5,subvol=/
12955 static int btrfs_subvolume_lookup_user(void)
12958 int dir1_fd = -EBADF, dir2_fd = -EBADF, mnt_fd = -EBADF,
12959 open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
12960 int subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
12961 uint64_t subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
12962 uint64_t subvolid = -EINVAL;
12963 struct mount_attr attr = {
12964 .attr_set = MOUNT_ATTR_IDMAP,
12967 struct btrfs_iter *iter;
12969 if (!caps_supported())
12972 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
12973 subvolume_fds[i] = -EBADF;
12975 for (i = 0; i < ARRAY_SIZE(subvolume_ids); i++)
12976 subvolume_ids[i] = -EINVAL;
12978 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL1)) {
12979 log_stderr("failure: btrfs_create_subvolume");
12983 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL2)) {
12984 log_stderr("failure: btrfs_create_subvolume");
12988 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] = openat(t_mnt_scratch_fd,
12989 BTRFS_SUBVOLUME_SUBVOL1,
12990 O_CLOEXEC | O_DIRECTORY);
12991 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] < 0) {
12992 log_stderr("failure: openat");
12996 /* create subvolume */
12997 if (btrfs_create_subvolume(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_SUBVOL3)) {
12998 log_stderr("failure: btrfs_create_subvolume");
13002 if (mkdirat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1, 0777)) {
13003 log_stderr("failure: mkdirat");
13007 dir1_fd = openat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1,
13008 O_CLOEXEC | O_DIRECTORY);
13010 log_stderr("failure: openat");
13014 if (mkdirat(dir1_fd, BTRFS_SUBVOLUME_DIR2, 0777)) {
13015 log_stderr("failure: mkdirat");
13019 dir2_fd = openat(dir1_fd, BTRFS_SUBVOLUME_DIR2, O_CLOEXEC | O_DIRECTORY);
13021 log_stderr("failure: openat");
13025 if (btrfs_create_subvolume(dir2_fd, BTRFS_SUBVOLUME_SUBVOL4)) {
13026 log_stderr("failure: btrfs_create_subvolume");
13030 if (mkdirat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, 0777)) {
13031 log_stderr("failure: mkdirat");
13035 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13036 if (sys_mount(t_device_scratch, t_buf, "btrfs", 0,
13037 "subvol=" BTRFS_SUBVOLUME_SUBVOL1)) {
13038 log_stderr("failure: mount");
13042 mnt_fd = openat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, O_CLOEXEC | O_DIRECTORY);
13044 log_stderr("failure: openat");
13048 if (chown_r(t_mnt_scratch_fd, ".", 1000, 1000)) {
13049 log_stderr("failure: chown_r");
13053 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] = openat(t_mnt_scratch_fd,
13054 BTRFS_SUBVOLUME_SUBVOL2,
13055 O_CLOEXEC | O_DIRECTORY);
13056 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] < 0) {
13057 log_stderr("failure: openat");
13061 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID],
13062 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL1_ID])) {
13063 log_stderr("failure: btrfs_get_subvolume_id");
13067 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID],
13068 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL2_ID])) {
13069 log_stderr("failure: btrfs_get_subvolume_id");
13073 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] = openat(t_mnt_scratch_fd,
13074 BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3,
13075 O_CLOEXEC | O_DIRECTORY);
13076 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] < 0) {
13077 log_stderr("failure: openat");
13081 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID],
13082 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])) {
13083 log_stderr("failure: btrfs_get_subvolume_id");
13087 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] = openat(t_mnt_scratch_fd,
13088 BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4,
13089 O_CLOEXEC | O_DIRECTORY);
13090 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] < 0) {
13091 log_stderr("failure: openat");
13095 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID],
13096 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])) {
13097 log_stderr("failure: btrfs_get_subvolume_id");
13102 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13103 log_stderr("failure: fchmod");
13107 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13108 log_stderr("failure: fchmod");
13112 attr.userns_fd = get_userns_fd(0, 10000, 10000);
13113 if (attr.userns_fd < 0) {
13114 log_stderr("failure: get_userns_fd");
13118 open_tree_fd = sys_open_tree(mnt_fd, "",
13121 AT_SYMLINK_NOFOLLOW |
13122 OPEN_TREE_CLOEXEC |
13124 if (open_tree_fd < 0) {
13125 log_stderr("failure: sys_open_tree");
13129 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
13130 log_stderr("failure: sys_mount_setattr");
13135 * The open_tree() syscall returns an O_PATH file descriptor which we
13136 * can't use with ioctl(). So let's reopen it as a proper file
13139 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
13141 log_stderr("failure: openat");
13147 log_stderr("failure: fork");
13151 bool subvolume3_found = false, subvolume4_found = false;
13153 if (!switch_fsids(11000, 11000))
13154 die("failure: switch fsids");
13157 die("failure: lower caps");
13159 if (btrfs_iterator_start(tree_fd, 0, &iter))
13160 die("failure: btrfs_iterator_start");
13163 char *subvol_path = NULL;
13166 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13170 die("failure: btrfs_iterator_next");
13172 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13173 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13174 die("failure: subvolume id %llu->%s",
13175 (long long unsigned)subvolid, subvol_path);
13177 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13178 subvolume3_found = true;
13180 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13181 subvolume4_found = true;
13185 btrfs_iterator_end(iter);
13187 if (!subvolume3_found || !subvolume4_found)
13188 die("failure: subvolume id");
13190 exit(EXIT_SUCCESS);
13192 if (wait_for_pid(pid))
13197 log_stderr("failure: fork");
13201 bool subvolume3_found = false, subvolume4_found = false;
13203 if (!switch_userns(attr.userns_fd, 0, 0, false))
13204 die("failure: switch_userns");
13206 if (btrfs_iterator_start(tree_fd, 0, &iter))
13207 die("failure: btrfs_iterator_start");
13210 char *subvol_path = NULL;
13213 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13217 die("failure: btrfs_iterator_next");
13219 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13220 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13221 die("failure: subvolume id %llu->%s",
13222 (long long unsigned)subvolid, subvol_path);
13224 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13225 subvolume3_found = true;
13227 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13228 subvolume4_found = true;
13232 btrfs_iterator_end(iter);
13234 if (!subvolume3_found || !subvolume4_found)
13235 die("failure: subvolume id");
13237 exit(EXIT_SUCCESS);
13239 if (wait_for_pid(pid))
13244 log_stderr("failure: fork");
13248 bool subvolume_found = false;
13250 if (!switch_fsids(0, 0))
13251 die("failure: switch fsids");
13254 die("failure: lower caps");
13256 if (btrfs_iterator_start(tree_fd, 0, &iter))
13257 die("failure: btrfs_iterator_start");
13260 char *subvol_path = NULL;
13263 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13267 die("failure: btrfs_iterator_next");
13271 subvolume_found = true;
13274 btrfs_iterator_end(iter);
13276 if (subvolume_found)
13277 die("failure: subvolume id");
13279 exit(EXIT_SUCCESS);
13281 if (wait_for_pid(pid))
13284 userns_fd = get_userns_fd(0, 30000, 10000);
13285 if (userns_fd < 0) {
13286 log_stderr("failure: get_userns_fd");
13292 log_stderr("failure: fork");
13296 bool subvolume_found = false;
13298 if (!switch_userns(userns_fd, 0, 0, true))
13299 die("failure: switch_userns");
13301 if (btrfs_iterator_start(tree_fd, 0, &iter))
13302 die("failure: btrfs_iterator_start");
13305 char *subvol_path = NULL;
13308 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13312 die("failure: btrfs_iterator_next");
13316 subvolume_found = true;
13319 btrfs_iterator_end(iter);
13321 if (subvolume_found)
13322 die("failure: subvolume id");
13324 exit(EXIT_SUCCESS);
13326 if (wait_for_pid(pid))
13330 log_debug("Ran test");
13332 safe_close(dir1_fd);
13333 safe_close(dir2_fd);
13334 safe_close(open_tree_fd);
13335 safe_close(tree_fd);
13336 safe_close(userns_fd);
13337 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
13338 safe_close(subvolume_fds[i]);
13339 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13340 sys_umount2(t_buf, MNT_DETACH);
13341 unlinkat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, AT_REMOVEDIR);
13346 #define USER1 "fsgqa"
13347 #define USER2 "fsgqa2"
13350 * lookup_ids - lookup uid and gid for a username
13351 * @name: [in] name of the user
13352 * @uid: [out] pointer to the user-ID
13353 * @gid: [out] pointer to the group-ID
13355 * Lookup the uid and gid of a user.
13357 * Return: On success, true is returned.
13358 * On error, false is returned.
13360 static bool lookup_ids(const char *name, uid_t *uid, gid_t *gid)
13363 struct passwd *pwentp = NULL;
13364 struct passwd pwent;
13369 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
13373 buf = malloc(bufsize);
13377 ret = getpwnam_r(name, &pwent, buf, bufsize, &pwentp);
13378 if (!ret && pwentp) {
13379 *uid = pwent.pw_uid;
13380 *gid = pwent.pw_gid;
13389 * setattr_fix_968219708108 - test for commit 968219708108 ("fs: handle circular mappings correctly")
13391 * Test that ->setattr() works correctly for idmapped mounts with circular
13392 * idmappings such as:
13397 * Assume a directory /source with two files:
13399 * /source/file1 | 1000:1000
13400 * /source/file2 | 1001:1001
13402 * and we create an idmapped mount of /source at /target with an idmapped of:
13404 * mnt_userns: 1000:1001:1
13407 * In the idmapped mount file1 will be owned by uid 1001 and file2 by uid 1000:
13409 * /target/file1 | 1001:1001
13410 * /target/file2 | 1000:1000
13412 * Because in essence the idmapped mount switches ownership for {g,u}id 1000
13413 * and {g,u}id 1001.
13415 * 1. A user with fs{g,u}id 1000 must be allowed to setattr /target/file2 from
13416 * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
13417 * 2. A user with fs{g,u}id 1001 must be allowed to setattr /target/file1 from
13418 * {g,u}id 1001 in the idmapped mount to {g,u}id 1001.
13419 * 3. A user with fs{g,u}id 1000 must fail to setattr /target/file1 from
13420 * {g,u}id 1001 in the idmapped mount to {g,u}id 1000.
13421 * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
13422 * {g,u}id of the file.
13423 * 4. A user with fs{g,u}id 1001 must fail to setattr /target/file2 from
13424 * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
13425 * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
13426 * {g,u}id of the file.
13427 * 5. Both, a user with fs{g,u}id 1000 and a user with fs{g,u}id 1001, must
13428 * fail to setattr /target/file1 owned by {g,u}id 1001 in the idmapped mount
13429 * and /target/file2 owned by {g,u}id 1000 in the idmapped mount to any
13430 * {g,u}id apart from {g,u}id 1000 or 1001 with EINVAL.
13431 * Only {g,u}id 1000 and 1001 have a mapping in the idmapped mount. Other
13432 * {g,u}id are unmapped.
13434 static int setattr_fix_968219708108(void)
13437 int open_tree_fd = -EBADF;
13438 struct mount_attr attr = {
13439 .attr_set = MOUNT_ATTR_IDMAP,
13440 .userns_fd = -EBADF,
13443 uid_t user1_uid, user2_uid;
13444 gid_t user1_gid, user2_gid;
13447 struct list *it_cur, *it_next;
13449 if (!caps_supported())
13454 if (!lookup_ids(USER1, &user1_uid, &user1_gid)) {
13455 log_stderr("failure: lookup_user");
13459 if (!lookup_ids(USER2, &user2_uid, &user2_gid)) {
13460 log_stderr("failure: lookup_user");
13464 log_debug("Found " USER1 " with uid(%d) and gid(%d) and " USER2 " with uid(%d) and gid(%d)",
13465 user1_uid, user1_gid, user2_uid, user2_gid);
13467 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
13468 log_stderr("failure: mkdirat");
13472 if (mknodat(t_dir1_fd, DIR1 "/" FILE1, S_IFREG | 0644, 0)) {
13473 log_stderr("failure: mknodat");
13477 if (chown_r(t_mnt_fd, T_DIR1, user1_uid, user1_gid)) {
13478 log_stderr("failure: chown_r");
13482 if (mknodat(t_dir1_fd, DIR1 "/" FILE2, S_IFREG | 0644, 0)) {
13483 log_stderr("failure: mknodat");
13487 if (fchownat(t_dir1_fd, DIR1 "/" FILE2, user2_uid, user2_gid, AT_SYMLINK_NOFOLLOW)) {
13488 log_stderr("failure: fchownat");
13492 print_r(t_mnt_fd, T_DIR1);
13494 /* u:1000:1001:1 */
13495 ret = add_map_entry(&idmap, user1_uid, user2_uid, 1, ID_TYPE_UID);
13497 log_stderr("failure: add_map_entry");
13501 /* u:1001:1000:1 */
13502 ret = add_map_entry(&idmap, user2_uid, user1_uid, 1, ID_TYPE_UID);
13504 log_stderr("failure: add_map_entry");
13508 /* g:1000:1001:1 */
13509 ret = add_map_entry(&idmap, user1_gid, user2_gid, 1, ID_TYPE_GID);
13511 log_stderr("failure: add_map_entry");
13515 /* g:1001:1000:1 */
13516 ret = add_map_entry(&idmap, user2_gid, user1_gid, 1, ID_TYPE_GID);
13518 log_stderr("failure: add_map_entry");
13522 attr.userns_fd = get_userns_fd_from_idmap(&idmap);
13523 if (attr.userns_fd < 0) {
13524 log_stderr("failure: get_userns_fd");
13528 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
13530 AT_SYMLINK_NOFOLLOW |
13531 OPEN_TREE_CLOEXEC |
13534 if (open_tree_fd < 0) {
13535 log_stderr("failure: sys_open_tree");
13539 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
13540 log_stderr("failure: sys_mount_setattr");
13544 print_r(open_tree_fd, "");
13548 log_stderr("failure: fork");
13552 /* switch to {g,u}id 1001 */
13553 if (!switch_resids(user2_uid, user2_gid))
13554 die("failure: switch_resids");
13556 /* drop all capabilities */
13558 die("failure: caps_down");
13561 * The {g,u}id 0 is not mapped in this idmapped mount so this
13562 * needs to fail with EINVAL.
13564 if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
13565 die("failure: change ownership");
13566 if (errno != EINVAL)
13567 die("failure: errno");
13570 * A user with fs{g,u}id 1001 must be allowed to change
13571 * ownership of /target/file1 owned by {g,u}id 1001 in this
13572 * idmapped mount to {g,u}id 1001.
13574 if (fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
13575 AT_SYMLINK_NOFOLLOW))
13576 die("failure: change ownership");
13578 /* Verify that the ownership is still {g,u}id 1001. */
13579 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13580 user2_uid, user2_gid))
13581 die("failure: check ownership");
13584 * A user with fs{g,u}id 1001 must not be allowed to change
13585 * ownership of /target/file1 owned by {g,u}id 1001 in this
13586 * idmapped mount to {g,u}id 1000.
13588 if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
13589 AT_SYMLINK_NOFOLLOW))
13590 die("failure: change ownership");
13591 if (errno != EPERM)
13592 die("failure: errno");
13594 /* Verify that the ownership is still {g,u}id 1001. */
13595 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13596 user2_uid, user2_gid))
13597 die("failure: check ownership");
13600 * A user with fs{g,u}id 1001 must not be allowed to change
13601 * ownership of /target/file2 owned by {g,u}id 1000 in this
13602 * idmapped mount to {g,u}id 1000.
13604 if (!fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
13605 AT_SYMLINK_NOFOLLOW))
13606 die("failure: change ownership");
13607 if (errno != EPERM)
13608 die("failure: errno");
13610 /* Verify that the ownership is still {g,u}id 1000. */
13611 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13612 user1_uid, user1_gid))
13613 die("failure: check ownership");
13616 * A user with fs{g,u}id 1001 must not be allowed to change
13617 * ownership of /target/file2 owned by {g,u}id 1000 in this
13618 * idmapped mount to {g,u}id 1001.
13620 if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
13621 AT_SYMLINK_NOFOLLOW))
13622 die("failure: change ownership");
13623 if (errno != EPERM)
13624 die("failure: errno");
13626 /* Verify that the ownership is still {g,u}id 1000. */
13627 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13628 user1_uid, user1_gid))
13629 die("failure: check ownership");
13631 exit(EXIT_SUCCESS);
13633 if (wait_for_pid(pid))
13638 log_stderr("failure: fork");
13642 /* switch to {g,u}id 1000 */
13643 if (!switch_resids(user1_uid, user1_gid))
13644 die("failure: switch_resids");
13646 /* drop all capabilities */
13648 die("failure: caps_down");
13651 * The {g,u}id 0 is not mapped in this idmapped mount so this
13652 * needs to fail with EINVAL.
13654 if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
13655 die("failure: change ownership");
13656 if (errno != EINVAL)
13657 die("failure: errno");
13660 * A user with fs{g,u}id 1000 must be allowed to change
13661 * ownership of /target/file2 owned by {g,u}id 1000 in this
13662 * idmapped mount to {g,u}id 1000.
13664 if (fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
13665 AT_SYMLINK_NOFOLLOW))
13666 die("failure: change ownership");
13668 /* Verify that the ownership is still {g,u}id 1000. */
13669 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13670 user1_uid, user1_gid))
13671 die("failure: check ownership");
13674 * A user with fs{g,u}id 1000 must not be allowed to change
13675 * ownership of /target/file2 owned by {g,u}id 1000 in this
13676 * idmapped mount to {g,u}id 1001.
13678 if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
13679 AT_SYMLINK_NOFOLLOW))
13680 die("failure: change ownership");
13681 if (errno != EPERM)
13682 die("failure: errno");
13684 /* Verify that the ownership is still {g,u}id 1000. */
13685 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13686 user1_uid, user1_gid))
13687 die("failure: check ownership");
13690 * A user with fs{g,u}id 1000 must not be allowed to change
13691 * ownership of /target/file1 owned by {g,u}id 1001 in this
13692 * idmapped mount to {g,u}id 1000.
13694 if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
13695 AT_SYMLINK_NOFOLLOW))
13696 die("failure: change ownership");
13697 if (errno != EPERM)
13698 die("failure: errno");
13700 /* Verify that the ownership is still {g,u}id 1001. */
13701 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13702 user2_uid, user2_gid))
13703 die("failure: check ownership");
13706 * A user with fs{g,u}id 1000 must not be allowed to change
13707 * ownership of /target/file1 owned by {g,u}id 1001 in this
13708 * idmapped mount to {g,u}id 1001.
13710 if (!fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
13711 AT_SYMLINK_NOFOLLOW))
13712 die("failure: change ownership");
13713 if (errno != EPERM)
13714 die("failure: errno");
13716 /* Verify that the ownership is still {g,u}id 1001. */
13717 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13718 user2_uid, user2_gid))
13719 die("failure: check ownership");
13721 exit(EXIT_SUCCESS);
13723 if (wait_for_pid(pid))
13727 log_debug("Ran test");
13729 safe_close(attr.userns_fd);
13730 safe_close(open_tree_fd);
13732 list_for_each_safe(it_cur, &idmap, it_next) {
13734 free(it_cur->elem);
13741 static void usage(void)
13743 fprintf(stderr, "Description:\n");
13744 fprintf(stderr, " Run idmapped mount tests\n\n");
13746 fprintf(stderr, "Arguments:\n");
13747 fprintf(stderr, "--device Device used in the tests\n");
13748 fprintf(stderr, "--fstype Filesystem type used in the tests\n");
13749 fprintf(stderr, "--help Print help\n");
13750 fprintf(stderr, "--mountpoint Mountpoint of device\n");
13751 fprintf(stderr, "--supported Test whether idmapped mounts are supported on this filesystem\n");
13752 fprintf(stderr, "--scratch-mountpoint Mountpoint of scratch device used in the tests\n");
13753 fprintf(stderr, "--scratch-device Scratch device used in the tests\n");
13754 fprintf(stderr, "--test-core Run core idmapped mount testsuite\n");
13755 fprintf(stderr, "--test-fscaps-regression Run fscap regression tests\n");
13756 fprintf(stderr, "--test-nested-userns Run nested userns idmapped mount testsuite\n");
13757 fprintf(stderr, "--test-btrfs Run btrfs specific idmapped mount testsuite\n");
13758 fprintf(stderr, "--test-setattr-fix-968219708108 Run setattr regression tests\n");
13760 _exit(EXIT_SUCCESS);
13763 static const struct option longopts[] = {
13764 {"device", required_argument, 0, 'd'},
13765 {"fstype", required_argument, 0, 'f'},
13766 {"mountpoint", required_argument, 0, 'm'},
13767 {"scratch-mountpoint", required_argument, 0, 'a'},
13768 {"scratch-device", required_argument, 0, 'e'},
13769 {"supported", no_argument, 0, 's'},
13770 {"help", no_argument, 0, 'h'},
13771 {"test-core", no_argument, 0, 'c'},
13772 {"test-fscaps-regression", no_argument, 0, 'g'},
13773 {"test-nested-userns", no_argument, 0, 'n'},
13774 {"test-btrfs", no_argument, 0, 'b'},
13775 {"test-setattr-fix-968219708108", no_argument, 0, 'i'},
13779 struct t_idmapped_mounts {
13781 const char *description;
13782 } basic_suite[] = {
13783 { acls, "posix acls on regular mounts", },
13784 { create_in_userns, "create operations in user namespace", },
13785 { device_node_in_userns, "device node in user namespace", },
13786 { expected_uid_gid_idmapped_mounts, "expected ownership on idmapped mounts", },
13787 { fscaps, "fscaps on regular mounts", },
13788 { fscaps_idmapped_mounts, "fscaps on idmapped mounts", },
13789 { fscaps_idmapped_mounts_in_userns, "fscaps on idmapped mounts in user namespace", },
13790 { fscaps_idmapped_mounts_in_userns_separate_userns, "fscaps on idmapped mounts in user namespace with different id mappings", },
13791 { fsids_mapped, "mapped fsids", },
13792 { fsids_unmapped, "unmapped fsids", },
13793 { hardlink_crossing_mounts, "cross mount hardlink", },
13794 { hardlink_crossing_idmapped_mounts, "cross idmapped mount hardlink", },
13795 { hardlink_from_idmapped_mount, "hardlinks from idmapped mounts", },
13796 { hardlink_from_idmapped_mount_in_userns, "hardlinks from idmapped mounts in user namespace", },
13797 #ifdef HAVE_LIBURING_H
13798 { io_uring, "io_uring", },
13799 { io_uring_userns, "io_uring in user namespace", },
13800 { io_uring_idmapped, "io_uring from idmapped mounts", },
13801 { io_uring_idmapped_userns, "io_uring from idmapped mounts in user namespace", },
13802 { io_uring_idmapped_unmapped, "io_uring from idmapped mounts with unmapped ids", },
13803 { io_uring_idmapped_unmapped_userns, "io_uring from idmapped mounts with unmapped ids in user namespace", },
13805 { protected_symlinks, "following protected symlinks on regular mounts", },
13806 { protected_symlinks_idmapped_mounts, "following protected symlinks on idmapped mounts", },
13807 { protected_symlinks_idmapped_mounts_in_userns, "following protected symlinks on idmapped mounts in user namespace", },
13808 { rename_crossing_mounts, "cross mount rename", },
13809 { rename_crossing_idmapped_mounts, "cross idmapped mount rename", },
13810 { rename_from_idmapped_mount, "rename from idmapped mounts", },
13811 { rename_from_idmapped_mount_in_userns, "rename from idmapped mounts in user namespace", },
13812 { setattr_truncate, "setattr truncate", },
13813 { setattr_truncate_idmapped, "setattr truncate on idmapped mounts", },
13814 { setattr_truncate_idmapped_in_userns, "setattr truncate on idmapped mounts in user namespace", },
13815 { setgid_create, "create operations in directories with setgid bit set", },
13816 { setgid_create_idmapped, "create operations in directories with setgid bit set on idmapped mounts", },
13817 { setgid_create_idmapped_in_userns, "create operations in directories with setgid bit set on idmapped mounts in user namespace", },
13818 { setid_binaries, "setid binaries on regular mounts", },
13819 { setid_binaries_idmapped_mounts, "setid binaries on idmapped mounts", },
13820 { setid_binaries_idmapped_mounts_in_userns, "setid binaries on idmapped mounts in user namespace", },
13821 { setid_binaries_idmapped_mounts_in_userns_separate_userns, "setid binaries on idmapped mounts in user namespace with different id mappings", },
13822 { sticky_bit_unlink, "sticky bit unlink operations on regular mounts", },
13823 { sticky_bit_unlink_idmapped_mounts, "sticky bit unlink operations on idmapped mounts", },
13824 { sticky_bit_unlink_idmapped_mounts_in_userns, "sticky bit unlink operations on idmapped mounts in user namespace", },
13825 { sticky_bit_rename, "sticky bit rename operations on regular mounts", },
13826 { sticky_bit_rename_idmapped_mounts, "sticky bit rename operations on idmapped mounts", },
13827 { sticky_bit_rename_idmapped_mounts_in_userns, "sticky bit rename operations on idmapped mounts in user namespace", },
13828 { symlink_regular_mounts, "symlink from regular mounts", },
13829 { symlink_idmapped_mounts, "symlink from idmapped mounts", },
13830 { symlink_idmapped_mounts_in_userns, "symlink from idmapped mounts in user namespace", },
13831 { threaded_idmapped_mount_interactions, "threaded operations on idmapped mounts", },
13834 struct t_idmapped_mounts fscaps_in_ancestor_userns[] = {
13835 { fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns, "fscaps on idmapped mounts in user namespace writing fscap valid in ancestor userns", },
13838 struct t_idmapped_mounts t_nested_userns[] = {
13839 { nested_userns, "test that nested user namespaces behave correctly when attached to idmapped mounts", },
13842 struct t_idmapped_mounts t_btrfs[] = {
13843 { btrfs_subvolumes_fsids_mapped, "test subvolumes with mapped fsids", },
13844 { btrfs_subvolumes_fsids_mapped_userns, "test subvolumes with mapped fsids inside user namespace", },
13845 { btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed, "test subvolume deletion with user_subvol_rm_allowed mount option", },
13846 { btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed, "test subvolume deletion with user_subvol_rm_allowed mount option inside user namespace", },
13847 { btrfs_subvolumes_fsids_unmapped, "test subvolumes with unmapped fsids", },
13848 { btrfs_subvolumes_fsids_unmapped_userns, "test subvolumes with unmapped fsids inside user namespace", },
13849 { btrfs_snapshots_fsids_mapped, "test snapshots with mapped fsids", },
13850 { btrfs_snapshots_fsids_mapped_userns, "test snapshots with mapped fsids inside user namespace", },
13851 { btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed, "test snapshots deletion with user_subvol_rm_allowed mount option", },
13852 { btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed, "test snapshots deletion with user_subvol_rm_allowed mount option inside user namespace", },
13853 { btrfs_snapshots_fsids_unmapped, "test snapshots with unmapped fsids", },
13854 { btrfs_snapshots_fsids_unmapped_userns, "test snapshots with unmapped fsids inside user namespace", },
13855 { btrfs_delete_by_spec_id, "test subvolume deletion by spec id", },
13856 { btrfs_subvolumes_setflags_fsids_mapped, "test subvolume flags with mapped fsids", },
13857 { btrfs_subvolumes_setflags_fsids_mapped_userns, "test subvolume flags with mapped fsids inside user namespace", },
13858 { btrfs_subvolumes_setflags_fsids_unmapped, "test subvolume flags with unmapped fsids", },
13859 { btrfs_subvolumes_setflags_fsids_unmapped_userns, "test subvolume flags with unmapped fsids inside user namespace", },
13860 { btrfs_snapshots_setflags_fsids_mapped, "test snapshots flags with mapped fsids", },
13861 { btrfs_snapshots_setflags_fsids_mapped_userns, "test snapshots flags with mapped fsids inside user namespace", },
13862 { btrfs_snapshots_setflags_fsids_unmapped, "test snapshots flags with unmapped fsids", },
13863 { btrfs_snapshots_setflags_fsids_unmapped_userns, "test snapshots flags with unmapped fsids inside user namespace", },
13864 { btrfs_subvolume_lookup_user, "test unprivileged subvolume lookup", },
13867 /* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */
13868 struct t_idmapped_mounts t_setattr_fix_968219708108[] = {
13869 { setattr_fix_968219708108, "test that setattr works correctly", },
13872 static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size)
13876 for (i = 0; i < suite_size; i++) {
13877 struct t_idmapped_mounts *t = &suite[i];
13890 die("failure: %s", t->description);
13892 exit(EXIT_SUCCESS);
13895 ret = wait_for_pid(pid);
13905 int main(int argc, char *argv[])
13909 bool supported = false, test_btrfs = false, test_core = false,
13910 test_fscaps_regression = false, test_nested_userns = false,
13911 test_setattr_fix_968219708108 = false;
13913 while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) {
13922 t_mountpoint = optarg;
13931 test_fscaps_regression = true;
13934 test_nested_userns = true;
13940 t_mountpoint_scratch = optarg;
13943 t_device_scratch = optarg;
13946 test_setattr_fix_968219708108 = true;
13956 die_errno(EINVAL, "test device missing");
13959 die_errno(EINVAL, "test filesystem type missing");
13962 die_errno(EINVAL, "mountpoint of test device missing");
13964 /* create separate mount namespace */
13965 if (unshare(CLONE_NEWNS))
13966 die("failure: create new mount namespace");
13968 /* turn off mount propagation */
13969 if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
13970 die("failure: turn mount propagation off");
13972 t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
13974 die("failed to open %s", t_mountpoint);
13976 t_mnt_scratch_fd = openat(-EBADF, t_mountpoint_scratch, O_CLOEXEC | O_DIRECTORY);
13978 die("failed to open %s", t_mountpoint_scratch);
13981 * Caller just wants to know whether the filesystem we're on supports
13985 int open_tree_fd = -EBADF;
13986 struct mount_attr attr = {
13987 .attr_set = MOUNT_ATTR_IDMAP,
13988 .userns_fd = -EBADF,
13991 /* Changing mount properties on a detached mount. */
13992 attr.userns_fd = get_userns_fd(0, 1000, 1);
13993 if (attr.userns_fd < 0)
13994 exit(EXIT_FAILURE);
13996 open_tree_fd = sys_open_tree(t_mnt_fd, "",
13999 AT_SYMLINK_NOFOLLOW |
14000 OPEN_TREE_CLOEXEC |
14002 if (open_tree_fd < 0)
14005 ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr));
14007 close(open_tree_fd);
14008 close(attr.userns_fd);
14011 exit(EXIT_FAILURE);
14013 exit(EXIT_SUCCESS);
14016 stash_overflowuid();
14017 stash_overflowgid();
14019 fret = EXIT_FAILURE;
14021 if (test_core && !run_test(basic_suite, ARRAY_SIZE(basic_suite)))
14024 if (test_fscaps_regression &&
14025 !run_test(fscaps_in_ancestor_userns,
14026 ARRAY_SIZE(fscaps_in_ancestor_userns)))
14029 if (test_nested_userns &&
14030 !run_test(t_nested_userns, ARRAY_SIZE(t_nested_userns)))
14033 if (test_btrfs && !run_test(t_btrfs, ARRAY_SIZE(t_btrfs)))
14036 if (test_setattr_fix_968219708108 &&
14037 !run_test(t_setattr_fix_968219708108,
14038 ARRAY_SIZE(t_setattr_fix_968219708108)))
14041 fret = EXIT_SUCCESS;