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 /* whether the underlying filesystem supports idmapped mounts */
129 bool t_fs_allow_idmap;
131 static void stash_overflowuid(void)
137 fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
141 ret = read(fd, buf, sizeof(buf));
146 t_overflowuid = atoi(buf);
149 static void stash_overflowgid(void)
155 fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
159 ret = read(fd, buf, sizeof(buf));
164 t_overflowgid = atoi(buf);
167 static bool is_xfs(void)
169 static int enabled = -1;
172 enabled = !strcmp(t_fstype, "xfs");
177 static bool protected_symlinks_enabled(void)
179 static int enabled = -1;
188 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
192 ret = read(fd, buf, sizeof(buf));
204 static bool xfs_irix_sgid_inherit_enabled(void)
206 static int enabled = -1;
216 fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
220 ret = read(fd, buf, sizeof(buf));
233 static inline bool caps_supported(void)
237 #ifdef HAVE_SYS_CAPABILITY_H
244 /* caps_down - lower all effective caps */
245 static int caps_down(void)
248 #ifdef HAVE_SYS_CAPABILITY_H
252 caps = cap_get_proc();
256 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
260 ret = cap_set_proc(caps);
272 /* caps_up - raise all permitted caps */
273 static int caps_up(void)
276 #ifdef HAVE_SYS_CAPABILITY_H
281 caps = cap_get_proc();
285 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
286 cap_flag_value_t flag;
288 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
296 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
301 ret = cap_set_proc(caps);
312 /* __expected_uid_gid - check whether file is owned by the provided uid and gid */
313 static bool __expected_uid_gid(int dfd, const char *path, int flags,
314 uid_t expected_uid, gid_t expected_gid, bool log)
319 ret = fstatat(dfd, path, &st, flags);
321 return log_errno(false, "failure: fstatat");
323 if (log && st.st_uid != expected_uid)
324 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
326 if (log && st.st_gid != expected_gid)
327 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
329 errno = 0; /* Don't report misleading errno. */
330 return st.st_uid == expected_uid && st.st_gid == expected_gid;
333 static bool expected_uid_gid(int dfd, const char *path, int flags,
334 uid_t expected_uid, gid_t expected_gid)
336 return __expected_uid_gid(dfd, path, flags,
337 expected_uid, expected_gid, true);
340 static bool expected_file_size(int dfd, const char *path,
341 int flags, off_t expected_size)
346 ret = fstatat(dfd, path, &st, flags);
348 return log_errno(false, "failure: fstatat");
350 if (st.st_size != expected_size)
351 return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)",
352 (size_t)st.st_size, (size_t)expected_size);
357 /* is_setid - check whether file is S_ISUID and S_ISGID */
358 static bool is_setid(int dfd, const char *path, int flags)
363 ret = fstatat(dfd, path, &st, flags);
367 errno = 0; /* Don't report misleading errno. */
368 return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
371 /* is_setgid - check whether file or directory is S_ISGID */
372 static bool is_setgid(int dfd, const char *path, int flags)
377 ret = fstatat(dfd, path, &st, flags);
381 errno = 0; /* Don't report misleading errno. */
382 return (st.st_mode & S_ISGID);
385 /* is_sticky - check whether file is S_ISVTX */
386 static bool is_sticky(int dfd, const char *path, int flags)
391 ret = fstatat(dfd, path, &st, flags);
395 errno = 0; /* Don't report misleading errno. */
396 return (st.st_mode & S_ISVTX) > 0;
399 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
402 return log_errno(false, "failure: setfsgid");
404 if (setfsgid(-1) != fsgid)
405 return log_errno(false, "failure: setfsgid(-1)");
408 return log_errno(false, "failure: setfsuid");
410 if (setfsuid(-1) != fsuid)
411 return log_errno(false, "failure: setfsuid(-1)");
416 static inline bool switch_resids(uid_t uid, gid_t gid)
418 if (setresgid(gid, gid, gid))
419 return log_errno(false, "failure: setregid");
421 if (setresuid(uid, uid, uid))
422 return log_errno(false, "failure: setresuid");
424 if (setfsgid(-1) != gid)
425 return log_errno(false, "failure: setfsgid(-1)");
427 if (setfsuid(-1) != uid)
428 return log_errno(false, "failure: setfsuid(-1)");
433 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
435 if (setns(fd, CLONE_NEWUSER))
436 return log_errno(false, "failure: setns");
438 if (!switch_ids(uid, gid))
439 return log_errno(false, "failure: switch_ids");
441 if (drop_caps && !caps_down())
442 return log_errno(false, "failure: caps_down");
447 /* rm_r - recursively remove all files */
448 static int rm_r(int fd, const char *path)
452 struct dirent *direntp;
454 if (!path || strcmp(path, "") == 0)
457 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
461 dir = fdopendir(dfd);
467 while ((direntp = readdir(dir))) {
470 if (!strcmp(direntp->d_name, ".") ||
471 !strcmp(direntp->d_name, ".."))
474 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
475 if (ret < 0 && errno != ENOENT)
478 if (S_ISDIR(st.st_mode))
479 ret = rm_r(dfd, direntp->d_name);
481 ret = unlinkat(dfd, direntp->d_name, 0);
482 if (ret < 0 && errno != ENOENT)
486 ret = unlinkat(fd, path, AT_REMOVEDIR);
491 /* chown_r - recursively change ownership of all files */
492 static int chown_r(int fd, const char *path, uid_t uid, gid_t gid)
496 struct dirent *direntp;
498 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
502 dir = fdopendir(dfd);
508 while ((direntp = readdir(dir))) {
511 if (!strcmp(direntp->d_name, ".") ||
512 !strcmp(direntp->d_name, ".."))
515 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
516 if (ret < 0 && errno != ENOENT)
519 if (S_ISDIR(st.st_mode))
520 ret = chown_r(dfd, direntp->d_name, uid, gid);
522 ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
523 if (ret < 0 && errno != ENOENT)
527 ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
533 * There'll be scenarios where you'll want to see the attributes associated with
534 * a directory tree during debugging or just to make sure things look correct.
535 * Simply uncomment and place the print_r() helper where you need it.
538 static int fd_cloexec(int fd, bool cloexec)
542 oflags = fcntl(fd, F_GETFD, 0);
547 nflags = oflags | FD_CLOEXEC;
549 nflags = oflags & ~FD_CLOEXEC;
551 if (nflags == oflags)
554 if (fcntl(fd, F_SETFD, nflags) < 0)
560 static inline int dup_cloexec(int fd)
568 if (fd_cloexec(fd_dup, true)) {
576 __attribute__((unused)) static int print_r(int fd, const char *path)
581 struct dirent *direntp;
584 if (!path || *path == '\0') {
585 char buf[sizeof("/proc/self/fd/") + 30];
587 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
588 if (ret < 0 || (size_t)ret >= sizeof(buf))
592 * O_PATH file descriptors can't be used so we need to re-open
595 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
597 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
603 * When fdopendir() below succeeds it assumes ownership of the fd so we
604 * to make sure we always have an fd that fdopendir() can own which is
605 * why we dup() in the case where the caller wants us to operate on the
608 dfd_dup = dup_cloexec(dfd);
614 dir = fdopendir(dfd);
620 /* Transfer ownership to fdopendir(). */
623 while ((direntp = readdir(dir))) {
624 if (!strcmp(direntp->d_name, ".") ||
625 !strcmp(direntp->d_name, ".."))
628 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
629 if (ret < 0 && errno != ENOENT)
633 if (S_ISDIR(st.st_mode))
634 ret = print_r(dfd_dup, direntp->d_name);
636 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n",
637 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
638 dfd_dup, direntp->d_name);
639 if (ret < 0 && errno != ENOENT)
643 if (!path || *path == '\0')
644 ret = fstatat(fd, "", &st,
645 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
648 ret = fstatat(fd, path, &st,
649 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
651 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n",
652 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
653 (path && *path) ? path : "(null)");
661 __attribute__((unused)) static int print_r(int fd, const char *path)
667 /* fd_to_fd - transfer data from one fd to another */
668 static int fd_to_fd(int from, int to)
671 uint8_t buf[PATH_MAX];
673 ssize_t bytes_to_write;
676 bytes_read = read_nointr(from, buf, sizeof buf);
682 bytes_to_write = (size_t)bytes_read;
684 ssize_t bytes_written;
686 bytes_written = write_nointr(to, p, bytes_to_write);
687 if (bytes_written < 0)
690 bytes_to_write -= bytes_written;
692 } while (bytes_to_write > 0);
698 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
702 return syscall(__NR_execveat, fd, path, argv, envp, flags);
710 #define CAP_NET_RAW 13
713 #ifndef VFS_CAP_FLAGS_EFFECTIVE
714 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
717 #ifndef VFS_CAP_U32_3
718 #define VFS_CAP_U32_3 2
722 #define VFS_CAP_U32 VFS_CAP_U32_3
725 #ifndef VFS_CAP_REVISION_1
726 #define VFS_CAP_REVISION_1 0x01000000
729 #ifndef VFS_CAP_REVISION_2
730 #define VFS_CAP_REVISION_2 0x02000000
733 #ifndef VFS_CAP_REVISION_3
734 #define VFS_CAP_REVISION_3 0x03000000
735 struct vfs_ns_cap_data {
745 #if __BYTE_ORDER == __BIG_ENDIAN
746 #define cpu_to_le16(w16) le16_to_cpu(w16)
747 #define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
748 #define cpu_to_le32(w32) le32_to_cpu(w32)
749 #define le32_to_cpu(w32) \
750 ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
751 (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
752 #elif __BYTE_ORDER == __LITTLE_ENDIAN
753 #define cpu_to_le16(w16) ((u_int16_t)(w16))
754 #define le16_to_cpu(w16) ((u_int16_t)(w16))
755 #define cpu_to_le32(w32) ((u_int32_t)(w32))
756 #define le32_to_cpu(w32) ((u_int32_t)(w32))
758 #error Expected endianess macro to be set
761 /* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */
762 static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid)
764 #define __cap_raised_permitted(x, ns_cap_data) \
765 ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31)))
766 struct vfs_ns_cap_data ns_xattr = {};
769 ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
770 if (ret < 0 || ret == 0)
773 if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
775 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
777 log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
780 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
781 (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
783 log_stderr("failure: fscaps version");
789 /* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */
790 static int set_dummy_vfs_caps(int fd, int flags, int rootuid)
792 #define __raise_cap_permitted(x, ns_cap_data) \
793 ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
795 struct vfs_ns_cap_data ns_xattr;
797 memset(&ns_xattr, 0, sizeof(ns_xattr));
798 __raise_cap_permitted(CAP_NET_RAW, ns_xattr);
799 ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
800 ns_xattr.rootid = cpu_to_le32(rootuid);
802 return fsetxattr(fd, "security.capability",
803 &ns_xattr, sizeof(ns_xattr), flags);
806 #define safe_close(fd) \
814 static void test_setup(void)
816 if (mkdirat(t_mnt_fd, T_DIR1, 0777))
817 die("failure: mkdirat");
819 t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
821 die("failure: openat");
823 if (fchmod(t_dir1_fd, 0777))
824 die("failure: fchmod");
827 static void test_cleanup(void)
829 safe_close(t_dir1_fd);
830 if (rm_r(t_mnt_fd, T_DIR1))
831 die("failure: rm_r");
834 /* Validate that basic file operations on idmapped mounts. */
835 static int fsids_unmapped(void)
838 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
839 struct mount_attr attr = {
840 .attr_set = MOUNT_ATTR_IDMAP,
843 /* create hardlink target */
844 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
845 if (hardlink_target_fd < 0) {
846 log_stderr("failure: openat");
850 /* create directory for rename test */
851 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
852 log_stderr("failure: mkdirat");
856 /* change ownership of all files to uid 0 */
857 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
858 log_stderr("failure: chown_r");
862 /* Changing mount properties on a detached mount. */
863 attr.userns_fd = get_userns_fd(0, 10000, 10000);
864 if (attr.userns_fd < 0) {
865 log_stderr("failure: get_userns_fd");
869 open_tree_fd = sys_open_tree(t_dir1_fd, "",
872 AT_SYMLINK_NOFOLLOW |
875 if (open_tree_fd < 0) {
876 log_stderr("failure: sys_open_tree");
880 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
881 log_stderr("failure: sys_mount_setattr");
885 if (!switch_fsids(0, 0)) {
886 log_stderr("failure: switch_fsids");
890 /* The caller's fsids don't have a mappings in the idmapped mount so any
891 * file creation must fail.
894 /* create hardlink */
895 if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
896 log_stderr("failure: linkat");
899 if (errno != EOVERFLOW) {
900 log_stderr("failure: errno");
904 /* try to rename a file */
905 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
906 log_stderr("failure: renameat");
909 if (errno != EOVERFLOW) {
910 log_stderr("failure: errno");
914 /* try to rename a directory */
915 if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
916 log_stderr("failure: renameat");
919 if (errno != EOVERFLOW) {
920 log_stderr("failure: errno");
924 /* The caller is privileged over the inode so file deletion must work. */
927 if (unlinkat(open_tree_fd, FILE1, 0)) {
928 log_stderr("failure: unlinkat");
932 /* remove directory */
933 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
934 log_stderr("failure: unlinkat");
938 /* The caller's fsids don't have a mappings in the idmapped mount so
939 * any file creation must fail.
942 /* create regular file via open() */
943 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
945 log_stderr("failure: create");
948 if (errno != EOVERFLOW) {
949 log_stderr("failure: errno");
953 /* create regular file via mknod */
954 if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
955 log_stderr("failure: mknodat");
958 if (errno != EOVERFLOW) {
959 log_stderr("failure: errno");
963 /* create character device */
964 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
965 log_stderr("failure: mknodat");
968 if (errno != EOVERFLOW) {
969 log_stderr("failure: errno");
974 if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
975 log_stderr("failure: symlinkat");
978 if (errno != EOVERFLOW) {
979 log_stderr("failure: errno");
983 /* create directory */
984 if (!mkdirat(open_tree_fd, DIR1, 0700)) {
985 log_stderr("failure: mkdirat");
988 if (errno != EOVERFLOW) {
989 log_stderr("failure: errno");
994 log_debug("Ran test");
996 safe_close(attr.userns_fd);
997 safe_close(hardlink_target_fd);
998 safe_close(file1_fd);
999 safe_close(open_tree_fd);
1004 static int fsids_mapped(void)
1007 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
1008 struct mount_attr attr = {
1009 .attr_set = MOUNT_ATTR_IDMAP,
1013 if (!caps_supported())
1016 /* create hardlink target */
1017 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1018 if (hardlink_target_fd < 0) {
1019 log_stderr("failure: openat");
1023 /* create directory for rename test */
1024 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
1025 log_stderr("failure: mkdirat");
1029 /* change ownership of all files to uid 0 */
1030 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1031 log_stderr("failure: chown_r");
1035 /* Changing mount properties on a detached mount. */
1036 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1037 if (attr.userns_fd < 0) {
1038 log_stderr("failure: get_userns_fd");
1042 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1045 AT_SYMLINK_NOFOLLOW |
1048 if (open_tree_fd < 0) {
1049 log_stderr("failure: sys_open_tree");
1053 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1054 log_stderr("failure: sys_mount_setattr");
1060 log_stderr("failure: fork");
1064 if (!switch_fsids(10000, 10000))
1065 die("failure: switch fsids");
1068 die("failure: raise caps");
1070 /* The caller's fsids now have mappings in the idmapped mount so
1071 * any file creation must fail.
1074 /* create hardlink */
1075 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1076 die("failure: create hardlink");
1078 /* try to rename a file */
1079 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1080 die("failure: rename");
1082 /* try to rename a directory */
1083 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1084 die("failure: rename");
1087 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1088 die("failure: delete");
1090 /* remove directory */
1091 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1092 die("failure: delete");
1094 /* The caller's fsids have mappings in the idmapped mount so any
1095 * file creation must fail.
1098 /* create regular file via open() */
1099 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1101 die("failure: create");
1103 /* create regular file via mknod */
1104 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1105 die("failure: create");
1107 /* create character device */
1108 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1109 die("failure: create");
1111 /* create symlink */
1112 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1113 die("failure: create");
1115 /* create directory */
1116 if (mkdirat(open_tree_fd, DIR1, 0700))
1117 die("failure: create");
1121 if (wait_for_pid(pid))
1125 log_debug("Ran test");
1127 safe_close(attr.userns_fd);
1128 safe_close(file1_fd);
1129 safe_close(hardlink_target_fd);
1130 safe_close(open_tree_fd);
1135 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1136 static int create_in_userns(void)
1139 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1140 struct mount_attr attr = {
1141 .attr_set = MOUNT_ATTR_IDMAP,
1145 /* change ownership of all files to uid 0 */
1146 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1147 log_stderr("failure: chown_r");
1151 /* Changing mount properties on a detached mount. */
1152 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1153 if (attr.userns_fd < 0) {
1154 log_stderr("failure: get_userns_fd");
1158 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1161 AT_SYMLINK_NOFOLLOW |
1164 if (open_tree_fd < 0) {
1165 log_stderr("failure: sys_open_tree");
1169 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1170 log_stderr("failure: sys_mount_setattr");
1176 log_stderr("failure: fork");
1180 if (!switch_userns(attr.userns_fd, 0, 0, false))
1181 die("failure: switch_userns");
1183 /* create regular file via open() */
1184 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1186 die("failure: open file");
1187 safe_close(file1_fd);
1189 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1190 die("failure: check ownership");
1192 /* create regular file via mknod */
1193 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1194 die("failure: create");
1196 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1197 die("failure: check ownership");
1199 /* create symlink */
1200 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1201 die("failure: create");
1203 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1204 die("failure: check ownership");
1206 /* create directory */
1207 if (mkdirat(open_tree_fd, DIR1, 0700))
1208 die("failure: create");
1210 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1211 die("failure: check ownership");
1213 /* try to rename a file */
1214 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1215 die("failure: create");
1217 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1218 die("failure: check ownership");
1220 /* try to rename a file */
1221 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1222 die("failure: create");
1224 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1225 die("failure: check ownership");
1228 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1229 die("failure: remove");
1231 /* remove directory */
1232 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1233 die("failure: remove");
1238 if (wait_for_pid(pid))
1242 log_debug("Ran test");
1244 safe_close(attr.userns_fd);
1245 safe_close(file1_fd);
1246 safe_close(open_tree_fd);
1251 static int hardlink_crossing_mounts(void)
1254 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1256 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1257 log_stderr("failure: chown_r");
1261 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1264 AT_SYMLINK_NOFOLLOW |
1267 if (open_tree_fd < 0) {
1268 log_stderr("failure: sys_open_tree");
1272 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1274 log_stderr("failure: openat");
1278 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1279 log_stderr("failure: mkdirat");
1283 /* We're crossing a mountpoint so this must fail.
1285 * Note that this must also fail for non-idmapped mounts but here we're
1286 * interested in making sure we're not introducing an accidental way to
1287 * violate that restriction or that suddenly this becomes possible.
1289 if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1290 log_stderr("failure: linkat");
1293 if (errno != EXDEV) {
1294 log_stderr("failure: errno");
1299 log_debug("Ran test");
1301 safe_close(file1_fd);
1302 safe_close(open_tree_fd);
1307 static int hardlink_crossing_idmapped_mounts(void)
1310 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1311 struct mount_attr attr = {
1312 .attr_set = MOUNT_ATTR_IDMAP,
1315 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1316 log_stderr("failure: chown_r");
1320 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1321 if (attr.userns_fd < 0) {
1322 log_stderr("failure: get_userns_fd");
1326 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1329 AT_SYMLINK_NOFOLLOW |
1332 if (open_tree_fd1 < 0) {
1333 log_stderr("failure: sys_open_tree");
1337 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1338 log_stderr("failure: sys_mount_setattr");
1342 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1344 log_stderr("failure: openat");
1348 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1349 log_stderr("failure: expected_uid_gid");
1353 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1354 log_stderr("failure: expected_uid_gid");
1358 safe_close(file1_fd);
1360 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1361 log_stderr("failure: mkdirat");
1365 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1367 AT_SYMLINK_NOFOLLOW |
1371 if (open_tree_fd2 < 0) {
1372 log_stderr("failure: sys_open_tree");
1376 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1377 log_stderr("failure: sys_mount_setattr");
1381 /* We're crossing a mountpoint so this must fail.
1383 * Note that this must also fail for non-idmapped mounts but here we're
1384 * interested in making sure we're not introducing an accidental way to
1385 * violate that restriction or that suddenly this becomes possible.
1387 if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1388 log_stderr("failure: linkat");
1391 if (errno != EXDEV) {
1392 log_stderr("failure: errno");
1397 log_debug("Ran test");
1399 safe_close(attr.userns_fd);
1400 safe_close(file1_fd);
1401 safe_close(open_tree_fd1);
1402 safe_close(open_tree_fd2);
1407 static int hardlink_from_idmapped_mount(void)
1410 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1411 struct mount_attr attr = {
1412 .attr_set = MOUNT_ATTR_IDMAP,
1415 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1416 log_stderr("failure: chown_r");
1420 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1421 if (attr.userns_fd < 0) {
1422 log_stderr("failure: get_userns_fd");
1426 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1429 AT_SYMLINK_NOFOLLOW |
1432 if (open_tree_fd < 0) {
1433 log_stderr("failure: sys_open_tree");
1437 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1438 log_stderr("failure: sys_mount_setattr");
1442 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1444 log_stderr("failure: openat");
1447 safe_close(file1_fd);
1449 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1450 log_stderr("failure: expected_uid_gid");
1454 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1455 log_stderr("failure: expected_uid_gid");
1459 /* We're not crossing a mountpoint so this must succeed. */
1460 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
1461 log_stderr("failure: linkat");
1467 log_debug("Ran test");
1469 safe_close(attr.userns_fd);
1470 safe_close(file1_fd);
1471 safe_close(open_tree_fd);
1476 static int hardlink_from_idmapped_mount_in_userns(void)
1479 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1480 struct mount_attr attr = {
1481 .attr_set = MOUNT_ATTR_IDMAP,
1485 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1486 log_stderr("failure: chown_r");
1490 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1491 if (attr.userns_fd < 0) {
1492 log_stderr("failure: get_userns_fd");
1496 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1499 AT_SYMLINK_NOFOLLOW |
1502 if (open_tree_fd < 0) {
1503 log_stderr("failure: sys_open_tree");
1507 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1508 log_stderr("failure: sys_mount_setattr");
1514 log_stderr("failure: fork");
1518 if (!switch_userns(attr.userns_fd, 0, 0, false))
1519 die("failure: switch_userns");
1521 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1523 die("failure: create");
1525 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1526 die("failure: check ownership");
1528 /* We're not crossing a mountpoint so this must succeed. */
1529 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1530 die("failure: create");
1532 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1533 die("failure: check ownership");
1538 if (wait_for_pid(pid))
1542 log_debug("Ran test");
1544 safe_close(attr.userns_fd);
1545 safe_close(file1_fd);
1546 safe_close(open_tree_fd);
1551 static int rename_crossing_mounts(void)
1554 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1556 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1557 log_stderr("failure: chown_r");
1561 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1564 AT_SYMLINK_NOFOLLOW |
1567 if (open_tree_fd < 0) {
1568 log_stderr("failure: sys_open_tree");
1572 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1574 log_stderr("failure: openat");
1578 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1579 log_stderr("failure: mkdirat");
1583 /* We're crossing a mountpoint so this must fail.
1585 * Note that this must also fail for non-idmapped mounts but here we're
1586 * interested in making sure we're not introducing an accidental way to
1587 * violate that restriction or that suddenly this becomes possible.
1589 if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1590 log_stderr("failure: renameat");
1593 if (errno != EXDEV) {
1594 log_stderr("failure: errno");
1599 log_debug("Ran test");
1601 safe_close(file1_fd);
1602 safe_close(open_tree_fd);
1607 static int rename_crossing_idmapped_mounts(void)
1610 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1611 struct mount_attr attr = {
1612 .attr_set = MOUNT_ATTR_IDMAP,
1615 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1616 log_stderr("failure: chown_r");
1620 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1621 if (attr.userns_fd < 0) {
1622 log_stderr("failure: get_userns_fd");
1626 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1629 AT_SYMLINK_NOFOLLOW |
1632 if (open_tree_fd1 < 0) {
1633 log_stderr("failure: sys_open_tree");
1637 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1638 log_stderr("failure: sys_mount_setattr");
1642 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1644 log_stderr("failure: openat");
1648 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1649 log_stderr("failure: expected_uid_gid");
1653 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1654 log_stderr("failure: expected_uid_gid");
1658 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1659 log_stderr("failure: mkdirat");
1663 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1665 AT_SYMLINK_NOFOLLOW |
1669 if (open_tree_fd2 < 0) {
1670 log_stderr("failure: sys_open_tree");
1674 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1675 log_stderr("failure: sys_mount_setattr");
1679 /* We're crossing a mountpoint so this must fail.
1681 * Note that this must also fail for non-idmapped mounts but here we're
1682 * interested in making sure we're not introducing an accidental way to
1683 * violate that restriction or that suddenly this becomes possible.
1685 if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1686 log_stderr("failure: renameat");
1689 if (errno != EXDEV) {
1690 log_stderr("failure: errno");
1695 log_debug("Ran test");
1697 safe_close(attr.userns_fd);
1698 safe_close(file1_fd);
1699 safe_close(open_tree_fd1);
1700 safe_close(open_tree_fd2);
1705 static int rename_from_idmapped_mount(void)
1708 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1709 struct mount_attr attr = {
1710 .attr_set = MOUNT_ATTR_IDMAP,
1713 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1714 log_stderr("failure: chown_r");
1718 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1719 if (attr.userns_fd < 0) {
1720 log_stderr("failure: get_userns_fd");
1724 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1727 AT_SYMLINK_NOFOLLOW |
1730 if (open_tree_fd < 0) {
1731 log_stderr("failure: sys_open_tree");
1735 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1736 log_stderr("failure: sys_mount_setattr");
1740 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1742 log_stderr("failure: openat");
1746 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1747 log_stderr("failure: expected_uid_gid");
1751 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1752 log_stderr("failure: expected_uid_gid");
1756 /* We're not crossing a mountpoint so this must succeed. */
1757 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
1758 log_stderr("failure: renameat");
1763 log_debug("Ran test");
1765 safe_close(attr.userns_fd);
1766 safe_close(file1_fd);
1767 safe_close(open_tree_fd);
1772 static int rename_from_idmapped_mount_in_userns(void)
1775 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1777 struct mount_attr attr = {
1778 .attr_set = MOUNT_ATTR_IDMAP,
1781 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1782 log_stderr("failure: chown_r");
1786 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1787 if (attr.userns_fd < 0) {
1788 log_stderr("failure: get_userns_fd");
1792 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1795 AT_SYMLINK_NOFOLLOW |
1798 if (open_tree_fd < 0) {
1799 log_stderr("failure: sys_open_tree");
1803 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1804 log_stderr("failure: sys_mount_setattr");
1810 log_stderr("failure: fork");
1814 if (!switch_userns(attr.userns_fd, 0, 0, false))
1815 die("failure: switch_userns");
1817 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1819 die("failure: create");
1821 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1822 die("failure: check ownership");
1824 /* We're not crossing a mountpoint so this must succeed. */
1825 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1826 die("failure: create");
1828 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1829 die("failure: check ownership");
1834 if (wait_for_pid(pid))
1838 log_debug("Ran test");
1840 safe_close(attr.userns_fd);
1841 safe_close(file1_fd);
1842 safe_close(open_tree_fd);
1847 static int symlink_regular_mounts(void)
1850 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1853 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1855 log_stderr("failure: openat");
1859 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1860 log_stderr("failure: chown_r");
1864 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1867 AT_SYMLINK_NOFOLLOW |
1870 if (open_tree_fd < 0) {
1871 log_stderr("failure: sys_open_tree");
1875 if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1876 log_stderr("failure: symlinkat");
1880 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1881 log_stderr("failure: fchownat");
1885 if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1886 log_stderr("failure: fstatat");
1890 if (st.st_uid != 15000 || st.st_gid != 15000) {
1891 log_stderr("failure: compare ids");
1895 if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1896 log_stderr("failure: fstatat");
1900 if (st.st_uid != 10000 || st.st_gid != 10000) {
1901 log_stderr("failure: compare ids");
1906 log_debug("Ran test");
1908 safe_close(file1_fd);
1909 safe_close(open_tree_fd);
1914 static int symlink_idmapped_mounts(void)
1917 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1918 struct mount_attr attr = {
1919 .attr_set = MOUNT_ATTR_IDMAP,
1923 if (!caps_supported())
1926 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1928 log_stderr("failure: openat");
1932 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1933 log_stderr("failure: chown_r");
1937 /* Changing mount properties on a detached mount. */
1938 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1939 if (attr.userns_fd < 0) {
1940 log_stderr("failure: get_userns_fd");
1944 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1947 AT_SYMLINK_NOFOLLOW |
1950 if (open_tree_fd < 0) {
1951 log_stderr("failure: sys_open_tree");
1955 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1956 log_stderr("failure: sys_mount_setattr");
1962 log_stderr("failure: fork");
1966 if (!switch_fsids(10000, 10000))
1967 die("failure: switch fsids");
1970 die("failure: raise caps");
1972 if (symlinkat(FILE1, open_tree_fd, FILE2))
1973 die("failure: create");
1975 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1976 die("failure: change ownership");
1978 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1979 die("failure: check ownership");
1981 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1982 die("failure: check ownership");
1986 if (wait_for_pid(pid))
1990 log_debug("Ran test");
1992 safe_close(attr.userns_fd);
1993 safe_close(file1_fd);
1994 safe_close(open_tree_fd);
1999 static int symlink_idmapped_mounts_in_userns(void)
2002 int file1_fd = -EBADF, open_tree_fd = -EBADF;
2003 struct mount_attr attr = {
2004 .attr_set = MOUNT_ATTR_IDMAP,
2008 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
2009 log_stderr("failure: chown_r");
2013 /* Changing mount properties on a detached mount. */
2014 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2015 if (attr.userns_fd < 0) {
2016 log_stderr("failure: get_userns_fd");
2020 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2023 AT_SYMLINK_NOFOLLOW |
2026 if (open_tree_fd < 0) {
2027 log_stderr("failure: sys_open_tree");
2031 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2032 log_stderr("failure: sys_mount_setattr");
2038 log_stderr("failure: fork");
2042 if (!switch_userns(attr.userns_fd, 0, 0, false))
2043 die("failure: switch_userns");
2045 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2047 die("failure: create");
2048 safe_close(file1_fd);
2050 if (symlinkat(FILE1, open_tree_fd, FILE2))
2051 die("failure: create");
2053 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2054 die("failure: change ownership");
2056 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2057 die("failure: check ownership");
2059 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2060 die("failure: check ownership");
2065 if (wait_for_pid(pid))
2068 if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2069 log_stderr("failure: expected_uid_gid");
2073 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2074 log_stderr("failure: expected_uid_gid");
2079 log_debug("Ran test");
2081 safe_close(attr.userns_fd);
2082 safe_close(file1_fd);
2083 safe_close(open_tree_fd);
2088 /* Validate that a caller whose fsids map into the idmapped mount within it's
2089 * user namespace cannot create any device nodes.
2091 static int device_node_in_userns(void)
2094 int open_tree_fd = -EBADF;
2095 struct mount_attr attr = {
2096 .attr_set = MOUNT_ATTR_IDMAP,
2100 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2101 if (attr.userns_fd < 0) {
2102 log_stderr("failure: get_userns_fd");
2106 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2109 AT_SYMLINK_NOFOLLOW |
2112 if (open_tree_fd < 0) {
2113 log_stderr("failure: sys_open_tree");
2117 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2118 log_stderr("failure: sys_mount_setattr");
2124 log_stderr("failure: fork");
2128 if (!switch_userns(attr.userns_fd, 0, 0, false))
2129 die("failure: switch_userns");
2131 /* create character device */
2132 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2133 die("failure: create");
2138 if (wait_for_pid(pid))
2142 log_debug("Ran test");
2144 safe_close(attr.userns_fd);
2145 safe_close(open_tree_fd);
2151 /* Validate that changing file ownership works correctly on idmapped mounts. */
2152 static int expected_uid_gid_idmapped_mounts(void)
2155 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2156 struct mount_attr attr1 = {
2157 .attr_set = MOUNT_ATTR_IDMAP,
2159 struct mount_attr attr2 = {
2160 .attr_set = MOUNT_ATTR_IDMAP,
2164 if (!switch_fsids(0, 0)) {
2165 log_stderr("failure: switch_fsids");
2169 /* create regular file via open() */
2170 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2172 log_stderr("failure: openat");
2176 /* create regular file via mknod */
2177 if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2178 log_stderr("failure: mknodat");
2182 /* create character device */
2183 if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2184 log_stderr("failure: mknodat");
2188 /* create hardlink */
2189 if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2190 log_stderr("failure: linkat");
2194 /* create symlink */
2195 if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2196 log_stderr("failure: symlinkat");
2200 /* create directory */
2201 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2202 log_stderr("failure: mkdirat");
2206 /* Changing mount properties on a detached mount. */
2207 attr1.userns_fd = get_userns_fd(0, 10000, 10000);
2208 if (attr1.userns_fd < 0) {
2209 log_stderr("failure: get_userns_fd");
2213 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2216 AT_SYMLINK_NOFOLLOW |
2219 if (open_tree_fd1 < 0) {
2220 log_stderr("failure: sys_open_tree");
2224 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2225 log_stderr("failure: sys_mount_setattr");
2229 /* Validate that all files created through the image mountpoint are
2230 * owned by the callers fsuid and fsgid.
2232 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2233 log_stderr("failure: expected_uid_gid");
2236 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2237 log_stderr("failure: expected_uid_gid");
2240 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2241 log_stderr("failure: expected_uid_gid");
2244 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2245 log_stderr("failure: expected_uid_gid");
2248 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2249 log_stderr("failure: expected_uid_gid");
2252 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2253 log_stderr("failure: expected_uid_gid");
2256 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2257 log_stderr("failure: expected_uid_gid");
2261 /* Validate that all files are owned by the uid and gid specified in
2262 * the idmapping of the mount they are accessed from.
2264 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2265 log_stderr("failure: expected_uid_gid");
2268 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2269 log_stderr("failure: expected_uid_gid");
2272 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2273 log_stderr("failure: expected_uid_gid");
2276 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2277 log_stderr("failure: expected_uid_gid");
2280 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2281 log_stderr("failure: expected_uid_gid");
2284 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2285 log_stderr("failure: expected_uid_gid");
2288 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2289 log_stderr("failure: expected_uid_gid");
2293 /* Changing mount properties on a detached mount. */
2294 attr2.userns_fd = get_userns_fd(0, 30000, 2001);
2295 if (attr2.userns_fd < 0) {
2296 log_stderr("failure: get_userns_fd");
2300 open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2303 AT_SYMLINK_NOFOLLOW |
2306 if (open_tree_fd2 < 0) {
2307 log_stderr("failure: sys_open_tree");
2311 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2312 log_stderr("failure: sys_mount_setattr");
2316 /* Validate that all files are owned by the uid and gid specified in
2317 * the idmapping of the mount they are accessed from.
2319 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2320 log_stderr("failure: expected_uid_gid");
2323 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2324 log_stderr("failure: expected_uid_gid");
2327 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2328 log_stderr("failure: expected_uid_gid");
2331 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2332 log_stderr("failure: expected_uid_gid");
2335 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2336 log_stderr("failure: expected_uid_gid");
2339 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2340 log_stderr("failure: expected_uid_gid");
2343 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2344 log_stderr("failure: expected_uid_gid");
2348 /* Change ownership throught original image mountpoint. */
2349 if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2350 log_stderr("failure: fchownat");
2353 if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2354 log_stderr("failure: fchownat");
2357 if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2358 log_stderr("failure: fchownat");
2361 if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2362 log_stderr("failure: fchownat");
2365 if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2366 log_stderr("failure: fchownat");
2369 if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2370 log_stderr("failure: fchownat");
2373 if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2374 log_stderr("failure: fchownat");
2378 /* Check ownership through original mount. */
2379 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 2000, 2000)) {
2380 log_stderr("failure: expected_uid_gid");
2383 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2384 log_stderr("failure: expected_uid_gid");
2387 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2388 log_stderr("failure: expected_uid_gid");
2391 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2392 log_stderr("failure: expected_uid_gid");
2395 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2396 log_stderr("failure: expected_uid_gid");
2399 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2400 log_stderr("failure: expected_uid_gid");
2403 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2404 log_stderr("failure: expected_uid_gid");
2408 /* Check ownership through first idmapped mount. */
2409 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 12000, 12000)) {
2410 log_stderr("failure:expected_uid_gid ");
2413 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2414 log_stderr("failure: expected_uid_gid");
2417 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2418 log_stderr("failure: expected_uid_gid");
2421 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2422 log_stderr("failure: expected_uid_gid");
2425 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2426 log_stderr("failure: expected_uid_gid");
2429 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2430 log_stderr("failure:expected_uid_gid ");
2433 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2434 log_stderr("failure: expected_uid_gid");
2438 /* Check ownership through second idmapped mount. */
2439 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 32000, 32000)) {
2440 log_stderr("failure: expected_uid_gid");
2443 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2444 log_stderr("failure: expected_uid_gid");
2447 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2448 log_stderr("failure: expected_uid_gid");
2451 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2452 log_stderr("failure: expected_uid_gid");
2455 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2456 log_stderr("failure: expected_uid_gid");
2459 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2460 log_stderr("failure: expected_uid_gid");
2463 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2464 log_stderr("failure: expected_uid_gid");
2470 log_stderr("failure: fork");
2474 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2475 die("failure: switch_userns");
2477 if (!fchownat(t_dir1_fd, FILE1, 1000, 1000, 0))
2478 die("failure: fchownat");
2479 if (!fchownat(t_dir1_fd, FILE2, 1000, 1000, 0))
2480 die("failure: fchownat");
2481 if (!fchownat(t_dir1_fd, HARDLINK1, 1000, 1000, 0))
2482 die("failure: fchownat");
2483 if (!fchownat(t_dir1_fd, CHRDEV1, 1000, 1000, 0))
2484 die("failure: fchownat");
2485 if (!fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2486 die("failure: fchownat");
2487 if (!fchownat(t_dir1_fd, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2488 die("failure: fchownat");
2489 if (!fchownat(t_dir1_fd, DIR1, 1000, 1000, AT_EMPTY_PATH))
2490 die("failure: fchownat");
2492 if (!fchownat(open_tree_fd2, FILE1, 1000, 1000, 0))
2493 die("failure: fchownat");
2494 if (!fchownat(open_tree_fd2, FILE2, 1000, 1000, 0))
2495 die("failure: fchownat");
2496 if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
2497 die("failure: fchownat");
2498 if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
2499 die("failure: fchownat");
2500 if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2501 die("failure: fchownat");
2502 if (!fchownat(open_tree_fd2, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2503 die("failure: fchownat");
2504 if (!fchownat(open_tree_fd2, DIR1, 1000, 1000, AT_EMPTY_PATH))
2505 die("failure: fchownat");
2507 if (fchownat(open_tree_fd1, FILE1, 1000, 1000, 0))
2508 die("failure: fchownat");
2509 if (fchownat(open_tree_fd1, FILE2, 1000, 1000, 0))
2510 die("failure: fchownat");
2511 if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
2512 die("failure: fchownat");
2513 if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
2514 die("failure: fchownat");
2515 if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2516 die("failure: fchownat");
2517 if (fchownat(open_tree_fd1, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2518 die("failure: fchownat");
2519 if (fchownat(open_tree_fd1, DIR1, 1000, 1000, AT_EMPTY_PATH))
2520 die("failure: fchownat");
2522 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2523 die("failure: expected_uid_gid");
2524 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2525 die("failure: expected_uid_gid");
2526 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2527 die("failure: expected_uid_gid");
2528 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2529 die("failure: expected_uid_gid");
2530 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2531 die("failure: expected_uid_gid");
2532 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2533 die("failure: expected_uid_gid");
2534 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2535 die("failure: expected_uid_gid");
2537 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, t_overflowuid, t_overflowgid))
2538 die("failure: expected_uid_gid");
2539 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, t_overflowuid, t_overflowgid))
2540 die("failure: expected_uid_gid");
2541 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2542 die("failure: expected_uid_gid");
2543 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2544 die("failure: expected_uid_gid");
2545 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2546 die("failure: expected_uid_gid");
2547 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2548 die("failure: expected_uid_gid");
2549 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, t_overflowuid, t_overflowgid))
2550 die("failure: expected_uid_gid");
2552 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 1000, 1000))
2553 die("failure: expected_uid_gid");
2554 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 1000, 1000))
2555 die("failure: expected_uid_gid");
2556 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
2557 die("failure: expected_uid_gid");
2558 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
2559 die("failure: expected_uid_gid");
2560 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2561 die("failure: expected_uid_gid");
2562 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 1000, 1000))
2563 die("failure: expected_uid_gid");
2564 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 1000, 1000))
2565 die("failure: expected_uid_gid");
2570 if (wait_for_pid(pid))
2573 /* Check ownership through original mount. */
2574 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 1000, 1000)) {
2575 log_stderr("failure: expected_uid_gid");
2578 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2579 log_stderr("failure: expected_uid_gid");
2582 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2583 log_stderr("failure: expected_uid_gid");
2586 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2587 log_stderr("failure: expected_uid_gid");
2590 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2591 log_stderr("failure: expected_uid_gid");
2594 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2595 log_stderr("failure: expected_uid_gid");
2598 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2599 log_stderr("failure: expected_uid_gid");
2603 /* Check ownership through first idmapped mount. */
2604 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 11000, 11000)) {
2605 log_stderr("failure: expected_uid_gid");
2608 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2609 log_stderr("failure: expected_uid_gid");
2612 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2613 log_stderr("failure: expected_uid_gid");
2616 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2617 log_stderr("failure: expected_uid_gid");
2620 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2621 log_stderr("failure: expected_uid_gid");
2624 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2625 log_stderr("failure: expected_uid_gid");
2628 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2629 log_stderr("failure: expected_uid_gid");
2633 /* Check ownership through second idmapped mount. */
2634 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 31000, 31000)) {
2635 log_stderr("failure: expected_uid_gid");
2638 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2639 log_stderr("failure: expected_uid_gid");
2642 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2643 log_stderr("failure: expected_uid_gid");
2646 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2647 log_stderr("failure: expected_uid_gid");
2650 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2651 log_stderr("failure: expected_uid_gid");
2654 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2655 log_stderr("failure: expected_uid_gid");
2658 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2659 log_stderr("failure: expected_uid_gid");
2665 log_stderr("failure: fork");
2669 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2670 die("failure: switch_userns");
2672 if (!fchownat(t_dir1_fd, FILE1, 0, 0, 0))
2673 die("failure: fchownat");
2674 if (!fchownat(t_dir1_fd, FILE2, 0, 0, 0))
2675 die("failure: fchownat");
2676 if (!fchownat(t_dir1_fd, HARDLINK1, 0, 0, 0))
2677 die("failure: fchownat");
2678 if (!fchownat(t_dir1_fd, CHRDEV1, 0, 0, 0))
2679 die("failure: fchownat");
2680 if (!fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2681 die("failure: fchownat");
2682 if (!fchownat(t_dir1_fd, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2683 die("failure: fchownat");
2684 if (!fchownat(t_dir1_fd, DIR1, 0, 0, AT_EMPTY_PATH))
2685 die("failure: fchownat");
2687 if (!fchownat(open_tree_fd1, FILE1, 0, 0, 0))
2688 die("failure: fchownat");
2689 if (!fchownat(open_tree_fd1, FILE2, 0, 0, 0))
2690 die("failure: fchownat");
2691 if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
2692 die("failure: fchownat");
2693 if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
2694 die("failure: fchownat");
2695 if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2696 die("failure: fchownat");
2697 if (!fchownat(open_tree_fd1, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2698 die("failure: fchownat");
2699 if (!fchownat(open_tree_fd1, DIR1, 0, 0, AT_EMPTY_PATH))
2700 die("failure: fchownat");
2702 if (fchownat(open_tree_fd2, FILE1, 0, 0, 0))
2703 die("failure: fchownat");
2704 if (fchownat(open_tree_fd2, FILE2, 0, 0, 0))
2705 die("failure: fchownat");
2706 if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
2707 die("failure: fchownat");
2708 if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
2709 die("failure: fchownat");
2710 if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2711 die("failure: fchownat");
2712 if (fchownat(open_tree_fd2, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2713 die("failure: fchownat");
2714 if (fchownat(open_tree_fd2, DIR1, 0, 0, AT_EMPTY_PATH))
2715 die("failure: fchownat");
2717 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2718 die("failure: expected_uid_gid");
2719 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2720 die("failure: expected_uid_gid");
2721 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2722 die("failure: expected_uid_gid");
2723 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2724 die("failure: expected_uid_gid");
2725 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2726 die("failure: expected_uid_gid");
2727 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2728 die("failure: expected_uid_gid");
2729 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2730 die("failure: expected_uid_gid");
2732 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, t_overflowuid, t_overflowgid))
2733 die("failure: expected_uid_gid");
2734 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, t_overflowuid, t_overflowgid))
2735 die("failure: expected_uid_gid");
2736 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2737 die("failure: expected_uid_gid");
2738 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2739 die("failure: expected_uid_gid");
2740 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2741 die("failure: expected_uid_gid");
2742 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2743 die("failure: expected_uid_gid");
2744 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, t_overflowuid, t_overflowgid))
2745 die("failure: expected_uid_gid");
2747 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 0, 0))
2748 die("failure: expected_uid_gid");
2749 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 0, 0))
2750 die("failure: expected_uid_gid");
2751 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
2752 die("failure: expected_uid_gid");
2753 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
2754 die("failure: expected_uid_gid");
2755 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2756 die("failure: expected_uid_gid");
2757 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 0, 0))
2758 die("failure: expected_uid_gid");
2759 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 0, 0))
2760 die("failure: expected_uid_gid");
2765 if (wait_for_pid(pid))
2768 /* Check ownership through original mount. */
2769 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2770 log_stderr("failure: expected_uid_gid");
2773 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2774 log_stderr("failure: expected_uid_gid");
2777 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2778 log_stderr("failure: expected_uid_gid");
2781 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2782 log_stderr("failure: expected_uid_gid");
2785 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2786 log_stderr("failure: expected_uid_gid");
2789 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2790 log_stderr("failure: expected_uid_gid");
2793 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2794 log_stderr("failure: expected_uid_gid");
2798 /* Check ownership through first idmapped mount. */
2799 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2800 log_stderr("failure: expected_uid_gid");
2803 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2804 log_stderr("failure: expected_uid_gid");
2807 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2808 log_stderr("failure: expected_uid_gid");
2811 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2812 log_stderr("failure: expected_uid_gid");
2815 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2816 log_stderr("failure: expected_uid_gid");
2819 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2820 log_stderr("failure: expected_uid_gid");
2823 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2824 log_stderr("failure: expected_uid_gid");
2828 /* Check ownership through second idmapped mount. */
2829 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2830 log_stderr("failure: expected_uid_gid");
2833 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2834 log_stderr("failure: expected_uid_gid");
2837 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2838 log_stderr("failure: expected_uid_gid");
2841 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2842 log_stderr("failure: expected_uid_gid");
2845 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2846 log_stderr("failure: expected_uid_gid");
2849 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2850 log_stderr("failure: expected_uid_gid");
2853 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2854 log_stderr("failure: expected_uid_gid");
2859 log_debug("Ran test");
2861 safe_close(attr1.userns_fd);
2862 safe_close(attr2.userns_fd);
2863 safe_close(file1_fd);
2864 safe_close(open_tree_fd1);
2865 safe_close(open_tree_fd2);
2870 static int fscaps(void)
2873 int file1_fd = -EBADF, fd_userns = -EBADF;
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 fd_userns = get_userns_fd(0, 10000, 10000);
2888 if (fd_userns < 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(fd_userns, 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(fd_userns, 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(file1_fd);
2981 safe_close(fd_userns);
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 (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0))
7867 die("failure: check ownership");
7869 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0))
7870 die("failure: check ownership");
7872 if (unlinkat(t_dir1_fd, FILE1, 0))
7873 die("failure: delete");
7875 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7876 die("failure: delete");
7880 if (wait_for_pid(pid))
7885 log_stderr("failure: fork");
7889 if (!switch_ids(0, 10000))
7890 die("failure: switch_ids");
7893 die("failure: caps_down");
7895 /* create regular file via open() */
7896 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7898 die("failure: create");
7900 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7901 * bit needs to be stripped.
7903 if (is_setgid(t_dir1_fd, FILE1, 0))
7904 die("failure: is_setgid");
7906 /* create directory */
7907 if (mkdirat(t_dir1_fd, DIR1, 0000))
7908 die("failure: create");
7910 if (xfs_irix_sgid_inherit_enabled()) {
7911 /* We're not in_group_p(). */
7912 if (is_setgid(t_dir1_fd, DIR1, 0))
7913 die("failure: is_setgid");
7915 /* Directories always inherit the setgid bit. */
7916 if (!is_setgid(t_dir1_fd, DIR1, 0))
7917 die("failure: is_setgid");
7921 * In setgid directories newly created files always inherit the
7922 * gid from the parent directory. Verify that the file is owned
7923 * by gid 0, not by gid 10000.
7925 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0))
7926 die("failure: check ownership");
7929 * In setgid directories newly created directories always
7930 * inherit the gid from the parent directory. Verify that the
7931 * directory is owned by gid 0, not by gid 10000.
7933 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0))
7934 die("failure: check ownership");
7938 if (wait_for_pid(pid))
7942 log_debug("Ran test");
7944 safe_close(file1_fd);
7949 static int setgid_create_idmapped(void)
7952 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7953 struct mount_attr attr = {
7954 .attr_set = MOUNT_ATTR_IDMAP,
7958 if (!caps_supported())
7961 if (fchmod(t_dir1_fd, S_IRUSR |
7971 log_stderr("failure: fchmod");
7975 /* Verify that the sid bits got raised. */
7976 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7977 log_stderr("failure: is_setgid");
7981 /* Changing mount properties on a detached mount. */
7982 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7983 if (attr.userns_fd < 0) {
7984 log_stderr("failure: get_userns_fd");
7988 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7991 AT_SYMLINK_NOFOLLOW |
7994 if (open_tree_fd < 0) {
7995 log_stderr("failure: sys_open_tree");
7999 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8000 log_stderr("failure: sys_mount_setattr");
8006 log_stderr("failure: fork");
8010 if (!switch_ids(10000, 11000))
8011 die("failure: switch fsids");
8013 /* create regular file via open() */
8014 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8016 die("failure: create");
8018 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8019 * bit needs to be stripped.
8021 if (is_setgid(open_tree_fd, FILE1, 0))
8022 die("failure: is_setgid");
8024 /* create directory */
8025 if (mkdirat(open_tree_fd, DIR1, 0000))
8026 die("failure: create");
8028 if (xfs_irix_sgid_inherit_enabled()) {
8029 /* We're not in_group_p(). */
8030 if (is_setgid(open_tree_fd, DIR1, 0))
8031 die("failure: is_setgid");
8033 /* Directories always inherit the setgid bit. */
8034 if (!is_setgid(open_tree_fd, DIR1, 0))
8035 die("failure: is_setgid");
8039 * In setgid directories newly created files always inherit the
8040 * gid from the parent directory. Verify that the file is owned
8041 * by gid 10000, not by gid 11000.
8043 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8044 die("failure: check ownership");
8047 * In setgid directories newly created directories always
8048 * inherit the gid from the parent directory. Verify that the
8049 * directory is owned by gid 10000, not by gid 11000.
8051 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000))
8052 die("failure: check ownership");
8056 if (wait_for_pid(pid))
8060 log_debug("Ran test");
8062 safe_close(attr.userns_fd);
8063 safe_close(file1_fd);
8064 safe_close(open_tree_fd);
8069 static int setgid_create_idmapped_in_userns(void)
8072 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8073 struct mount_attr attr = {
8074 .attr_set = MOUNT_ATTR_IDMAP,
8078 if (!caps_supported())
8081 if (fchmod(t_dir1_fd, S_IRUSR |
8091 log_stderr("failure: fchmod");
8095 /* Verify that the sid bits got raised. */
8096 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
8097 log_stderr("failure: is_setgid");
8101 /* Changing mount properties on a detached mount. */
8102 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8103 if (attr.userns_fd < 0) {
8104 log_stderr("failure: get_userns_fd");
8108 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8111 AT_SYMLINK_NOFOLLOW |
8114 if (open_tree_fd < 0) {
8115 log_stderr("failure: sys_open_tree");
8119 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8120 log_stderr("failure: sys_mount_setattr");
8126 log_stderr("failure: fork");
8130 if (!switch_userns(attr.userns_fd, 0, 0, false))
8131 die("failure: switch_userns");
8133 /* create regular file via open() */
8134 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8136 die("failure: create");
8138 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
8139 * bit needs to be set.
8141 if (!is_setgid(open_tree_fd, FILE1, 0))
8142 die("failure: is_setgid");
8144 /* create directory */
8145 if (mkdirat(open_tree_fd, DIR1, 0000))
8146 die("failure: create");
8148 /* Directories always inherit the setgid bit. */
8149 if (!is_setgid(open_tree_fd, DIR1, 0))
8150 die("failure: is_setgid");
8152 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8153 die("failure: check ownership");
8155 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8156 die("failure: check ownership");
8158 if (unlinkat(open_tree_fd, FILE1, 0))
8159 die("failure: delete");
8161 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8162 die("failure: delete");
8166 if (wait_for_pid(pid))
8170 * Below we verify that setgid inheritance for a newly created file or
8171 * directory works correctly. As part of this we need to verify that
8172 * newly created files or directories inherit their gid from their
8173 * parent directory. So we change the parent directorie's gid to 1000
8174 * and create a file with fs{g,u}id 0 and verify that the newly created
8175 * file and directory inherit gid 1000, not 0.
8177 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8178 log_stderr("failure: fchownat");
8184 log_stderr("failure: fork");
8188 if (!caps_supported()) {
8189 log_debug("skip: capability library not installed");
8193 if (!switch_userns(attr.userns_fd, 0, 0, true))
8194 die("failure: switch_userns");
8196 /* create regular file via open() */
8197 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8199 die("failure: create");
8201 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8202 * bit needs to be stripped.
8204 if (is_setgid(open_tree_fd, FILE1, 0))
8205 die("failure: is_setgid");
8207 /* create directory */
8208 if (mkdirat(open_tree_fd, DIR1, 0000))
8209 die("failure: create");
8211 if (xfs_irix_sgid_inherit_enabled()) {
8212 /* We're not in_group_p(). */
8213 if (is_setgid(open_tree_fd, DIR1, 0))
8214 die("failure: is_setgid");
8216 /* Directories always inherit the setgid bit. */
8217 if (!is_setgid(open_tree_fd, DIR1, 0))
8218 die("failure: is_setgid");
8222 * In setgid directories newly created files always inherit the
8223 * gid from the parent directory. Verify that the file is owned
8224 * by gid 1000, not by gid 0.
8226 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8227 die("failure: check ownership");
8230 * In setgid directories newly created directories always
8231 * inherit the gid from the parent directory. Verify that the
8232 * directory is owned by gid 1000, not by gid 0.
8234 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8235 die("failure: check ownership");
8237 if (unlinkat(open_tree_fd, FILE1, 0))
8238 die("failure: delete");
8240 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8241 die("failure: delete");
8245 if (wait_for_pid(pid))
8248 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8249 log_stderr("failure: fchownat");
8253 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8254 log_stderr("failure: fchownat");
8260 log_stderr("failure: fork");
8264 if (!caps_supported()) {
8265 log_debug("skip: capability library not installed");
8269 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8270 die("failure: switch_userns");
8272 /* create regular file via open() */
8273 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8275 die("failure: create");
8277 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8278 * bit needs to be stripped.
8280 if (is_setgid(open_tree_fd, FILE1, 0))
8281 die("failure: is_setgid");
8283 /* create directory */
8284 if (mkdirat(open_tree_fd, DIR1, 0000))
8285 die("failure: create");
8287 /* Directories always inherit the setgid bit. */
8288 if (xfs_irix_sgid_inherit_enabled()) {
8289 /* We're not in_group_p(). */
8290 if (is_setgid(open_tree_fd, DIR1, 0))
8291 die("failure: is_setgid");
8293 /* Directories always inherit the setgid bit. */
8294 if (!is_setgid(open_tree_fd, DIR1, 0))
8295 die("failure: is_setgid");
8298 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8299 die("failure: check ownership");
8301 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8302 die("failure: check ownership");
8306 if (wait_for_pid(pid))
8310 log_debug("Ran test");
8312 safe_close(attr.userns_fd);
8313 safe_close(file1_fd);
8314 safe_close(open_tree_fd);
8319 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8320 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8322 static void *idmapped_mount_create_cb(void *data)
8324 int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8325 struct mount_attr attr = {
8326 .attr_set = MOUNT_ATTR_IDMAP,
8329 /* Changing mount properties on a detached mount. */
8330 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8331 if (attr.userns_fd < 0) {
8332 log_stderr("failure: get_userns_fd");
8336 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8337 log_stderr("failure: sys_mount_setattr");
8341 fret = EXIT_SUCCESS;
8344 safe_close(attr.userns_fd);
8345 pthread_exit(INT_TO_PTR(fret));
8348 /* This tries to verify that we never see an inconistent ownership on-disk and
8349 * can't write invalid ids to disk. To do this we create a race between
8350 * idmapping a mount and creating files on it.
8351 * Note, while it is perfectly fine to see overflowuid and overflowgid as owner
8352 * if we create files through the open_tree_fd before the mount is idmapped but
8353 * look at the files after the mount has been idmapped in this test it can never
8354 * be the case that we see overflowuid and overflowgid when we access the file
8355 * through a non-idmapped mount (in the initial user namespace).
8357 static void *idmapped_mount_operations_cb(void *data)
8359 int file1_fd = -EBADF, file2_fd = -EBADF, dir1_fd = -EBADF,
8360 dir1_fd2 = -EBADF, fret = EXIT_FAILURE,
8361 open_tree_fd = PTR_TO_INT(data);
8363 if (!switch_fsids(10000, 10000)) {
8364 log_stderr("failure: switch fsids");
8368 file1_fd = openat(open_tree_fd, FILE1,
8369 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8371 log_stderr("failure: openat");
8375 file2_fd = openat(open_tree_fd, FILE2,
8376 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8378 log_stderr("failure: openat");
8382 if (mkdirat(open_tree_fd, DIR1, 0777)) {
8383 log_stderr("failure: mkdirat");
8387 dir1_fd = openat(open_tree_fd, DIR1,
8388 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8390 log_stderr("failure: openat");
8394 if (!__expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0, false) &&
8395 !__expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000, false) &&
8396 !__expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid, false)) {
8397 log_stderr("failure: expected_uid_gid");
8401 if (!__expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0, false) &&
8402 !__expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000, false) &&
8403 !__expected_uid_gid(open_tree_fd, FILE2, 0, t_overflowuid, t_overflowgid, false)) {
8404 log_stderr("failure: expected_uid_gid");
8408 if (!__expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0, false) &&
8409 !__expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000, false) &&
8410 !__expected_uid_gid(open_tree_fd, DIR1, 0, t_overflowuid, t_overflowgid, false)) {
8411 log_stderr("failure: expected_uid_gid");
8415 if (!__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 0, 0, false) &&
8416 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 10000, 10000, false) &&
8417 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, t_overflowuid, t_overflowgid, false)) {
8418 log_stderr("failure: expected_uid_gid");
8422 dir1_fd2 = openat(t_dir1_fd, DIR1,
8423 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8425 log_stderr("failure: openat");
8429 if (!__expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0, false) &&
8430 !__expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000, false)) {
8431 log_stderr("failure: expected_uid_gid");
8435 if (!__expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0, false) &&
8436 !__expected_uid_gid(t_dir1_fd, FILE2, 0, 10000, 10000, false)) {
8437 log_stderr("failure: expected_uid_gid");
8441 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8442 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8443 log_stderr("failure: expected_uid_gid");
8447 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8448 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8449 log_stderr("failure: expected_uid_gid");
8453 if (!__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 0, 0, false) &&
8454 !__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 10000, 10000, false)) {
8455 log_stderr("failure: expected_uid_gid");
8459 fret = EXIT_SUCCESS;
8462 safe_close(file1_fd);
8463 safe_close(file2_fd);
8464 safe_close(dir1_fd);
8465 safe_close(dir1_fd2);
8467 pthread_exit(INT_TO_PTR(fret));
8470 static int threaded_idmapped_mount_interactions(void)
8475 pthread_attr_t thread_attr;
8476 pthread_t threads[2];
8478 pthread_attr_init(&thread_attr);
8480 for (i = 0; i < 1000; i++) {
8481 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8485 log_stderr("failure: fork");
8489 int open_tree_fd = -EBADF;
8491 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8494 AT_SYMLINK_NOFOLLOW |
8497 if (open_tree_fd < 0)
8498 die("failure: sys_open_tree");
8500 if (pthread_create(&threads[0], &thread_attr,
8501 idmapped_mount_create_cb,
8502 INT_TO_PTR(open_tree_fd)))
8503 die("failure: pthread_create");
8505 if (pthread_create(&threads[1], &thread_attr,
8506 idmapped_mount_operations_cb,
8507 INT_TO_PTR(open_tree_fd)))
8508 die("failure: pthread_create");
8510 ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8511 ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8515 die("failure: pthread_join");
8520 die("failure: pthread_join");
8530 if (wait_for_pid(pid)) {
8531 log_stderr("failure: iteration %d", i);
8535 rm_r(t_dir1_fd, ".");
8540 log_debug("Ran test");
8546 static int setattr_truncate(void)
8549 int file1_fd = -EBADF;
8551 /* create regular file via open() */
8552 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8554 log_stderr("failure: create");
8558 if (ftruncate(file1_fd, 10000)) {
8559 log_stderr("failure: ftruncate");
8563 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8564 log_stderr("failure: check ownership");
8568 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8569 log_stderr("failure: expected_file_size");
8573 if (ftruncate(file1_fd, 0)) {
8574 log_stderr("failure: ftruncate");
8578 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8579 log_stderr("failure: check ownership");
8583 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8584 log_stderr("failure: expected_file_size");
8588 if (unlinkat(t_dir1_fd, FILE1, 0)) {
8589 log_stderr("failure: remove");
8594 log_debug("Ran test");
8596 safe_close(file1_fd);
8601 static int setattr_truncate_idmapped(void)
8604 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8606 struct mount_attr attr = {
8607 .attr_set = MOUNT_ATTR_IDMAP,
8610 /* Changing mount properties on a detached mount. */
8611 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8612 if (attr.userns_fd < 0) {
8613 log_stderr("failure: get_userns_fd");
8617 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8620 AT_SYMLINK_NOFOLLOW |
8623 if (open_tree_fd < 0) {
8624 log_stderr("failure: sys_open_tree");
8628 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8629 log_stderr("failure: sys_mount_setattr");
8635 log_stderr("failure: fork");
8639 if (!switch_ids(10000, 10000))
8640 die("failure: switch_ids");
8642 /* create regular file via open() */
8643 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8645 die("failure: create");
8647 if (ftruncate(file1_fd, 10000))
8648 die("failure: ftruncate");
8650 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8651 die("failure: check ownership");
8653 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8654 die("failure: expected_file_size");
8656 if (ftruncate(file1_fd, 0))
8657 die("failure: ftruncate");
8659 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8660 die("failure: check ownership");
8662 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8663 die("failure: expected_file_size");
8667 if (wait_for_pid(pid))
8672 log_stderr("failure: fork");
8676 int file1_fd2 = -EBADF;
8678 /* create regular file via open() */
8679 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8681 die("failure: create");
8683 if (ftruncate(file1_fd2, 10000))
8684 die("failure: ftruncate");
8686 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8687 die("failure: check ownership");
8689 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8690 die("failure: expected_file_size");
8692 if (ftruncate(file1_fd2, 0))
8693 die("failure: ftruncate");
8695 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8696 die("failure: check ownership");
8698 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8699 die("failure: expected_file_size");
8703 if (wait_for_pid(pid))
8707 log_debug("Ran test");
8709 safe_close(file1_fd);
8710 safe_close(open_tree_fd);
8715 static int setattr_truncate_idmapped_in_userns(void)
8718 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8719 struct mount_attr attr = {
8720 .attr_set = MOUNT_ATTR_IDMAP,
8724 /* Changing mount properties on a detached mount. */
8725 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8726 if (attr.userns_fd < 0) {
8727 log_stderr("failure: get_userns_fd");
8731 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8734 AT_SYMLINK_NOFOLLOW |
8737 if (open_tree_fd < 0) {
8738 log_stderr("failure: sys_open_tree");
8742 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8743 log_stderr("failure: sys_mount_setattr");
8749 log_stderr("failure: fork");
8753 if (!switch_userns(attr.userns_fd, 0, 0, false))
8754 die("failure: switch_userns");
8756 /* create regular file via open() */
8757 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8759 die("failure: create");
8761 if (ftruncate(file1_fd, 10000))
8762 die("failure: ftruncate");
8764 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8765 die("failure: check ownership");
8767 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8768 die("failure: expected_file_size");
8770 if (ftruncate(file1_fd, 0))
8771 die("failure: ftruncate");
8773 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8774 die("failure: check ownership");
8776 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8777 die("failure: expected_file_size");
8779 if (unlinkat(open_tree_fd, FILE1, 0))
8780 die("failure: delete");
8784 if (wait_for_pid(pid))
8787 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8788 log_stderr("failure: fchownat");
8792 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8793 log_stderr("failure: fchownat");
8799 log_stderr("failure: fork");
8803 if (!caps_supported()) {
8804 log_debug("skip: capability library not installed");
8808 if (!switch_userns(attr.userns_fd, 0, 0, true))
8809 die("failure: switch_userns");
8811 /* create regular file via open() */
8812 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8814 die("failure: create");
8816 if (ftruncate(file1_fd, 10000))
8817 die("failure: ftruncate");
8819 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8820 die("failure: check ownership");
8822 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8823 die("failure: expected_file_size");
8825 if (ftruncate(file1_fd, 0))
8826 die("failure: ftruncate");
8828 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8829 die("failure: check ownership");
8831 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8832 die("failure: expected_file_size");
8834 if (unlinkat(open_tree_fd, FILE1, 0))
8835 die("failure: delete");
8839 if (wait_for_pid(pid))
8842 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8843 log_stderr("failure: fchownat");
8847 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8848 log_stderr("failure: fchownat");
8854 log_stderr("failure: fork");
8858 if (!caps_supported()) {
8859 log_debug("skip: capability library not installed");
8863 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8864 die("failure: switch_userns");
8866 /* create regular file via open() */
8867 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8869 die("failure: create");
8871 if (ftruncate(file1_fd, 10000))
8872 die("failure: ftruncate");
8874 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8875 die("failure: check ownership");
8877 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8878 die("failure: expected_file_size");
8880 if (ftruncate(file1_fd, 0))
8881 die("failure: ftruncate");
8883 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8884 die("failure: check ownership");
8886 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8887 die("failure: expected_file_size");
8889 if (unlinkat(open_tree_fd, FILE1, 0))
8890 die("failure: delete");
8894 if (wait_for_pid(pid))
8898 log_debug("Ran test");
8900 safe_close(attr.userns_fd);
8901 safe_close(file1_fd);
8902 safe_close(open_tree_fd);
8907 static int nested_userns(void)
8913 struct list *it, *next;
8914 struct userns_hierarchy hierarchy[] = {
8915 { .level = 1, .fd_userns = -EBADF, },
8916 { .level = 2, .fd_userns = -EBADF, },
8917 { .level = 3, .fd_userns = -EBADF, },
8918 { .level = 4, .fd_userns = -EBADF, },
8919 /* Dummy entry that marks the end. */
8920 { .level = MAX_USERNS_LEVEL, .fd_userns = -EBADF, },
8922 struct mount_attr attr_level1 = {
8923 .attr_set = MOUNT_ATTR_IDMAP,
8924 .userns_fd = -EBADF,
8926 struct mount_attr attr_level2 = {
8927 .attr_set = MOUNT_ATTR_IDMAP,
8928 .userns_fd = -EBADF,
8930 struct mount_attr attr_level3 = {
8931 .attr_set = MOUNT_ATTR_IDMAP,
8932 .userns_fd = -EBADF,
8934 struct mount_attr attr_level4 = {
8935 .attr_set = MOUNT_ATTR_IDMAP,
8936 .userns_fd = -EBADF,
8938 int fd_dir1 = -EBADF,
8939 fd_open_tree_level1 = -EBADF,
8940 fd_open_tree_level2 = -EBADF,
8941 fd_open_tree_level3 = -EBADF,
8942 fd_open_tree_level4 = -EBADF;
8943 const unsigned int id_file_range = 10000;
8945 list_init(&hierarchy[0].id_map);
8946 list_init(&hierarchy[1].id_map);
8947 list_init(&hierarchy[2].id_map);
8948 list_init(&hierarchy[3].id_map);
8951 * Give a large map to the outermost user namespace so we can create
8952 * comfortable nested maps.
8954 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_UID);
8956 log_stderr("failure: adding uidmap for userns at level 1");
8960 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_GID);
8962 log_stderr("failure: adding gidmap for userns at level 1");
8966 /* This is uid:0->2000000:100000000 in init userns. */
8967 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_UID);
8969 log_stderr("failure: adding uidmap for userns at level 2");
8973 /* This is gid:0->2000000:100000000 in init userns. */
8974 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_GID);
8976 log_stderr("failure: adding gidmap for userns at level 2");
8980 /* This is uid:0->3000000:999 in init userns. */
8981 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_UID);
8983 log_stderr("failure: adding uidmap for userns at level 3");
8987 /* This is gid:0->3000000:999 in the init userns. */
8988 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_GID);
8990 log_stderr("failure: adding gidmap for userns at level 3");
8994 /* id 999 will remain unmapped. */
8996 /* This is uid:1000->2001000:1 in init userns. */
8997 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_UID);
8999 log_stderr("failure: adding uidmap for userns at level 3");
9003 /* This is gid:1000->2001000:1 in init userns. */
9004 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_GID);
9006 log_stderr("failure: adding gidmap for userns at level 3");
9010 /* This is uid:1001->3001001:10000 in init userns. */
9011 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_UID);
9013 log_stderr("failure: adding uidmap for userns at level 3");
9017 /* This is gid:1001->3001001:10000 in init userns. */
9018 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_GID);
9020 log_stderr("failure: adding gidmap for userns at level 3");
9024 /* Don't write a mapping in the 4th userns. */
9025 list_empty(&hierarchy[4].id_map);
9027 /* Create the actual userns hierarchy. */
9028 ret = create_userns_hierarchy(hierarchy);
9030 log_stderr("failure: create userns hierarchy");
9034 attr_level1.userns_fd = hierarchy[0].fd_userns;
9035 attr_level2.userns_fd = hierarchy[1].fd_userns;
9036 attr_level3.userns_fd = hierarchy[2].fd_userns;
9037 attr_level4.userns_fd = hierarchy[3].fd_userns;
9040 * Create one directory where we create files for each uid/gid within
9043 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
9044 log_stderr("failure: mkdirat");
9048 fd_dir1 = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
9050 log_stderr("failure: openat");
9054 for (id = 0; id <= id_file_range; id++) {
9057 snprintf(file, sizeof(file), DIR1 "/" FILE1 "_%u", id);
9059 if (mknodat(t_dir1_fd, file, S_IFREG | 0644, 0)) {
9060 log_stderr("failure: create %s", file);
9064 if (fchownat(t_dir1_fd, file, id, id, AT_SYMLINK_NOFOLLOW)) {
9065 log_stderr("failure: fchownat %s", file);
9069 if (!expected_uid_gid(t_dir1_fd, file, 0, id, id)) {
9070 log_stderr("failure: check ownership %s", file);
9075 /* Create detached mounts for all the user namespaces. */
9076 fd_open_tree_level1 = sys_open_tree(t_dir1_fd, DIR1,
9078 AT_SYMLINK_NOFOLLOW |
9081 if (fd_open_tree_level1 < 0) {
9082 log_stderr("failure: sys_open_tree");
9086 fd_open_tree_level2 = sys_open_tree(t_dir1_fd, DIR1,
9088 AT_SYMLINK_NOFOLLOW |
9091 if (fd_open_tree_level2 < 0) {
9092 log_stderr("failure: sys_open_tree");
9096 fd_open_tree_level3 = sys_open_tree(t_dir1_fd, DIR1,
9098 AT_SYMLINK_NOFOLLOW |
9101 if (fd_open_tree_level3 < 0) {
9102 log_stderr("failure: sys_open_tree");
9106 fd_open_tree_level4 = sys_open_tree(t_dir1_fd, DIR1,
9108 AT_SYMLINK_NOFOLLOW |
9111 if (fd_open_tree_level4 < 0) {
9112 log_stderr("failure: sys_open_tree");
9116 /* Turn detached mounts into detached idmapped mounts. */
9117 if (sys_mount_setattr(fd_open_tree_level1, "", AT_EMPTY_PATH,
9118 &attr_level1, sizeof(attr_level1))) {
9119 log_stderr("failure: sys_mount_setattr");
9123 if (sys_mount_setattr(fd_open_tree_level2, "", AT_EMPTY_PATH,
9124 &attr_level2, sizeof(attr_level2))) {
9125 log_stderr("failure: sys_mount_setattr");
9129 if (sys_mount_setattr(fd_open_tree_level3, "", AT_EMPTY_PATH,
9130 &attr_level3, sizeof(attr_level3))) {
9131 log_stderr("failure: sys_mount_setattr");
9135 if (sys_mount_setattr(fd_open_tree_level4, "", AT_EMPTY_PATH,
9136 &attr_level4, sizeof(attr_level4))) {
9137 log_stderr("failure: sys_mount_setattr");
9141 /* Verify that ownership looks correct for callers in the init userns. */
9142 for (id = 0; id <= id_file_range; id++) {
9144 unsigned int id_level1, id_level2, id_level3;
9147 snprintf(file, sizeof(file), FILE1 "_%u", id);
9149 id_level1 = id + 1000000;
9150 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) {
9151 log_stderr("failure: check ownership %s", file);
9155 id_level2 = id + 2000000;
9156 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) {
9157 log_stderr("failure: check ownership %s", file);
9162 /* This id is unmapped. */
9163 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9164 } else if (id == 1000) {
9165 id_level3 = id + 2000000; /* We punched a hole in the map at 1000. */
9166 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9168 id_level3 = id + 3000000; /* Rest is business as usual. */
9169 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9172 log_stderr("failure: check ownership %s", file);
9176 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid)) {
9177 log_stderr("failure: check ownership %s", file);
9182 /* Verify that ownership looks correct for callers in the first userns. */
9185 log_stderr("failure: fork");
9189 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9190 die("failure: switch_userns");
9192 for (id = 0; id <= id_file_range; id++) {
9194 unsigned int id_level1, id_level2, id_level3;
9197 snprintf(file, sizeof(file), FILE1 "_%u", id);
9200 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9201 die("failure: check ownership %s", file);
9203 id_level2 = id + 1000000;
9204 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9205 die("failure: check ownership %s", file);
9208 /* This id is unmapped. */
9209 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9210 } else if (id == 1000) {
9211 id_level3 = id + 1000000; /* We punched a hole in the map at 1000. */
9212 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9214 id_level3 = id + 2000000; /* Rest is business as usual. */
9215 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9218 die("failure: check ownership %s", file);
9220 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9221 die("failure: check ownership %s", file);
9226 if (wait_for_pid(pid))
9229 /* Verify that ownership looks correct for callers in the second userns. */
9232 log_stderr("failure: fork");
9236 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9237 die("failure: switch_userns");
9239 for (id = 0; id <= id_file_range; id++) {
9241 unsigned int id_level2, id_level3;
9244 snprintf(file, sizeof(file), FILE1 "_%u", id);
9246 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9247 die("failure: check ownership %s", file);
9250 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9251 die("failure: check ownership %s", file);
9254 /* This id is unmapped. */
9255 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9256 } else if (id == 1000) {
9257 id_level3 = id; /* We punched a hole in the map at 1000. */
9258 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9260 id_level3 = id + 1000000; /* Rest is business as usual. */
9261 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9264 die("failure: check ownership %s", file);
9266 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9267 die("failure: check ownership %s", file);
9272 if (wait_for_pid(pid))
9275 /* Verify that ownership looks correct for callers in the third userns. */
9278 log_stderr("failure: fork");
9282 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9283 die("failure: switch_userns");
9285 for (id = 0; id <= id_file_range; id++) {
9287 unsigned int id_level2, id_level3;
9290 snprintf(file, sizeof(file), FILE1 "_%u", id);
9292 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9293 die("failure: check ownership %s", file);
9297 * The idmapping of the third userns has a hole
9298 * at uid/gid 1000. That means:
9299 * - 1000->userns_0(2000000) // init userns
9300 * - 1000->userns_1(2000000) // level 1
9301 * - 1000->userns_2(1000000) // level 2
9302 * - 1000->userns_3(1000) // level 3 (because level 3 has a hole)
9305 bret = expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2);
9307 bret = expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid);
9310 die("failure: check ownership %s", file);
9314 /* This id is unmapped. */
9315 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9317 id_level3 = id; /* Rest is business as usual. */
9318 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9321 die("failure: check ownership %s", file);
9323 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9324 die("failure: check ownership %s", file);
9329 if (wait_for_pid(pid))
9332 /* Verify that ownership looks correct for callers in the fourth userns. */
9335 log_stderr("failure: fork");
9339 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9340 die("failure: switch_userns");
9342 for (id = 0; id <= id_file_range; id++) {
9345 snprintf(file, sizeof(file), FILE1 "_%u", id);
9347 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9348 die("failure: check ownership %s", file);
9350 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9351 die("failure: check ownership %s", file);
9353 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9354 die("failure: check ownership %s", file);
9356 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9357 die("failure: check ownership %s", file);
9362 if (wait_for_pid(pid))
9365 /* Verify that chown works correctly for callers in the first userns. */
9368 log_stderr("failure: fork");
9372 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9373 die("failure: switch_userns");
9375 for (id = 0; id <= id_file_range; id++) {
9377 unsigned int id_level1, id_level2, id_level3, id_new;
9380 snprintf(file, sizeof(file), FILE1 "_%u", id);
9383 if (fchownat(fd_open_tree_level1, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9384 die("failure: fchownat %s", file);
9387 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9388 die("failure: check ownership %s", file);
9390 id_level2 = id_new + 1000000;
9391 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9392 die("failure: check ownership %s", file);
9394 if (id_new == 999) {
9395 /* This id is unmapped. */
9396 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9397 } else if (id_new == 1000) {
9398 id_level3 = id_new + 1000000; /* We punched a hole in the map at 1000. */
9399 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9401 id_level3 = id_new + 2000000; /* Rest is business as usual. */
9402 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9405 die("failure: check ownership %s", file);
9407 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9408 die("failure: check ownership %s", file);
9410 /* Revert ownership. */
9411 if (fchownat(fd_open_tree_level1, file, id, id, AT_SYMLINK_NOFOLLOW))
9412 die("failure: fchownat %s", file);
9417 if (wait_for_pid(pid))
9420 /* Verify that chown works correctly for callers in the second userns. */
9423 log_stderr("failure: fork");
9427 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9428 die("failure: switch_userns");
9430 for (id = 0; id <= id_file_range; id++) {
9432 unsigned int id_level2, id_level3, id_new;
9435 snprintf(file, sizeof(file), FILE1 "_%u", id);
9438 if (fchownat(fd_open_tree_level2, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9439 die("failure: fchownat %s", file);
9441 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9442 die("failure: check ownership %s", file);
9445 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9446 die("failure: check ownership %s", file);
9448 if (id_new == 999) {
9449 /* This id is unmapped. */
9450 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9451 } else if (id_new == 1000) {
9452 id_level3 = id_new; /* We punched a hole in the map at 1000. */
9453 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9455 id_level3 = id_new + 1000000; /* Rest is business as usual. */
9456 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9459 die("failure: check ownership %s", file);
9461 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9462 die("failure: check ownership %s", file);
9464 /* Revert ownership. */
9465 if (fchownat(fd_open_tree_level2, file, id, id, AT_SYMLINK_NOFOLLOW))
9466 die("failure: fchownat %s", file);
9471 if (wait_for_pid(pid))
9474 /* Verify that chown works correctly for callers in the third userns. */
9477 log_stderr("failure: fork");
9481 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9482 die("failure: switch_userns");
9484 for (id = 0; id <= id_file_range; id++) {
9485 unsigned int id_new;
9488 snprintf(file, sizeof(file), FILE1 "_%u", id);
9491 if (id_new == 999 || id_new == 1000) {
9493 * We can't change ownership as we can't
9494 * chown from or to an unmapped id.
9496 if (!fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9497 die("failure: fchownat %s", file);
9499 if (fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9500 die("failure: fchownat %s", file);
9503 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9504 die("failure: check ownership %s", file);
9506 /* There's no id 1000 anymore as we changed ownership for id 1000 to 1001 above. */
9507 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9508 die("failure: check ownership %s", file);
9510 if (id_new == 999) {
9512 * We did not change ownership as we can't
9513 * chown to an unmapped id.
9515 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id, id))
9516 die("failure: check ownership %s", file);
9517 } else if (id_new == 1000) {
9519 * We did not change ownership as we can't
9520 * chown from an unmapped id.
9522 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9523 die("failure: check ownership %s", file);
9525 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id_new, id_new))
9526 die("failure: check ownership %s", file);
9529 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9530 die("failure: check ownership %s", file);
9532 /* Revert ownership. */
9533 if (id_new != 999 && id_new != 1000) {
9534 if (fchownat(fd_open_tree_level3, file, id, id, AT_SYMLINK_NOFOLLOW))
9535 die("failure: fchownat %s", file);
9541 if (wait_for_pid(pid))
9544 /* Verify that chown works correctly for callers in the fourth userns. */
9547 log_stderr("failure: fork");
9551 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9552 die("failure: switch_userns");
9554 for (id = 0; id <= id_file_range; id++) {
9556 unsigned long id_new;
9558 snprintf(file, sizeof(file), FILE1 "_%u", id);
9561 if (!fchownat(fd_open_tree_level4, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9562 die("failure: fchownat %s", file);
9564 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9565 die("failure: check ownership %s", file);
9567 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9568 die("failure: check ownership %s", file);
9570 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9571 die("failure: check ownership %s", file);
9573 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9574 die("failure: check ownership %s", file);
9580 if (wait_for_pid(pid))
9584 log_debug("Ran test");
9587 list_for_each_safe(it, &hierarchy[0].id_map, next) {
9593 list_for_each_safe(it, &hierarchy[1].id_map, next) {
9599 list_for_each_safe(it, &hierarchy[2].id_map, next) {
9605 safe_close(hierarchy[0].fd_userns);
9606 safe_close(hierarchy[1].fd_userns);
9607 safe_close(hierarchy[2].fd_userns);
9608 safe_close(fd_dir1);
9609 safe_close(fd_open_tree_level1);
9610 safe_close(fd_open_tree_level2);
9611 safe_close(fd_open_tree_level3);
9612 safe_close(fd_open_tree_level4);
9616 #ifndef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS
9618 #ifndef BTRFS_PATH_NAME_MAX
9619 #define BTRFS_PATH_NAME_MAX 4087
9622 struct btrfs_ioctl_vol_args {
9624 char name[BTRFS_PATH_NAME_MAX + 1];
9628 #ifndef HAVE_STRUCT_BTRFS_QGROUP_LIMIT
9629 struct btrfs_qgroup_limit {
9638 #ifndef HAVE_STRUCT_BTRFS_QGROUP_INHERIT
9639 struct btrfs_qgroup_inherit {
9642 __u64 num_ref_copies;
9643 __u64 num_excl_copies;
9644 struct btrfs_qgroup_limit lim;
9649 #if !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2) || !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2_SUBVOLID)
9651 #ifndef BTRFS_SUBVOL_NAME_MAX
9652 #define BTRFS_SUBVOL_NAME_MAX 4039
9655 struct btrfs_ioctl_vol_args_v2 {
9662 struct btrfs_qgroup_inherit *qgroup_inherit;
9667 char name[BTRFS_SUBVOL_NAME_MAX + 1];
9674 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_ARGS
9676 #ifndef BTRFS_INO_LOOKUP_PATH_MAX
9677 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
9679 struct btrfs_ioctl_ino_lookup_args {
9682 char name[BTRFS_INO_LOOKUP_PATH_MAX];
9686 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_USER_ARGS
9688 #ifndef BTRFS_VOL_NAME_MAX
9689 #define BTRFS_VOL_NAME_MAX 255
9692 #ifndef BTRFS_INO_LOOKUP_USER_PATH_MAX
9693 #define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1)
9696 struct btrfs_ioctl_ino_lookup_user_args {
9699 char name[BTRFS_VOL_NAME_MAX + 1];
9700 char path[BTRFS_INO_LOOKUP_USER_PATH_MAX];
9704 #ifndef HAVE_STRUCT_BTRFS_IOCTL_GET_SUBVOL_ROOTREF_ARGS
9706 #ifndef BTRFS_MAX_ROOTREF_BUFFER_NUM
9707 #define BTRFS_MAX_ROOTREF_BUFFER_NUM 255
9710 struct btrfs_ioctl_get_subvol_rootref_args {
9715 } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
9721 #ifndef BTRFS_IOCTL_MAGIC
9722 #define BTRFS_IOCTL_MAGIC 0x94
9725 #ifndef BTRFS_IOC_SNAP_DESTROY
9726 #define BTRFS_IOC_SNAP_DESTROY \
9727 _IOW(BTRFS_IOCTL_MAGIC, 15, struct btrfs_ioctl_vol_args)
9730 #ifndef BTRFS_IOC_SNAP_DESTROY_V2
9731 #define BTRFS_IOC_SNAP_DESTROY_V2 \
9732 _IOW(BTRFS_IOCTL_MAGIC, 63, struct btrfs_ioctl_vol_args_v2)
9735 #ifndef BTRFS_IOC_SNAP_CREATE_V2
9736 #define BTRFS_IOC_SNAP_CREATE_V2 \
9737 _IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
9740 #ifndef BTRFS_IOC_SUBVOL_CREATE_V2
9741 #define BTRFS_IOC_SUBVOL_CREATE_V2 \
9742 _IOW(BTRFS_IOCTL_MAGIC, 24, struct btrfs_ioctl_vol_args_v2)
9745 #ifndef BTRFS_IOC_SUBVOL_GETFLAGS
9746 #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
9749 #ifndef BTRFS_IOC_SUBVOL_SETFLAGS
9750 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
9753 #ifndef BTRFS_IOC_INO_LOOKUP
9754 #define BTRFS_IOC_INO_LOOKUP \
9755 _IOWR(BTRFS_IOCTL_MAGIC, 18, struct btrfs_ioctl_ino_lookup_args)
9758 #ifndef BTRFS_IOC_INO_LOOKUP_USER
9759 #define BTRFS_IOC_INO_LOOKUP_USER \
9760 _IOWR(BTRFS_IOCTL_MAGIC, 62, struct btrfs_ioctl_ino_lookup_user_args)
9763 #ifndef BTRFS_IOC_GET_SUBVOL_ROOTREF
9764 #define BTRFS_IOC_GET_SUBVOL_ROOTREF \
9765 _IOWR(BTRFS_IOCTL_MAGIC, 61, struct btrfs_ioctl_get_subvol_rootref_args)
9768 #ifndef BTRFS_SUBVOL_RDONLY
9769 #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
9772 #ifndef BTRFS_SUBVOL_SPEC_BY_ID
9773 #define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4)
9776 #ifndef BTRFS_FIRST_FREE_OBJECTID
9777 #define BTRFS_FIRST_FREE_OBJECTID 256ULL
9780 static int btrfs_delete_subvolume(int parent_fd, const char *name)
9782 struct btrfs_ioctl_vol_args args = {};
9787 if (len >= sizeof(args.name))
9788 return -ENAMETOOLONG;
9790 memcpy(args.name, name, len);
9791 args.name[len] = '\0';
9793 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY, &args);
9800 static int btrfs_delete_subvolume_id(int parent_fd, uint64_t subvolid)
9802 struct btrfs_ioctl_vol_args_v2 args = {};
9805 args.flags = BTRFS_SUBVOL_SPEC_BY_ID;
9806 args.subvolid = subvolid;
9808 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY_V2, &args);
9815 static int btrfs_create_subvolume(int parent_fd, const char *name)
9817 struct btrfs_ioctl_vol_args_v2 args = {};
9822 if (len >= sizeof(args.name))
9823 return -ENAMETOOLONG;
9825 memcpy(args.name, name, len);
9826 args.name[len] = '\0';
9828 ret = ioctl(parent_fd, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
9835 static int btrfs_create_snapshot(int fd, int parent_fd, const char *name,
9838 struct btrfs_ioctl_vol_args_v2 args = {
9844 if (flags & ~BTRFS_SUBVOL_RDONLY)
9848 if (len >= sizeof(args.name))
9849 return -ENAMETOOLONG;
9850 memcpy(args.name, name, len);
9851 args.name[len] = '\0';
9853 if (flags & BTRFS_SUBVOL_RDONLY)
9854 args.flags |= BTRFS_SUBVOL_RDONLY;
9855 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_CREATE_V2, &args);
9862 static int btrfs_get_subvolume_ro(int fd, bool *read_only_ret)
9867 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9871 *read_only_ret = flags & BTRFS_SUBVOL_RDONLY;
9875 static int btrfs_set_subvolume_ro(int fd, bool read_only)
9880 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9885 flags |= BTRFS_SUBVOL_RDONLY;
9887 flags &= ~BTRFS_SUBVOL_RDONLY;
9889 ret = ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
9896 static int btrfs_get_subvolume_id(int fd, uint64_t *id_ret)
9898 struct btrfs_ioctl_ino_lookup_args args = {
9900 .objectid = BTRFS_FIRST_FREE_OBJECTID,
9904 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
9908 *id_ret = args.treeid;
9914 * The following helpers are adapted from the btrfsutils library. We can't use
9915 * the library directly since we need full control over how the subvolume
9916 * iteration happens. We need to be able to check whether unprivileged
9917 * subvolume iteration is possible, i.e. whether BTRFS_IOC_INO_LOOKUP_USER is
9918 * available and also ensure that it is actually used when looking up paths.
9920 struct btrfs_stack {
9922 struct btrfs_ioctl_get_subvol_rootref_args rootref_args;
9931 struct btrfs_stack *search_stack;
9933 size_t stack_capacity;
9936 size_t cur_path_capacity;
9939 static struct btrfs_stack *top_stack_entry(struct btrfs_iter *iter)
9941 return &iter->search_stack[iter->stack_len - 1];
9944 static int pop_stack(struct btrfs_iter *iter)
9946 struct btrfs_stack *top, *parent;
9950 if (iter->stack_len == 1) {
9955 top = top_stack_entry(iter);
9957 parent = top_stack_entry(iter);
9960 for (i = parent->path_len; i < top->path_len; i++) {
9961 if (i == 0 || iter->cur_path[i] == '/') {
9962 parent_fd = openat(fd, "..", O_RDONLY);
9963 if (fd != iter->cur_fd)
9965 if (parent_fd == -1)
9970 if (iter->cur_fd != iter->fd)
9971 close(iter->cur_fd);
9977 static int append_stack(struct btrfs_iter *iter, uint64_t tree_id, size_t path_len)
9979 struct btrfs_stack *entry;
9981 if (iter->stack_len >= iter->stack_capacity) {
9982 size_t new_capacity = iter->stack_capacity * 2;
9983 struct btrfs_stack *new_search_stack;
9984 #ifdef HAVE_REALLOCARRAY
9985 new_search_stack = reallocarray(iter->search_stack, new_capacity,
9986 sizeof(*iter->search_stack));
9988 new_search_stack = realloc(iter->search_stack, new_capacity * sizeof(*iter->search_stack));
9990 if (!new_search_stack)
9993 iter->stack_capacity = new_capacity;
9994 iter->search_stack = new_search_stack;
9997 entry = &iter->search_stack[iter->stack_len];
9999 memset(entry, 0, sizeof(*entry));
10000 entry->path_len = path_len;
10001 entry->tree_id = tree_id;
10003 if (iter->stack_len) {
10004 struct btrfs_stack *top;
10008 top = top_stack_entry(iter);
10009 path = &iter->cur_path[top->path_len];
10012 fd = openat(iter->cur_fd, path, O_RDONLY);
10016 close(iter->cur_fd);
10025 static int btrfs_iterator_start(int fd, uint64_t top, struct btrfs_iter **ret)
10027 struct btrfs_iter *iter;
10030 iter = malloc(sizeof(*iter));
10037 iter->stack_len = 0;
10038 iter->stack_capacity = 4;
10039 iter->search_stack = malloc(sizeof(*iter->search_stack) *
10040 iter->stack_capacity);
10041 if (!iter->search_stack) {
10046 iter->cur_path_capacity = 256;
10047 iter->cur_path = malloc(iter->cur_path_capacity);
10048 if (!iter->cur_path) {
10050 goto out_search_stack;
10053 err = append_stack(iter, top, 0);
10062 free(iter->cur_path);
10064 free(iter->search_stack);
10070 static void btrfs_iterator_end(struct btrfs_iter *iter)
10073 free(iter->cur_path);
10074 free(iter->search_stack);
10075 if (iter->cur_fd != iter->fd)
10076 close(iter->cur_fd);
10082 static int __append_path(struct btrfs_iter *iter, const char *name,
10083 size_t name_len, const char *dir, size_t dir_len,
10084 size_t *path_len_ret)
10086 struct btrfs_stack *top = top_stack_entry(iter);
10090 path_len = top->path_len;
10092 * We need a joining slash if we have a current path and a subdirectory.
10094 if (top->path_len && dir_len)
10096 path_len += dir_len;
10098 * We need another joining slash if we have a current path and a name,
10099 * but not if we have a subdirectory, because the lookup ioctl includes
10100 * a trailing slash.
10102 if (top->path_len && !dir_len && name_len)
10104 path_len += name_len;
10106 /* We need one extra character for the NUL terminator. */
10107 if (path_len + 1 > iter->cur_path_capacity) {
10108 char *tmp = realloc(iter->cur_path, path_len + 1);
10112 iter->cur_path = tmp;
10113 iter->cur_path_capacity = path_len + 1;
10116 p = iter->cur_path + top->path_len;
10117 if (top->path_len && dir_len)
10119 memcpy(p, dir, dir_len);
10121 if (top->path_len && !dir_len && name_len)
10123 memcpy(p, name, name_len);
10127 *path_len_ret = path_len;
10132 static int get_subvolume_path(struct btrfs_iter *iter, uint64_t treeid,
10133 uint64_t dirid, size_t *path_len_ret)
10135 struct btrfs_ioctl_ino_lookup_user_args args = {
10141 ret = ioctl(iter->cur_fd, BTRFS_IOC_INO_LOOKUP_USER, &args);
10145 return __append_path(iter, args.name, strlen(args.name), args.path,
10146 strlen(args.path), path_len_ret);
10149 static int btrfs_iterator_next(struct btrfs_iter *iter, char **path_ret,
10152 struct btrfs_stack *top;
10153 uint64_t treeid, dirid;
10159 if (iter->stack_len == 0)
10162 top = top_stack_entry(iter);
10163 if (top->items_pos < top->rootref_args.num_items) {
10166 ret = ioctl(iter->cur_fd,
10167 BTRFS_IOC_GET_SUBVOL_ROOTREF,
10168 &top->rootref_args);
10169 if (ret == -1 && errno != EOVERFLOW)
10171 top->items_pos = 0;
10173 if (top->rootref_args.num_items == 0) {
10174 err = pop_stack(iter);
10181 treeid = top->rootref_args.rootref[top->items_pos].treeid;
10182 dirid = top->rootref_args.rootref[top->items_pos].dirid;
10184 err = get_subvolume_path(iter, treeid, dirid, &path_len);
10186 /* Skip the subvolume if we can't access it. */
10187 if (errno == EACCES)
10192 err = append_stack(iter, treeid, path_len);
10195 * Skip the subvolume if it does not exist (which can
10196 * happen if there is another filesystem mounted over a
10197 * parent directory) or we don't have permission to
10200 if (errno == ENOENT || errno == EACCES)
10205 top = top_stack_entry(iter);
10211 *path_ret = malloc(top->path_len + 1);
10214 memcpy(*path_ret, iter->cur_path, top->path_len);
10215 (*path_ret)[top->path_len] = '\0';
10218 *id_ret = top->tree_id;
10222 #define BTRFS_SUBVOLUME1 "subvol1"
10223 #define BTRFS_SUBVOLUME1_SNAPSHOT1 "subvol1_snapshot1"
10224 #define BTRFS_SUBVOLUME1_SNAPSHOT1_RO "subvol1_snapshot1_ro"
10225 #define BTRFS_SUBVOLUME1_RENAME "subvol1_rename"
10226 #define BTRFS_SUBVOLUME2 "subvol2"
10228 static int btrfs_subvolumes_fsids_mapped(void)
10231 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10232 struct mount_attr attr = {
10233 .attr_set = MOUNT_ATTR_IDMAP,
10237 if (!caps_supported())
10240 /* Changing mount properties on a detached mount. */
10241 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10242 if (attr.userns_fd < 0) {
10243 log_stderr("failure: get_userns_fd");
10247 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10250 AT_SYMLINK_NOFOLLOW |
10251 OPEN_TREE_CLOEXEC |
10253 if (open_tree_fd < 0) {
10254 log_stderr("failure: sys_open_tree");
10258 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10259 log_stderr("failure: sys_mount_setattr");
10264 * The open_tree() syscall returns an O_PATH file descriptor which we
10265 * can't use with ioctl(). So let's reopen it as a proper file
10268 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10270 log_stderr("failure: openat");
10276 log_stderr("failure: fork");
10280 if (!switch_fsids(10000, 10000))
10281 die("failure: switch fsids");
10284 die("failure: raise caps");
10287 * The caller's fsids now have mappings in the idmapped mount so
10288 * any file creation must succeed.
10291 /* create subvolume */
10292 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10293 die("failure: btrfs_create_subvolume");
10295 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10296 die("failure: check ownership");
10298 /* remove subvolume */
10299 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10300 die("failure: btrfs_delete_subvolume");
10302 /* create subvolume */
10303 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10304 die("failure: btrfs_create_subvolume");
10306 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10307 die("failure: check ownership");
10310 die("failure: lower caps");
10313 * The filesystem is not mounted with user_subvol_rm_allowed so
10314 * subvolume deletion must fail.
10316 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10317 die("failure: btrfs_delete_subvolume");
10318 if (errno != EPERM)
10319 die("failure: errno");
10321 exit(EXIT_SUCCESS);
10323 if (wait_for_pid(pid))
10326 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10327 die("failure: check ownership");
10329 /* remove subvolume */
10330 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10331 log_stderr("failure: btrfs_delete_subvolume");
10336 log_debug("Ran test");
10338 safe_close(attr.userns_fd);
10339 safe_close(open_tree_fd);
10340 safe_close(tree_fd);
10345 static int btrfs_subvolumes_fsids_mapped_userns(void)
10348 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10349 struct mount_attr attr = {
10350 .attr_set = MOUNT_ATTR_IDMAP,
10354 if (!caps_supported())
10357 /* Changing mount properties on a detached mount. */
10358 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10359 if (attr.userns_fd < 0) {
10360 log_stderr("failure: get_userns_fd");
10364 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10367 AT_SYMLINK_NOFOLLOW |
10368 OPEN_TREE_CLOEXEC |
10370 if (open_tree_fd < 0) {
10371 log_stderr("failure: sys_open_tree");
10375 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10376 log_stderr("failure: sys_mount_setattr");
10381 * The open_tree() syscall returns an O_PATH file descriptor which we
10382 * can't use with ioctl(). So let's reopen it as a proper file
10385 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10387 log_stderr("failure: openat");
10393 log_stderr("failure: fork");
10397 if (!switch_userns(attr.userns_fd, 0, 0, false))
10398 die("failure: switch_userns");
10400 /* The caller's fsids now have mappings in the idmapped mount so
10401 * any file creation must fail.
10404 /* create subvolume */
10405 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10406 die("failure: btrfs_create_subvolume");
10408 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10409 die("failure: check ownership");
10411 /* remove subvolume */
10412 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10413 die("failure: btrfs_delete_subvolume");
10415 exit(EXIT_SUCCESS);
10417 if (wait_for_pid(pid))
10420 /* remove subvolume */
10421 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10422 log_stderr("failure: btrfs_delete_subvolume");
10427 log_debug("Ran test");
10429 safe_close(attr.userns_fd);
10430 safe_close(open_tree_fd);
10431 safe_close(tree_fd);
10436 static int btrfs_subvolumes_fsids_unmapped(void)
10439 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10440 struct mount_attr attr = {
10441 .attr_set = MOUNT_ATTR_IDMAP,
10444 /* create directory for rename test */
10445 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10446 log_stderr("failure: btrfs_create_subvolume");
10450 /* change ownership of all files to uid 0 */
10451 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10452 log_stderr("failure: fchownat");
10456 /* Changing mount properties on a detached mount. */
10457 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10458 if (attr.userns_fd < 0) {
10459 log_stderr("failure: get_userns_fd");
10463 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10466 AT_SYMLINK_NOFOLLOW |
10467 OPEN_TREE_CLOEXEC |
10469 if (open_tree_fd < 0) {
10470 log_stderr("failure: sys_open_tree");
10474 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10475 log_stderr("failure: sys_mount_setattr");
10479 if (!switch_fsids(0, 0)) {
10480 log_stderr("failure: switch_fsids");
10485 * The caller's fsids don't have a mappings in the idmapped mount so
10486 * any file creation must fail.
10490 * The open_tree() syscall returns an O_PATH file descriptor which we
10491 * can't use with ioctl(). So let's reopen it as a proper file
10494 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10496 log_stderr("failure: openat");
10500 /* create subvolume */
10501 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2)) {
10502 log_stderr("failure: btrfs_create_subvolume");
10505 if (errno != EOVERFLOW) {
10506 log_stderr("failure: errno");
10510 /* try to rename a subvolume */
10511 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10512 BTRFS_SUBVOLUME1_RENAME)) {
10513 log_stderr("failure: renameat");
10516 if (errno != EOVERFLOW) {
10517 log_stderr("failure: errno");
10521 /* The caller is privileged over the inode so file deletion must work. */
10523 /* remove subvolume */
10524 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10525 log_stderr("failure: btrfs_delete_subvolume");
10530 log_debug("Ran test");
10532 safe_close(attr.userns_fd);
10533 safe_close(open_tree_fd);
10534 safe_close(tree_fd);
10539 static int btrfs_subvolumes_fsids_unmapped_userns(void)
10542 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
10543 struct mount_attr attr = {
10544 .attr_set = MOUNT_ATTR_IDMAP,
10548 /* create directory for rename test */
10549 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10550 log_stderr("failure: btrfs_create_subvolume");
10554 /* change ownership of all files to uid 0 */
10555 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10556 log_stderr("failure: fchownat");
10560 /* Changing mount properties on a detached mount. */
10561 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10562 if (attr.userns_fd < 0) {
10563 log_stderr("failure: get_userns_fd");
10567 /* Changing mount properties on a detached mount. */
10568 userns_fd = get_userns_fd(0, 30000, 10000);
10569 if (userns_fd < 0) {
10570 log_stderr("failure: get_userns_fd");
10574 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10577 AT_SYMLINK_NOFOLLOW |
10578 OPEN_TREE_CLOEXEC |
10580 if (open_tree_fd < 0) {
10581 log_stderr("failure: sys_open_tree");
10585 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10586 log_stderr("failure: sys_mount_setattr");
10591 * The open_tree() syscall returns an O_PATH file descriptor which we
10592 * can't use with ioctl(). So let's reopen it as a proper file
10595 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10597 log_stderr("failure: openat");
10603 log_stderr("failure: fork");
10607 if (!switch_userns(userns_fd, 0, 0, false))
10608 die("failure: switch_userns");
10610 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
10611 t_overflowuid, t_overflowgid))
10612 die("failure: expected_uid_gid");
10614 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
10615 t_overflowuid, t_overflowgid))
10616 die("failure: expected_uid_gid");
10619 * The caller's fsids don't have a mappings in the idmapped mount so
10620 * any file creation must fail.
10623 /* create subvolume */
10624 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
10625 die("failure: btrfs_create_subvolume");
10626 if (errno != EOVERFLOW)
10627 die("failure: errno");
10629 /* try to rename a subvolume */
10630 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10631 BTRFS_SUBVOLUME1_RENAME))
10632 die("failure: renameat");
10633 if (errno != EOVERFLOW)
10634 die("failure: errno");
10637 * The caller is not privileged over the inode so subvolume
10638 * deletion must fail.
10641 /* remove subvolume */
10642 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10643 die("failure: btrfs_delete_subvolume");
10645 exit(EXIT_SUCCESS);
10647 if (wait_for_pid(pid))
10650 /* remove subvolume */
10651 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10652 log_stderr("failure: btrfs_delete_subvolume");
10657 log_debug("Ran test");
10659 safe_close(attr.userns_fd);
10660 safe_close(open_tree_fd);
10661 safe_close(tree_fd);
10662 safe_close(userns_fd);
10667 static int btrfs_snapshots_fsids_mapped(void)
10670 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10671 struct mount_attr attr = {
10672 .attr_set = MOUNT_ATTR_IDMAP,
10676 if (!caps_supported())
10679 /* Changing mount properties on a detached mount. */
10680 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10681 if (attr.userns_fd < 0) {
10682 log_stderr("failure: get_userns_fd");
10686 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10689 AT_SYMLINK_NOFOLLOW |
10690 OPEN_TREE_CLOEXEC |
10692 if (open_tree_fd < 0) {
10693 log_stderr("failure: sys_open_tree");
10697 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10698 log_stderr("failure: sys_mount_setattr");
10703 * The open_tree() syscall returns an O_PATH file descriptor which we
10704 * can't use with ioctl(). So let's reopen it as a proper file
10707 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10709 log_stderr("failure: openat");
10715 log_stderr("failure: fork");
10719 int subvolume_fd = -EBADF;
10721 if (!switch_fsids(10000, 10000))
10722 die("failure: switch fsids");
10725 die("failure: raise caps");
10727 /* The caller's fsids now have mappings in the idmapped mount so
10728 * any file creation must fail.
10731 /* create subvolume */
10732 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10733 die("failure: btrfs_create_subvolume");
10735 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10736 die("failure: expected_uid_gid");
10738 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10739 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10740 if (subvolume_fd < 0)
10741 die("failure: openat");
10743 /* create read-write snapshot */
10744 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10745 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10746 die("failure: btrfs_create_snapshot");
10748 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10749 die("failure: expected_uid_gid");
10751 /* create read-only snapshot */
10752 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10753 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10754 BTRFS_SUBVOL_RDONLY))
10755 die("failure: btrfs_create_snapshot");
10757 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10758 die("failure: expected_uid_gid");
10760 safe_close(subvolume_fd);
10762 /* remove subvolume */
10763 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10764 die("failure: btrfs_delete_subvolume");
10766 /* remove read-write snapshot */
10767 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
10768 die("failure: btrfs_delete_subvolume");
10770 /* remove read-only snapshot */
10771 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
10772 die("failure: btrfs_delete_subvolume");
10774 /* create directory */
10775 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10776 die("failure: btrfs_create_subvolume");
10778 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10779 die("failure: expected_uid_gid");
10781 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10782 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10783 if (subvolume_fd < 0)
10784 die("failure: openat");
10786 /* create read-write snapshot */
10787 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10788 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10789 die("failure: btrfs_create_snapshot");
10791 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10792 die("failure: expected_uid_gid");
10794 /* create read-only snapshot */
10795 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10796 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10797 BTRFS_SUBVOL_RDONLY))
10798 die("failure: btrfs_create_snapshot");
10800 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10801 die("failure: expected_uid_gid");
10803 safe_close(subvolume_fd);
10805 exit(EXIT_SUCCESS);
10807 if (wait_for_pid(pid))
10810 /* remove directory */
10811 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10812 log_stderr("failure: btrfs_delete_subvolume");
10816 /* remove read-write snapshot */
10817 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10818 log_stderr("failure: btrfs_delete_subvolume");
10822 /* remove read-only snapshot */
10823 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10824 log_stderr("failure: btrfs_delete_subvolume");
10829 log_debug("Ran test");
10831 safe_close(attr.userns_fd);
10832 safe_close(open_tree_fd);
10833 safe_close(tree_fd);
10838 static int btrfs_snapshots_fsids_mapped_userns(void)
10841 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10842 struct mount_attr attr = {
10843 .attr_set = MOUNT_ATTR_IDMAP,
10847 if (!caps_supported())
10850 /* Changing mount properties on a detached mount. */
10851 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10852 if (attr.userns_fd < 0) {
10853 log_stderr("failure: get_userns_fd");
10857 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10860 AT_SYMLINK_NOFOLLOW |
10861 OPEN_TREE_CLOEXEC |
10863 if (open_tree_fd < 0) {
10864 log_stderr("failure: sys_open_tree");
10868 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10869 log_stderr("failure: sys_mount_setattr");
10874 * The open_tree() syscall returns an O_PATH file descriptor which we
10875 * can't use with ioctl(). So let's reopen it as a proper file
10878 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10880 log_stderr("failure: openat");
10886 log_stderr("failure: fork");
10890 int subvolume_fd = -EBADF;
10892 if (!switch_userns(attr.userns_fd, 0, 0, false))
10893 die("failure: switch_userns");
10895 /* create subvolume */
10896 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10897 die("failure: btrfs_create_subvolume");
10899 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10900 die("failure: expected_uid_gid");
10902 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10903 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10904 if (subvolume_fd < 0)
10905 die("failure: openat");
10907 /* create read-write snapshot */
10908 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10909 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10910 die("failure: btrfs_create_snapshot");
10912 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
10913 die("failure: expected_uid_gid");
10915 /* create read-only snapshot */
10916 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10917 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10918 BTRFS_SUBVOL_RDONLY))
10919 die("failure: btrfs_create_snapshot");
10921 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
10922 die("failure: expected_uid_gid");
10924 safe_close(subvolume_fd);
10926 exit(EXIT_SUCCESS);
10928 if (wait_for_pid(pid))
10931 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10932 die("failure: expected_uid_gid");
10934 /* remove directory */
10935 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10936 log_stderr("failure: btrfs_delete_subvolume");
10940 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10941 die("failure: expected_uid_gid");
10943 /* remove read-write snapshot */
10944 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10945 log_stderr("failure: btrfs_delete_subvolume");
10949 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10950 die("failure: expected_uid_gid");
10952 /* remove read-only snapshot */
10953 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10954 log_stderr("failure: btrfs_delete_subvolume");
10959 log_debug("Ran test");
10961 safe_close(attr.userns_fd);
10962 safe_close(open_tree_fd);
10963 safe_close(tree_fd);
10968 static int btrfs_snapshots_fsids_unmapped(void)
10971 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10972 struct mount_attr attr = {
10973 .attr_set = MOUNT_ATTR_IDMAP,
10977 if (!caps_supported())
10980 /* create directory for rename test */
10981 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10982 log_stderr("failure: btrfs_create_subvolume");
10986 /* change ownership of all files to uid 0 */
10987 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10988 log_stderr("failure: fchownat");
10992 /* Changing mount properties on a detached mount. */
10993 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10994 if (attr.userns_fd < 0) {
10995 log_stderr("failure: get_userns_fd");
10999 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11002 AT_SYMLINK_NOFOLLOW |
11003 OPEN_TREE_CLOEXEC |
11005 if (open_tree_fd < 0) {
11006 log_stderr("failure: sys_open_tree");
11010 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
11012 log_stderr("failure: sys_mount_setattr");
11018 log_stderr("failure: fork");
11022 int subvolume_fd = -EBADF;
11024 if (!switch_fsids(0, 0)) {
11025 log_stderr("failure: switch_fsids");
11030 * The caller's fsids don't have a mappings in the idmapped
11031 * mount so any file creation must fail.
11035 * The open_tree() syscall returns an O_PATH file descriptor
11036 * which we can't use with ioctl(). So let's reopen it as a
11037 * proper file descriptor.
11039 tree_fd = openat(open_tree_fd, ".",
11040 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11042 die("failure: openat");
11044 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11045 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11046 if (subvolume_fd < 0)
11047 die("failure: openat");
11049 /* create directory */
11050 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
11051 die("failure: btrfs_create_subvolume");
11052 if (errno != EOVERFLOW)
11053 die("failure: errno");
11055 /* create read-write snapshot */
11056 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11057 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11058 die("failure: btrfs_create_snapshot");
11059 if (errno != EOVERFLOW)
11060 die("failure: errno");
11062 /* create read-only snapshot */
11063 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11064 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11065 BTRFS_SUBVOL_RDONLY))
11066 die("failure: btrfs_create_snapshot");
11067 if (errno != EOVERFLOW)
11068 die("failure: errno");
11070 /* try to rename a directory */
11071 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11072 BTRFS_SUBVOLUME1_RENAME))
11073 die("failure: renameat");
11074 if (errno != EOVERFLOW)
11075 die("failure: errno");
11078 die("failure: caps_down");
11080 /* create read-write snapshot */
11081 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11082 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11083 die("failure: btrfs_create_snapshot");
11084 if (errno != EPERM)
11085 die("failure: errno");
11087 /* create read-only snapshot */
11088 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11089 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11090 BTRFS_SUBVOL_RDONLY))
11091 die("failure: btrfs_create_snapshot");
11092 if (errno != EPERM)
11093 die("failure: errno");
11096 * The caller is not privileged over the inode so subvolume
11097 * deletion must fail.
11100 /* remove directory */
11101 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11102 die("failure: btrfs_delete_subvolume");
11103 if (errno != EPERM)
11104 die("failure: errno");
11107 die("failure: caps_down");
11110 * The caller is privileged over the inode so subvolume
11111 * deletion must work.
11114 /* remove directory */
11115 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11116 die("failure: btrfs_delete_subvolume");
11118 exit(EXIT_SUCCESS);
11120 if (wait_for_pid(pid))
11124 log_debug("Ran test");
11126 safe_close(attr.userns_fd);
11127 safe_close(open_tree_fd);
11128 safe_close(tree_fd);
11133 static int btrfs_snapshots_fsids_unmapped_userns(void)
11136 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
11137 userns_fd = -EBADF;
11138 struct mount_attr attr = {
11139 .attr_set = MOUNT_ATTR_IDMAP,
11143 if (!caps_supported())
11146 /* create directory for rename test */
11147 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
11148 log_stderr("failure: btrfs_create_subvolume");
11152 /* change ownership of all files to uid 0 */
11153 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
11154 log_stderr("failure: fchownat");
11158 /* Changing mount properties on a detached mount. */
11159 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11160 if (attr.userns_fd < 0) {
11161 log_stderr("failure: get_userns_fd");
11165 /* Changing mount properties on a detached mount. */
11166 userns_fd = get_userns_fd(0, 30000, 10000);
11167 if (userns_fd < 0) {
11168 log_stderr("failure: get_userns_fd");
11172 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11175 AT_SYMLINK_NOFOLLOW |
11176 OPEN_TREE_CLOEXEC |
11178 if (open_tree_fd < 0) {
11179 log_stderr("failure: sys_open_tree");
11183 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
11185 log_stderr("failure: sys_mount_setattr");
11190 * The open_tree() syscall returns an O_PATH file descriptor
11191 * which we can't use with ioctl(). So let's reopen it as a
11192 * proper file descriptor.
11194 tree_fd = openat(open_tree_fd, ".",
11195 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11197 log_stderr("failure: openat");
11201 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11202 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11203 if (subvolume_fd < 0) {
11204 log_stderr("failure: openat");
11210 log_stderr("failure: fork");
11214 if (!switch_userns(userns_fd, 0, 0, false))
11215 die("failure: switch_userns");
11217 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
11218 t_overflowuid, t_overflowgid))
11219 die("failure: expected_uid_gid");
11221 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
11222 t_overflowuid, t_overflowgid))
11223 die("failure: expected_uid_gid");
11226 * The caller's fsids don't have a mappings in the idmapped
11227 * mount so any file creation must fail.
11230 /* create directory */
11231 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
11232 die("failure: btrfs_create_subvolume");
11233 if (errno != EOVERFLOW)
11234 die("failure: errno");
11236 /* create read-write snapshot */
11237 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11238 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11239 die("failure: btrfs_create_snapshot");
11240 if (errno != EPERM)
11241 die("failure: errno");
11243 /* create read-only snapshot */
11244 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11245 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11246 BTRFS_SUBVOL_RDONLY))
11247 die("failure: btrfs_create_snapshot");
11248 if (errno != EPERM)
11249 die("failure: errno");
11251 /* try to rename a directory */
11252 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11253 BTRFS_SUBVOLUME1_RENAME))
11254 die("failure: renameat");
11255 if (errno != EOVERFLOW)
11256 die("failure: errno");
11259 * The caller is not privileged over the inode so subvolume
11260 * deletion must fail.
11263 /* remove directory */
11264 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11265 die("failure: btrfs_delete_subvolume");
11266 if (errno != EPERM)
11267 die("failure: errno");
11269 exit(EXIT_SUCCESS);
11271 if (wait_for_pid(pid))
11274 /* remove directory */
11275 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11276 die("failure: btrfs_delete_subvolume");
11279 log_debug("Ran test");
11281 safe_close(attr.userns_fd);
11282 safe_close(open_tree_fd);
11283 safe_close(subvolume_fd);
11284 safe_close(tree_fd);
11289 static int btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed(void)
11292 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11293 struct mount_attr attr = {
11294 .attr_set = MOUNT_ATTR_IDMAP,
11298 if (!caps_supported())
11301 /* Changing mount properties on a detached mount. */
11302 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11303 if (attr.userns_fd < 0) {
11304 log_stderr("failure: get_userns_fd");
11308 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11311 AT_SYMLINK_NOFOLLOW |
11312 OPEN_TREE_CLOEXEC |
11314 if (open_tree_fd < 0) {
11315 log_stderr("failure: sys_open_tree");
11319 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11320 log_stderr("failure: sys_mount_setattr");
11325 * The open_tree() syscall returns an O_PATH file descriptor which we
11326 * can't use with ioctl(). So let's reopen it as a proper file
11329 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11331 log_stderr("failure: openat");
11337 log_stderr("failure: fork");
11341 if (!switch_fsids(10000, 10000))
11342 die("failure: switch fsids");
11345 die("failure: raise caps");
11348 * The caller's fsids now have mappings in the idmapped mount so
11349 * any file creation must succedd.
11352 /* create subvolume */
11353 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11354 die("failure: btrfs_create_subvolume");
11356 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11357 die("failure: check ownership");
11360 * The scratch device is mounted with user_subvol_rm_allowed so
11361 * subvolume deletion must succeed.
11363 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11364 die("failure: btrfs_delete_subvolume");
11366 exit(EXIT_SUCCESS);
11368 if (wait_for_pid(pid))
11372 log_debug("Ran test");
11374 safe_close(attr.userns_fd);
11375 safe_close(open_tree_fd);
11376 safe_close(tree_fd);
11381 static int btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed(void)
11384 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11385 struct mount_attr attr = {
11386 .attr_set = MOUNT_ATTR_IDMAP,
11390 if (!caps_supported())
11393 /* Changing mount properties on a detached mount. */
11394 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11395 if (attr.userns_fd < 0) {
11396 log_stderr("failure: get_userns_fd");
11400 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11403 AT_SYMLINK_NOFOLLOW |
11404 OPEN_TREE_CLOEXEC |
11406 if (open_tree_fd < 0) {
11407 log_stderr("failure: sys_open_tree");
11411 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11412 log_stderr("failure: sys_mount_setattr");
11417 * The open_tree() syscall returns an O_PATH file descriptor which we
11418 * can't use with ioctl(). So let's reopen it as a proper file
11421 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11423 log_stderr("failure: openat");
11429 log_stderr("failure: fork");
11433 if (!switch_userns(attr.userns_fd, 0, 0, false))
11434 die("failure: switch_userns");
11436 /* The caller's fsids now have mappings in the idmapped mount so
11437 * any file creation must fail.
11440 /* create subvolume */
11441 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11442 die("failure: btrfs_create_subvolume");
11444 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11445 die("failure: check ownership");
11448 * The scratch device is mounted with user_subvol_rm_allowed so
11449 * subvolume deletion must succeed.
11451 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11452 die("failure: btrfs_delete_subvolume");
11454 exit(EXIT_SUCCESS);
11456 if (wait_for_pid(pid))
11460 log_debug("Ran test");
11462 safe_close(attr.userns_fd);
11463 safe_close(open_tree_fd);
11464 safe_close(tree_fd);
11469 static int btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed(void)
11472 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11473 struct mount_attr attr = {
11474 .attr_set = MOUNT_ATTR_IDMAP,
11478 if (!caps_supported())
11481 /* Changing mount properties on a detached mount. */
11482 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11483 if (attr.userns_fd < 0) {
11484 log_stderr("failure: get_userns_fd");
11488 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11491 AT_SYMLINK_NOFOLLOW |
11492 OPEN_TREE_CLOEXEC |
11494 if (open_tree_fd < 0) {
11495 log_stderr("failure: sys_open_tree");
11499 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11500 log_stderr("failure: sys_mount_setattr");
11505 * The open_tree() syscall returns an O_PATH file descriptor which we
11506 * can't use with ioctl(). So let's reopen it as a proper file
11509 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11511 log_stderr("failure: openat");
11517 log_stderr("failure: fork");
11521 int subvolume_fd = -EBADF;
11523 if (!switch_fsids(10000, 10000))
11524 die("failure: switch fsids");
11527 die("failure: raise caps");
11530 * The caller's fsids now have mappings in the idmapped mount so
11531 * any file creation must succeed.
11534 /* create subvolume */
11535 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11536 die("failure: btrfs_create_subvolume");
11538 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11539 die("failure: expected_uid_gid");
11541 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11542 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11543 if (subvolume_fd < 0)
11544 die("failure: openat");
11546 /* create read-write snapshot */
11547 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11548 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11549 die("failure: btrfs_create_snapshot");
11551 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
11552 die("failure: expected_uid_gid");
11554 /* create read-only snapshot */
11555 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11556 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11557 BTRFS_SUBVOL_RDONLY))
11558 die("failure: btrfs_create_snapshot");
11560 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
11561 die("failure: expected_uid_gid");
11563 safe_close(subvolume_fd);
11565 /* remove subvolume */
11566 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11567 die("failure: btrfs_delete_subvolume");
11569 /* remove read-write snapshot */
11570 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11571 die("failure: btrfs_delete_subvolume");
11573 /* remove read-only snapshot */
11574 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11575 die("failure: btrfs_delete_subvolume");
11577 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11578 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11579 if (subvolume_fd < 0)
11580 die("failure: openat");
11582 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11583 die("failure: btrfs_set_subvolume_ro");
11585 safe_close(subvolume_fd);
11587 /* remove read-only snapshot */
11588 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11589 die("failure: btrfs_delete_subvolume");
11591 exit(EXIT_SUCCESS);
11593 if (wait_for_pid(pid))
11597 log_debug("Ran test");
11599 safe_close(attr.userns_fd);
11600 safe_close(open_tree_fd);
11601 safe_close(tree_fd);
11606 static int btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed(void)
11609 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11610 struct mount_attr attr = {
11611 .attr_set = MOUNT_ATTR_IDMAP,
11615 if (!caps_supported())
11618 /* Changing mount properties on a detached mount. */
11619 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11620 if (attr.userns_fd < 0) {
11621 log_stderr("failure: get_userns_fd");
11625 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11628 AT_SYMLINK_NOFOLLOW |
11629 OPEN_TREE_CLOEXEC |
11631 if (open_tree_fd < 0) {
11632 log_stderr("failure: sys_open_tree");
11636 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11637 log_stderr("failure: sys_mount_setattr");
11642 * The open_tree() syscall returns an O_PATH file descriptor which we
11643 * can't use with ioctl(). So let's reopen it as a proper file
11646 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11648 log_stderr("failure: openat");
11654 log_stderr("failure: fork");
11658 int subvolume_fd = -EBADF;
11660 if (!switch_userns(attr.userns_fd, 0, 0, false))
11661 die("failure: switch_userns");
11663 /* create subvolume */
11664 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11665 die("failure: btrfs_create_subvolume");
11667 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11668 die("failure: expected_uid_gid");
11670 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11671 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11672 if (subvolume_fd < 0)
11673 die("failure: openat");
11675 /* create read-write snapshot */
11676 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11677 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11678 die("failure: btrfs_create_snapshot");
11680 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11681 die("failure: expected_uid_gid");
11683 /* create read-only snapshot */
11684 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11685 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11686 BTRFS_SUBVOL_RDONLY))
11687 die("failure: btrfs_create_snapshot");
11689 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11690 die("failure: expected_uid_gid");
11692 /* remove directory */
11693 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11694 die("failure: btrfs_delete_subvolume");
11696 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11697 die("failure: expected_uid_gid");
11699 /* remove read-write snapshot */
11700 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11701 die("failure: btrfs_delete_subvolume");
11703 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11704 die("failure: expected_uid_gid");
11706 /* remove read-only snapshot */
11707 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11708 die("failure: btrfs_delete_subvolume");
11710 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11711 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11712 if (subvolume_fd < 0)
11713 die("failure: openat");
11715 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11716 die("failure: btrfs_set_subvolume_ro");
11718 safe_close(subvolume_fd);
11720 /* remove read-only snapshot */
11721 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11722 die("failure: btrfs_delete_subvolume");
11724 exit(EXIT_SUCCESS);
11726 if (wait_for_pid(pid))
11730 log_debug("Ran test");
11732 safe_close(attr.userns_fd);
11733 safe_close(open_tree_fd);
11734 safe_close(tree_fd);
11739 static int btrfs_delete_by_spec_id(void)
11742 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
11743 uint64_t subvolume_id1 = -EINVAL, subvolume_id2 = -EINVAL;
11744 struct mount_attr attr = {
11745 .attr_set = MOUNT_ATTR_IDMAP,
11749 /* Changing mount properties on a detached mount. */
11750 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11751 if (attr.userns_fd < 0) {
11752 log_stderr("failure: get_userns_fd");
11756 /* create subvolume */
11757 if (btrfs_create_subvolume(t_mnt_scratch_fd, "A")) {
11758 log_stderr("failure: btrfs_create_subvolume");
11762 /* create subvolume */
11763 if (btrfs_create_subvolume(t_mnt_scratch_fd, "B")) {
11764 log_stderr("failure: btrfs_create_subvolume");
11768 subvolume_fd = openat(t_mnt_scratch_fd, "B", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11769 if (subvolume_fd < 0) {
11770 log_stderr("failure: openat");
11774 /* create subvolume */
11775 if (btrfs_create_subvolume(subvolume_fd, "C")) {
11776 log_stderr("failure: btrfs_create_subvolume");
11780 safe_close(subvolume_fd);
11782 subvolume_fd = openat(t_mnt_scratch_fd, "A", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11783 if (subvolume_fd < 0) {
11784 log_stderr("failure: openat");
11788 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id1)) {
11789 log_stderr("failure: btrfs_get_subvolume_id");
11793 subvolume_fd = openat(t_mnt_scratch_fd, "B/C", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11794 if (subvolume_fd < 0) {
11795 log_stderr("failure: openat");
11799 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id2)) {
11800 log_stderr("failure: btrfs_get_subvolume_id");
11804 if (sys_mount(t_device_scratch, t_mountpoint, "btrfs", 0, "subvol=B/C")) {
11805 log_stderr("failure: mount");
11809 open_tree_fd = sys_open_tree(-EBADF, t_mountpoint,
11811 AT_SYMLINK_NOFOLLOW |
11812 OPEN_TREE_CLOEXEC |
11814 if (open_tree_fd < 0) {
11815 log_stderr("failure: sys_open_tree");
11819 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11820 log_stderr("failure: sys_mount_setattr");
11825 * The open_tree() syscall returns an O_PATH file descriptor which we
11826 * can't use with ioctl(). So let's reopen it as a proper file
11829 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11831 log_stderr("failure: openat");
11837 log_stderr("failure: fork");
11842 * The subvolume isn't exposed in the idmapped mount so
11843 * delation via spec id must fail.
11845 if (!btrfs_delete_subvolume_id(tree_fd, subvolume_id1))
11846 die("failure: btrfs_delete_subvolume_id");
11847 if (errno != EOPNOTSUPP)
11848 die("failure: errno");
11850 if (btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id1))
11851 die("failure: btrfs_delete_subvolume_id");
11853 exit(EXIT_SUCCESS);
11855 if (wait_for_pid(pid))
11859 log_debug("Ran test");
11861 safe_close(attr.userns_fd);
11862 safe_close(open_tree_fd);
11863 safe_close(tree_fd);
11864 sys_umount2(t_mountpoint, MNT_DETACH);
11865 btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id2);
11866 btrfs_delete_subvolume(t_mnt_scratch_fd, "B");
11871 static int btrfs_subvolumes_setflags_fsids_mapped(void)
11874 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11875 struct mount_attr attr = {
11876 .attr_set = MOUNT_ATTR_IDMAP,
11880 if (!caps_supported())
11883 /* Changing mount properties on a detached mount. */
11884 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11885 if (attr.userns_fd < 0) {
11886 log_stderr("failure: get_userns_fd");
11890 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11893 AT_SYMLINK_NOFOLLOW |
11894 OPEN_TREE_CLOEXEC |
11896 if (open_tree_fd < 0) {
11897 log_stderr("failure: sys_open_tree");
11901 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11902 log_stderr("failure: sys_mount_setattr");
11907 * The open_tree() syscall returns an O_PATH file descriptor which we
11908 * can't use with ioctl(). So let's reopen it as a proper file
11911 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11913 log_stderr("failure: openat");
11919 log_stderr("failure: fork");
11923 int subvolume_fd = -EBADF;
11924 bool read_only = false;
11926 if (!switch_fsids(10000, 10000))
11927 die("failure: switch fsids");
11930 die("failure: raise caps");
11932 /* The caller's fsids now have mappings in the idmapped mount so
11933 * any file creation must fail.
11936 /* create subvolume */
11937 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11938 die("failure: btrfs_create_subvolume");
11940 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11941 die("failure: expected_uid_gid");
11943 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11944 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11945 if (subvolume_fd < 0)
11946 die("failure: openat");
11948 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11949 die("failure: btrfs_get_subvolume_ro");
11952 die("failure: read_only");
11954 if (btrfs_set_subvolume_ro(subvolume_fd, true))
11955 die("failure: btrfs_set_subvolume_ro");
11957 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11958 die("failure: btrfs_get_subvolume_ro");
11961 die("failure: not read_only");
11963 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11964 die("failure: btrfs_set_subvolume_ro");
11966 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11967 die("failure: btrfs_get_subvolume_ro");
11970 die("failure: read_only");
11972 safe_close(subvolume_fd);
11974 exit(EXIT_SUCCESS);
11976 if (wait_for_pid(pid))
11979 /* remove directory */
11980 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
11981 log_stderr("failure: btrfs_delete_subvolume");
11986 log_debug("Ran test");
11988 safe_close(attr.userns_fd);
11989 safe_close(open_tree_fd);
11990 safe_close(tree_fd);
11995 static int btrfs_subvolumes_setflags_fsids_mapped_userns(void)
11998 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11999 struct mount_attr attr = {
12000 .attr_set = MOUNT_ATTR_IDMAP,
12004 if (!caps_supported())
12007 /* Changing mount properties on a detached mount. */
12008 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12009 if (attr.userns_fd < 0) {
12010 log_stderr("failure: get_userns_fd");
12014 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12017 AT_SYMLINK_NOFOLLOW |
12018 OPEN_TREE_CLOEXEC |
12020 if (open_tree_fd < 0) {
12021 log_stderr("failure: sys_open_tree");
12025 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12026 log_stderr("failure: sys_mount_setattr");
12031 * The open_tree() syscall returns an O_PATH file descriptor which we
12032 * can't use with ioctl(). So let's reopen it as a proper file
12035 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12037 log_stderr("failure: openat");
12043 log_stderr("failure: fork");
12047 int subvolume_fd = -EBADF;
12048 bool read_only = false;
12050 if (!switch_userns(attr.userns_fd, 0, 0, false))
12051 die("failure: switch_userns");
12053 /* The caller's fsids now have mappings in the idmapped mount so
12054 * any file creation must fail.
12057 /* create subvolume */
12058 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12059 die("failure: btrfs_create_subvolume");
12061 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
12062 die("failure: expected_uid_gid");
12064 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12065 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12066 if (subvolume_fd < 0)
12067 die("failure: openat");
12069 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12070 die("failure: btrfs_get_subvolume_ro");
12073 die("failure: read_only");
12075 if (btrfs_set_subvolume_ro(subvolume_fd, true))
12076 die("failure: btrfs_set_subvolume_ro");
12078 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12079 die("failure: btrfs_get_subvolume_ro");
12082 die("failure: not read_only");
12084 if (btrfs_set_subvolume_ro(subvolume_fd, false))
12085 die("failure: btrfs_set_subvolume_ro");
12087 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12088 die("failure: btrfs_get_subvolume_ro");
12091 die("failure: read_only");
12093 safe_close(subvolume_fd);
12095 exit(EXIT_SUCCESS);
12097 if (wait_for_pid(pid))
12100 /* remove directory */
12101 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12102 log_stderr("failure: btrfs_delete_subvolume");
12107 log_debug("Ran test");
12109 safe_close(attr.userns_fd);
12110 safe_close(open_tree_fd);
12111 safe_close(tree_fd);
12116 static int btrfs_subvolumes_setflags_fsids_unmapped(void)
12119 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12120 struct mount_attr attr = {
12121 .attr_set = MOUNT_ATTR_IDMAP,
12125 if (!caps_supported())
12128 /* Changing mount properties on a detached mount. */
12129 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12130 if (attr.userns_fd < 0) {
12131 log_stderr("failure: get_userns_fd");
12135 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12138 AT_SYMLINK_NOFOLLOW |
12139 OPEN_TREE_CLOEXEC |
12141 if (open_tree_fd < 0) {
12142 log_stderr("failure: sys_open_tree");
12146 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12147 log_stderr("failure: sys_mount_setattr");
12152 * The open_tree() syscall returns an O_PATH file descriptor which we
12153 * can't use with ioctl(). So let's reopen it as a proper file
12156 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12158 log_stderr("failure: openat");
12162 /* create subvolume */
12163 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12164 log_stderr("failure: btrfs_create_subvolume");
12168 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12169 log_stderr("failure: expected_uid_gid");
12173 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12174 log_stderr("failure: expected_uid_gid");
12180 log_stderr("failure: fork");
12184 int subvolume_fd = -EBADF;
12185 bool read_only = false;
12187 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12188 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12189 if (subvolume_fd < 0)
12190 die("failure: openat");
12192 if (!switch_fsids(0, 0))
12193 die("failure: switch fsids");
12196 die("failure: raise caps");
12199 * The caller's fsids don't have mappings in the idmapped mount
12200 * so any file creation must fail.
12203 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12204 die("failure: btrfs_get_subvolume_ro");
12207 die("failure: read_only");
12209 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12210 die("failure: btrfs_set_subvolume_ro");
12211 if (errno != EPERM)
12212 die("failure: errno");
12214 safe_close(subvolume_fd);
12216 exit(EXIT_SUCCESS);
12218 if (wait_for_pid(pid))
12221 /* remove directory */
12222 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12223 log_stderr("failure: btrfs_delete_subvolume");
12228 log_debug("Ran test");
12230 safe_close(attr.userns_fd);
12231 safe_close(open_tree_fd);
12232 safe_close(tree_fd);
12237 static int btrfs_subvolumes_setflags_fsids_unmapped_userns(void)
12240 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
12241 struct mount_attr attr = {
12242 .attr_set = MOUNT_ATTR_IDMAP,
12246 if (!caps_supported())
12249 /* Changing mount properties on a detached mount. */
12250 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12251 if (attr.userns_fd < 0) {
12252 log_stderr("failure: get_userns_fd");
12256 /* Changing mount properties on a detached mount. */
12257 userns_fd = get_userns_fd(0, 30000, 10000);
12258 if (userns_fd < 0) {
12259 log_stderr("failure: get_userns_fd");
12263 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12266 AT_SYMLINK_NOFOLLOW |
12267 OPEN_TREE_CLOEXEC |
12269 if (open_tree_fd < 0) {
12270 log_stderr("failure: sys_open_tree");
12274 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12275 log_stderr("failure: sys_mount_setattr");
12280 * The open_tree() syscall returns an O_PATH file descriptor which we
12281 * can't use with ioctl(). So let's reopen it as a proper file
12284 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12286 log_stderr("failure: openat");
12290 /* create subvolume */
12291 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12292 log_stderr("failure: btrfs_create_subvolume");
12296 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12297 log_stderr("failure: expected_uid_gid");
12301 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12302 log_stderr("failure: expected_uid_gid");
12308 log_stderr("failure: fork");
12312 int subvolume_fd = -EBADF;
12313 bool read_only = false;
12316 * The caller's fsids don't have mappings in the idmapped mount
12317 * so any file creation must fail.
12320 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12321 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12322 if (subvolume_fd < 0)
12323 die("failure: openat");
12325 if (!switch_userns(userns_fd, 0, 0, false))
12326 die("failure: switch_userns");
12328 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12329 t_overflowuid, t_overflowgid))
12330 die("failure: expected_uid_gid");
12332 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12333 t_overflowuid, t_overflowgid))
12334 die("failure: expected_uid_gid");
12336 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12337 die("failure: btrfs_get_subvolume_ro");
12340 die("failure: read_only");
12342 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12343 die("failure: btrfs_set_subvolume_ro");
12344 if (errno != EPERM)
12345 die("failure: errno");
12347 safe_close(subvolume_fd);
12349 exit(EXIT_SUCCESS);
12351 if (wait_for_pid(pid))
12354 /* remove directory */
12355 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12356 log_stderr("failure: btrfs_delete_subvolume");
12361 log_debug("Ran test");
12363 safe_close(attr.userns_fd);
12364 safe_close(open_tree_fd);
12365 safe_close(tree_fd);
12366 safe_close(userns_fd);
12371 static int btrfs_snapshots_setflags_fsids_mapped(void)
12374 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12375 struct mount_attr attr = {
12376 .attr_set = MOUNT_ATTR_IDMAP,
12380 if (!caps_supported())
12383 /* Changing mount properties on a detached mount. */
12384 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12385 if (attr.userns_fd < 0) {
12386 log_stderr("failure: get_userns_fd");
12390 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12393 AT_SYMLINK_NOFOLLOW |
12394 OPEN_TREE_CLOEXEC |
12396 if (open_tree_fd < 0) {
12397 log_stderr("failure: sys_open_tree");
12401 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12402 log_stderr("failure: sys_mount_setattr");
12407 * The open_tree() syscall returns an O_PATH file descriptor which we
12408 * can't use with ioctl(). So let's reopen it as a proper file
12411 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12413 log_stderr("failure: openat");
12419 log_stderr("failure: fork");
12423 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12424 bool read_only = false;
12426 if (!switch_fsids(10000, 10000))
12427 die("failure: switch fsids");
12430 die("failure: raise caps");
12433 * The caller's fsids now have mappings in the idmapped mount
12434 * so any file creation must succeed.
12437 /* create subvolume */
12438 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12439 die("failure: btrfs_create_subvolume");
12441 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
12442 die("failure: expected_uid_gid");
12444 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12445 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12446 if (subvolume_fd < 0)
12447 die("failure: openat");
12449 /* create read-write snapshot */
12450 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12451 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12452 die("failure: btrfs_create_snapshot");
12454 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
12455 die("failure: expected_uid_gid");
12457 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12458 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12459 if (snapshot_fd < 0)
12460 die("failure: openat");
12462 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12463 die("failure: btrfs_get_subvolume_ro");
12466 die("failure: read_only");
12468 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12469 die("failure: btrfs_set_subvolume_ro");
12471 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12472 die("failure: btrfs_get_subvolume_ro");
12475 die("failure: not read_only");
12477 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12478 die("failure: btrfs_set_subvolume_ro");
12480 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12481 die("failure: btrfs_get_subvolume_ro");
12484 die("failure: read_only");
12486 safe_close(snapshot_fd);
12487 safe_close(subvolume_fd);
12489 exit(EXIT_SUCCESS);
12491 if (wait_for_pid(pid))
12494 /* remove directory */
12495 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12496 log_stderr("failure: btrfs_delete_subvolume");
12500 /* remove directory */
12501 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12502 log_stderr("failure: btrfs_delete_subvolume");
12507 log_debug("Ran test");
12509 safe_close(attr.userns_fd);
12510 safe_close(open_tree_fd);
12511 safe_close(tree_fd);
12516 static int btrfs_snapshots_setflags_fsids_mapped_userns(void)
12519 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12520 struct mount_attr attr = {
12521 .attr_set = MOUNT_ATTR_IDMAP,
12525 if (!caps_supported())
12528 /* Changing mount properties on a detached mount. */
12529 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12530 if (attr.userns_fd < 0) {
12531 log_stderr("failure: get_userns_fd");
12535 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12538 AT_SYMLINK_NOFOLLOW |
12539 OPEN_TREE_CLOEXEC |
12541 if (open_tree_fd < 0) {
12542 log_stderr("failure: sys_open_tree");
12546 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12547 log_stderr("failure: sys_mount_setattr");
12552 * The open_tree() syscall returns an O_PATH file descriptor which we
12553 * can't use with ioctl(). So let's reopen it as a proper file
12556 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12558 log_stderr("failure: openat");
12564 log_stderr("failure: fork");
12568 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12569 bool read_only = false;
12571 if (!switch_userns(attr.userns_fd, 0, 0, false))
12572 die("failure: switch_userns");
12575 * The caller's fsids now have mappings in the idmapped mount so
12576 * any file creation must succeed.
12579 /* create subvolume */
12580 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12581 die("failure: btrfs_create_subvolume");
12583 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
12584 die("failure: expected_uid_gid");
12586 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12587 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12588 if (subvolume_fd < 0)
12589 die("failure: openat");
12591 /* create read-write snapshot */
12592 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12593 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12594 die("failure: btrfs_create_snapshot");
12596 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
12597 die("failure: expected_uid_gid");
12599 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12600 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12601 if (snapshot_fd < 0)
12602 die("failure: openat");
12604 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12605 die("failure: btrfs_get_subvolume_ro");
12608 die("failure: read_only");
12610 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12611 die("failure: btrfs_set_subvolume_ro");
12613 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12614 die("failure: btrfs_get_subvolume_ro");
12617 die("failure: not read_only");
12619 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12620 die("failure: btrfs_set_subvolume_ro");
12622 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12623 die("failure: btrfs_get_subvolume_ro");
12626 die("failure: read_only");
12628 safe_close(snapshot_fd);
12629 safe_close(subvolume_fd);
12631 exit(EXIT_SUCCESS);
12633 if (wait_for_pid(pid))
12636 /* remove directory */
12637 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12638 log_stderr("failure: btrfs_delete_subvolume");
12642 /* remove directory */
12643 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12644 log_stderr("failure: btrfs_delete_subvolume");
12649 log_debug("Ran test");
12651 safe_close(attr.userns_fd);
12652 safe_close(open_tree_fd);
12653 safe_close(tree_fd);
12658 static int btrfs_snapshots_setflags_fsids_unmapped(void)
12661 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
12662 struct mount_attr attr = {
12663 .attr_set = MOUNT_ATTR_IDMAP,
12667 if (!caps_supported())
12670 /* Changing mount properties on a detached mount. */
12671 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12672 if (attr.userns_fd < 0) {
12673 log_stderr("failure: get_userns_fd");
12677 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12680 AT_SYMLINK_NOFOLLOW |
12681 OPEN_TREE_CLOEXEC |
12683 if (open_tree_fd < 0) {
12684 log_stderr("failure: sys_open_tree");
12688 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12689 log_stderr("failure: sys_mount_setattr");
12694 * The open_tree() syscall returns an O_PATH file descriptor which we
12695 * can't use with ioctl(). So let's reopen it as a proper file
12698 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12700 log_stderr("failure: openat");
12704 /* create subvolume */
12705 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12706 log_stderr("failure: btrfs_create_subvolume");
12710 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12711 log_stderr("failure: expected_uid_gid");
12715 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12716 log_stderr("failure: expected_uid_gid");
12720 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12721 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12722 if (subvolume_fd < 0) {
12723 log_stderr("failure: openat");
12727 /* create read-write snapshot */
12728 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12729 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12730 log_stderr("failure: btrfs_create_snapshot");
12734 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12735 log_stderr("failure: expected_uid_gid");
12739 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12740 log_stderr("failure: expected_uid_gid");
12746 log_stderr("failure: fork");
12750 int snapshot_fd = -EBADF;
12751 bool read_only = false;
12753 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12754 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12755 if (snapshot_fd < 0)
12756 die("failure: openat");
12758 if (!switch_fsids(0, 0))
12759 die("failure: switch fsids");
12762 die("failure: raise caps");
12765 * The caller's fsids don't have mappings in the idmapped mount
12766 * so any file creation must fail.
12769 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12770 die("failure: btrfs_get_subvolume_ro");
12773 die("failure: read_only");
12775 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12776 die("failure: btrfs_set_subvolume_ro");
12777 if (errno != EPERM)
12778 die("failure: errno");
12780 safe_close(snapshot_fd);
12782 exit(EXIT_SUCCESS);
12784 if (wait_for_pid(pid))
12787 /* remove directory */
12788 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12789 log_stderr("failure: btrfs_delete_subvolume");
12793 /* remove directory */
12794 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12795 log_stderr("failure: btrfs_delete_subvolume");
12800 log_debug("Ran test");
12802 safe_close(attr.userns_fd);
12803 safe_close(open_tree_fd);
12804 safe_close(subvolume_fd);
12805 safe_close(tree_fd);
12810 static int btrfs_snapshots_setflags_fsids_unmapped_userns(void)
12813 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
12814 userns_fd = -EBADF;
12815 struct mount_attr attr = {
12816 .attr_set = MOUNT_ATTR_IDMAP,
12820 if (!caps_supported())
12823 /* Changing mount properties on a detached mount. */
12824 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12825 if (attr.userns_fd < 0) {
12826 log_stderr("failure: get_userns_fd");
12830 /* Changing mount properties on a detached mount. */
12831 userns_fd = get_userns_fd(0, 30000, 10000);
12832 if (userns_fd < 0) {
12833 log_stderr("failure: get_userns_fd");
12837 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12840 AT_SYMLINK_NOFOLLOW |
12841 OPEN_TREE_CLOEXEC |
12843 if (open_tree_fd < 0) {
12844 log_stderr("failure: sys_open_tree");
12848 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12849 log_stderr("failure: sys_mount_setattr");
12854 * The open_tree() syscall returns an O_PATH file descriptor which we
12855 * can't use with ioctl(). So let's reopen it as a proper file
12858 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12860 log_stderr("failure: openat");
12864 /* create subvolume */
12865 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12866 log_stderr("failure: btrfs_create_subvolume");
12870 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12871 log_stderr("failure: expected_uid_gid");
12875 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12876 log_stderr("failure: expected_uid_gid");
12880 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12881 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12882 if (subvolume_fd < 0) {
12883 log_stderr("failure: openat");
12887 /* create read-write snapshot */
12888 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12889 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12890 log_stderr("failure: btrfs_create_snapshot");
12894 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12895 log_stderr("failure: expected_uid_gid");
12899 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12900 log_stderr("failure: expected_uid_gid");
12906 log_stderr("failure: fork");
12910 int snapshot_fd = -EBADF;
12911 bool read_only = false;
12914 * The caller's fsids don't have mappings in the idmapped mount
12915 * so any file creation must fail.
12918 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12919 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12920 if (snapshot_fd < 0)
12921 die("failure: openat");
12924 if (!switch_userns(userns_fd, 0, 0, false))
12925 die("failure: switch_userns");
12927 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12928 t_overflowuid, t_overflowgid))
12929 die("failure: expected_uid_gid");
12931 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12932 t_overflowuid, t_overflowgid))
12933 die("failure: expected_uid_gid");
12936 * The caller's fsids don't have mappings in the idmapped mount
12937 * so any file creation must fail.
12940 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12941 die("failure: btrfs_get_subvolume_ro");
12944 die("failure: read_only");
12946 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12947 die("failure: btrfs_set_subvolume_ro");
12948 if (errno != EPERM)
12949 die("failure: errno");
12951 safe_close(snapshot_fd);
12953 exit(EXIT_SUCCESS);
12955 if (wait_for_pid(pid))
12958 /* remove directory */
12959 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12960 log_stderr("failure: btrfs_delete_subvolume");
12964 /* remove directory */
12965 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12966 log_stderr("failure: btrfs_delete_subvolume");
12971 log_debug("Ran test");
12973 safe_close(attr.userns_fd);
12974 safe_close(open_tree_fd);
12975 safe_close(subvolume_fd);
12976 safe_close(tree_fd);
12977 safe_close(userns_fd);
12982 #define BTRFS_SUBVOLUME_SUBVOL1 "subvol1"
12983 #define BTRFS_SUBVOLUME_SUBVOL2 "subvol2"
12984 #define BTRFS_SUBVOLUME_SUBVOL3 "subvol3"
12985 #define BTRFS_SUBVOLUME_SUBVOL4 "subvol4"
12987 #define BTRFS_SUBVOLUME_SUBVOL1_ID 0
12988 #define BTRFS_SUBVOLUME_SUBVOL2_ID 1
12989 #define BTRFS_SUBVOLUME_SUBVOL3_ID 2
12990 #define BTRFS_SUBVOLUME_SUBVOL4_ID 3
12992 #define BTRFS_SUBVOLUME_DIR1 "dir1"
12993 #define BTRFS_SUBVOLUME_DIR2 "dir2"
12995 #define BTRFS_SUBVOLUME_MNT "mnt_subvolume1"
12997 #define BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3 "subvol1/subvol3"
12998 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2 "subvol1/dir1/dir2"
12999 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4 "subvol1/dir1/dir2/subvol4"
13002 * We create the following mount layout to test lookup:
13004 * |-/mnt/test /dev/loop0 btrfs rw,relatime,space_cache,subvolid=5,subvol=/
13005 * | |-/mnt/test/mnt1 /dev/loop1[/subvol1] btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=268,subvol=/subvol1
13006 * '-/mnt/scratch /dev/loop1 btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=5,subvol=/
13008 static int btrfs_subvolume_lookup_user(void)
13011 int dir1_fd = -EBADF, dir2_fd = -EBADF, mnt_fd = -EBADF,
13012 open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
13013 int subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
13014 uint64_t subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
13015 uint64_t subvolid = -EINVAL;
13016 struct mount_attr attr = {
13017 .attr_set = MOUNT_ATTR_IDMAP,
13020 struct btrfs_iter *iter;
13022 if (!caps_supported())
13025 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
13026 subvolume_fds[i] = -EBADF;
13028 for (i = 0; i < ARRAY_SIZE(subvolume_ids); i++)
13029 subvolume_ids[i] = -EINVAL;
13031 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL1)) {
13032 log_stderr("failure: btrfs_create_subvolume");
13036 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL2)) {
13037 log_stderr("failure: btrfs_create_subvolume");
13041 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] = openat(t_mnt_scratch_fd,
13042 BTRFS_SUBVOLUME_SUBVOL1,
13043 O_CLOEXEC | O_DIRECTORY);
13044 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] < 0) {
13045 log_stderr("failure: openat");
13049 /* create subvolume */
13050 if (btrfs_create_subvolume(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_SUBVOL3)) {
13051 log_stderr("failure: btrfs_create_subvolume");
13055 if (mkdirat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1, 0777)) {
13056 log_stderr("failure: mkdirat");
13060 dir1_fd = openat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1,
13061 O_CLOEXEC | O_DIRECTORY);
13063 log_stderr("failure: openat");
13067 if (mkdirat(dir1_fd, BTRFS_SUBVOLUME_DIR2, 0777)) {
13068 log_stderr("failure: mkdirat");
13072 dir2_fd = openat(dir1_fd, BTRFS_SUBVOLUME_DIR2, O_CLOEXEC | O_DIRECTORY);
13074 log_stderr("failure: openat");
13078 if (btrfs_create_subvolume(dir2_fd, BTRFS_SUBVOLUME_SUBVOL4)) {
13079 log_stderr("failure: btrfs_create_subvolume");
13083 if (mkdirat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, 0777)) {
13084 log_stderr("failure: mkdirat");
13088 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13089 if (sys_mount(t_device_scratch, t_buf, "btrfs", 0,
13090 "subvol=" BTRFS_SUBVOLUME_SUBVOL1)) {
13091 log_stderr("failure: mount");
13095 mnt_fd = openat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, O_CLOEXEC | O_DIRECTORY);
13097 log_stderr("failure: openat");
13101 if (chown_r(t_mnt_scratch_fd, ".", 1000, 1000)) {
13102 log_stderr("failure: chown_r");
13106 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] = openat(t_mnt_scratch_fd,
13107 BTRFS_SUBVOLUME_SUBVOL2,
13108 O_CLOEXEC | O_DIRECTORY);
13109 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] < 0) {
13110 log_stderr("failure: openat");
13114 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID],
13115 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL1_ID])) {
13116 log_stderr("failure: btrfs_get_subvolume_id");
13120 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID],
13121 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL2_ID])) {
13122 log_stderr("failure: btrfs_get_subvolume_id");
13126 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] = openat(t_mnt_scratch_fd,
13127 BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3,
13128 O_CLOEXEC | O_DIRECTORY);
13129 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] < 0) {
13130 log_stderr("failure: openat");
13134 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID],
13135 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])) {
13136 log_stderr("failure: btrfs_get_subvolume_id");
13140 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] = openat(t_mnt_scratch_fd,
13141 BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4,
13142 O_CLOEXEC | O_DIRECTORY);
13143 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] < 0) {
13144 log_stderr("failure: openat");
13148 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID],
13149 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])) {
13150 log_stderr("failure: btrfs_get_subvolume_id");
13155 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13156 log_stderr("failure: fchmod");
13160 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13161 log_stderr("failure: fchmod");
13165 attr.userns_fd = get_userns_fd(0, 10000, 10000);
13166 if (attr.userns_fd < 0) {
13167 log_stderr("failure: get_userns_fd");
13171 open_tree_fd = sys_open_tree(mnt_fd, "",
13174 AT_SYMLINK_NOFOLLOW |
13175 OPEN_TREE_CLOEXEC |
13177 if (open_tree_fd < 0) {
13178 log_stderr("failure: sys_open_tree");
13182 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
13183 log_stderr("failure: sys_mount_setattr");
13188 * The open_tree() syscall returns an O_PATH file descriptor which we
13189 * can't use with ioctl(). So let's reopen it as a proper file
13192 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
13194 log_stderr("failure: openat");
13200 log_stderr("failure: fork");
13204 bool subvolume3_found = false, subvolume4_found = false;
13206 if (!switch_fsids(11000, 11000))
13207 die("failure: switch fsids");
13210 die("failure: lower caps");
13212 if (btrfs_iterator_start(tree_fd, 0, &iter))
13213 die("failure: btrfs_iterator_start");
13216 char *subvol_path = NULL;
13219 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13223 die("failure: btrfs_iterator_next");
13225 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13226 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13227 die("failure: subvolume id %llu->%s",
13228 (long long unsigned)subvolid, subvol_path);
13230 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13231 subvolume3_found = true;
13233 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13234 subvolume4_found = true;
13238 btrfs_iterator_end(iter);
13240 if (!subvolume3_found || !subvolume4_found)
13241 die("failure: subvolume id");
13243 exit(EXIT_SUCCESS);
13245 if (wait_for_pid(pid))
13250 log_stderr("failure: fork");
13254 bool subvolume3_found = false, subvolume4_found = false;
13256 if (!switch_userns(attr.userns_fd, 0, 0, false))
13257 die("failure: switch_userns");
13259 if (btrfs_iterator_start(tree_fd, 0, &iter))
13260 die("failure: btrfs_iterator_start");
13263 char *subvol_path = NULL;
13266 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13270 die("failure: btrfs_iterator_next");
13272 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13273 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13274 die("failure: subvolume id %llu->%s",
13275 (long long unsigned)subvolid, subvol_path);
13277 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13278 subvolume3_found = true;
13280 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13281 subvolume4_found = true;
13285 btrfs_iterator_end(iter);
13287 if (!subvolume3_found || !subvolume4_found)
13288 die("failure: subvolume id");
13290 exit(EXIT_SUCCESS);
13292 if (wait_for_pid(pid))
13297 log_stderr("failure: fork");
13301 bool subvolume_found = false;
13303 if (!switch_fsids(0, 0))
13304 die("failure: switch fsids");
13307 die("failure: lower caps");
13309 if (btrfs_iterator_start(tree_fd, 0, &iter))
13310 die("failure: btrfs_iterator_start");
13313 char *subvol_path = NULL;
13316 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13320 die("failure: btrfs_iterator_next");
13324 subvolume_found = true;
13327 btrfs_iterator_end(iter);
13329 if (subvolume_found)
13330 die("failure: subvolume id");
13332 exit(EXIT_SUCCESS);
13334 if (wait_for_pid(pid))
13337 userns_fd = get_userns_fd(0, 30000, 10000);
13338 if (userns_fd < 0) {
13339 log_stderr("failure: get_userns_fd");
13345 log_stderr("failure: fork");
13349 bool subvolume_found = false;
13351 if (!switch_userns(userns_fd, 0, 0, true))
13352 die("failure: switch_userns");
13354 if (btrfs_iterator_start(tree_fd, 0, &iter))
13355 die("failure: btrfs_iterator_start");
13358 char *subvol_path = NULL;
13361 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13365 die("failure: btrfs_iterator_next");
13369 subvolume_found = true;
13372 btrfs_iterator_end(iter);
13374 if (subvolume_found)
13375 die("failure: subvolume id");
13377 exit(EXIT_SUCCESS);
13379 if (wait_for_pid(pid))
13383 log_debug("Ran test");
13385 safe_close(dir1_fd);
13386 safe_close(dir2_fd);
13387 safe_close(open_tree_fd);
13388 safe_close(tree_fd);
13389 safe_close(userns_fd);
13390 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
13391 safe_close(subvolume_fds[i]);
13392 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13393 sys_umount2(t_buf, MNT_DETACH);
13394 unlinkat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, AT_REMOVEDIR);
13399 #define USER1 "fsgqa"
13400 #define USER2 "fsgqa2"
13403 * lookup_ids - lookup uid and gid for a username
13404 * @name: [in] name of the user
13405 * @uid: [out] pointer to the user-ID
13406 * @gid: [out] pointer to the group-ID
13408 * Lookup the uid and gid of a user.
13410 * Return: On success, true is returned.
13411 * On error, false is returned.
13413 static bool lookup_ids(const char *name, uid_t *uid, gid_t *gid)
13416 struct passwd *pwentp = NULL;
13417 struct passwd pwent;
13422 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
13426 buf = malloc(bufsize);
13430 ret = getpwnam_r(name, &pwent, buf, bufsize, &pwentp);
13431 if (!ret && pwentp) {
13432 *uid = pwent.pw_uid;
13433 *gid = pwent.pw_gid;
13442 * setattr_fix_968219708108 - test for commit 968219708108 ("fs: handle circular mappings correctly")
13444 * Test that ->setattr() works correctly for idmapped mounts with circular
13445 * idmappings such as:
13450 * Assume a directory /source with two files:
13452 * /source/file1 | 1000:1000
13453 * /source/file2 | 1001:1001
13455 * and we create an idmapped mount of /source at /target with an idmapped of:
13457 * mnt_userns: 1000:1001:1
13460 * In the idmapped mount file1 will be owned by uid 1001 and file2 by uid 1000:
13462 * /target/file1 | 1001:1001
13463 * /target/file2 | 1000:1000
13465 * Because in essence the idmapped mount switches ownership for {g,u}id 1000
13466 * and {g,u}id 1001.
13468 * 1. A user with fs{g,u}id 1000 must be allowed to setattr /target/file2 from
13469 * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
13470 * 2. A user with fs{g,u}id 1001 must be allowed to setattr /target/file1 from
13471 * {g,u}id 1001 in the idmapped mount to {g,u}id 1001.
13472 * 3. A user with fs{g,u}id 1000 must fail to setattr /target/file1 from
13473 * {g,u}id 1001 in the idmapped mount to {g,u}id 1000.
13474 * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
13475 * {g,u}id of the file.
13476 * 4. A user with fs{g,u}id 1001 must fail to setattr /target/file2 from
13477 * {g,u}id 1000 in the idmapped mount to {g,u}id 1000.
13478 * This must fail with EPERM. The caller's fs{g,u}id doesn't match the
13479 * {g,u}id of the file.
13480 * 5. Both, a user with fs{g,u}id 1000 and a user with fs{g,u}id 1001, must
13481 * fail to setattr /target/file1 owned by {g,u}id 1001 in the idmapped mount
13482 * and /target/file2 owned by {g,u}id 1000 in the idmapped mount to any
13483 * {g,u}id apart from {g,u}id 1000 or 1001 with EINVAL.
13484 * Only {g,u}id 1000 and 1001 have a mapping in the idmapped mount. Other
13485 * {g,u}id are unmapped.
13487 static int setattr_fix_968219708108(void)
13490 int open_tree_fd = -EBADF;
13491 struct mount_attr attr = {
13492 .attr_set = MOUNT_ATTR_IDMAP,
13493 .userns_fd = -EBADF,
13496 uid_t user1_uid, user2_uid;
13497 gid_t user1_gid, user2_gid;
13500 struct list *it_cur, *it_next;
13502 if (!caps_supported())
13507 if (!lookup_ids(USER1, &user1_uid, &user1_gid)) {
13508 log_stderr("failure: lookup_user");
13512 if (!lookup_ids(USER2, &user2_uid, &user2_gid)) {
13513 log_stderr("failure: lookup_user");
13517 log_debug("Found " USER1 " with uid(%d) and gid(%d) and " USER2 " with uid(%d) and gid(%d)",
13518 user1_uid, user1_gid, user2_uid, user2_gid);
13520 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
13521 log_stderr("failure: mkdirat");
13525 if (mknodat(t_dir1_fd, DIR1 "/" FILE1, S_IFREG | 0644, 0)) {
13526 log_stderr("failure: mknodat");
13530 if (chown_r(t_mnt_fd, T_DIR1, user1_uid, user1_gid)) {
13531 log_stderr("failure: chown_r");
13535 if (mknodat(t_dir1_fd, DIR1 "/" FILE2, S_IFREG | 0644, 0)) {
13536 log_stderr("failure: mknodat");
13540 if (fchownat(t_dir1_fd, DIR1 "/" FILE2, user2_uid, user2_gid, AT_SYMLINK_NOFOLLOW)) {
13541 log_stderr("failure: fchownat");
13545 print_r(t_mnt_fd, T_DIR1);
13547 /* u:1000:1001:1 */
13548 ret = add_map_entry(&idmap, user1_uid, user2_uid, 1, ID_TYPE_UID);
13550 log_stderr("failure: add_map_entry");
13554 /* u:1001:1000:1 */
13555 ret = add_map_entry(&idmap, user2_uid, user1_uid, 1, ID_TYPE_UID);
13557 log_stderr("failure: add_map_entry");
13561 /* g:1000:1001:1 */
13562 ret = add_map_entry(&idmap, user1_gid, user2_gid, 1, ID_TYPE_GID);
13564 log_stderr("failure: add_map_entry");
13568 /* g:1001:1000:1 */
13569 ret = add_map_entry(&idmap, user2_gid, user1_gid, 1, ID_TYPE_GID);
13571 log_stderr("failure: add_map_entry");
13575 attr.userns_fd = get_userns_fd_from_idmap(&idmap);
13576 if (attr.userns_fd < 0) {
13577 log_stderr("failure: get_userns_fd");
13581 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
13583 AT_SYMLINK_NOFOLLOW |
13584 OPEN_TREE_CLOEXEC |
13587 if (open_tree_fd < 0) {
13588 log_stderr("failure: sys_open_tree");
13592 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
13593 log_stderr("failure: sys_mount_setattr");
13597 print_r(open_tree_fd, "");
13601 log_stderr("failure: fork");
13605 /* switch to {g,u}id 1001 */
13606 if (!switch_resids(user2_uid, user2_gid))
13607 die("failure: switch_resids");
13609 /* drop all capabilities */
13611 die("failure: caps_down");
13614 * The {g,u}id 0 is not mapped in this idmapped mount so this
13615 * needs to fail with EINVAL.
13617 if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
13618 die("failure: change ownership");
13619 if (errno != EINVAL)
13620 die("failure: errno");
13623 * A user with fs{g,u}id 1001 must be allowed to change
13624 * ownership of /target/file1 owned by {g,u}id 1001 in this
13625 * idmapped mount to {g,u}id 1001.
13627 if (fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
13628 AT_SYMLINK_NOFOLLOW))
13629 die("failure: change ownership");
13631 /* Verify that the ownership is still {g,u}id 1001. */
13632 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13633 user2_uid, user2_gid))
13634 die("failure: check ownership");
13637 * A user with fs{g,u}id 1001 must not be allowed to change
13638 * ownership of /target/file1 owned by {g,u}id 1001 in this
13639 * idmapped mount to {g,u}id 1000.
13641 if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
13642 AT_SYMLINK_NOFOLLOW))
13643 die("failure: change ownership");
13644 if (errno != EPERM)
13645 die("failure: errno");
13647 /* Verify that the ownership is still {g,u}id 1001. */
13648 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13649 user2_uid, user2_gid))
13650 die("failure: check ownership");
13653 * A user with fs{g,u}id 1001 must not be allowed to change
13654 * ownership of /target/file2 owned by {g,u}id 1000 in this
13655 * idmapped mount to {g,u}id 1000.
13657 if (!fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
13658 AT_SYMLINK_NOFOLLOW))
13659 die("failure: change ownership");
13660 if (errno != EPERM)
13661 die("failure: errno");
13663 /* Verify that the ownership is still {g,u}id 1000. */
13664 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13665 user1_uid, user1_gid))
13666 die("failure: check ownership");
13669 * A user with fs{g,u}id 1001 must not be allowed to change
13670 * ownership of /target/file2 owned by {g,u}id 1000 in this
13671 * idmapped mount to {g,u}id 1001.
13673 if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
13674 AT_SYMLINK_NOFOLLOW))
13675 die("failure: change ownership");
13676 if (errno != EPERM)
13677 die("failure: errno");
13679 /* Verify that the ownership is still {g,u}id 1000. */
13680 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13681 user1_uid, user1_gid))
13682 die("failure: check ownership");
13684 exit(EXIT_SUCCESS);
13686 if (wait_for_pid(pid))
13691 log_stderr("failure: fork");
13695 /* switch to {g,u}id 1000 */
13696 if (!switch_resids(user1_uid, user1_gid))
13697 die("failure: switch_resids");
13699 /* drop all capabilities */
13701 die("failure: caps_down");
13704 * The {g,u}id 0 is not mapped in this idmapped mount so this
13705 * needs to fail with EINVAL.
13707 if (!fchownat(open_tree_fd, FILE1, 0, 0, AT_SYMLINK_NOFOLLOW))
13708 die("failure: change ownership");
13709 if (errno != EINVAL)
13710 die("failure: errno");
13713 * A user with fs{g,u}id 1000 must be allowed to change
13714 * ownership of /target/file2 owned by {g,u}id 1000 in this
13715 * idmapped mount to {g,u}id 1000.
13717 if (fchownat(open_tree_fd, FILE2, user1_uid, user1_gid,
13718 AT_SYMLINK_NOFOLLOW))
13719 die("failure: change ownership");
13721 /* Verify that the ownership is still {g,u}id 1000. */
13722 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13723 user1_uid, user1_gid))
13724 die("failure: check ownership");
13727 * A user with fs{g,u}id 1000 must not be allowed to change
13728 * ownership of /target/file2 owned by {g,u}id 1000 in this
13729 * idmapped mount to {g,u}id 1001.
13731 if (!fchownat(open_tree_fd, FILE2, user2_uid, user2_gid,
13732 AT_SYMLINK_NOFOLLOW))
13733 die("failure: change ownership");
13734 if (errno != EPERM)
13735 die("failure: errno");
13737 /* Verify that the ownership is still {g,u}id 1000. */
13738 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW,
13739 user1_uid, user1_gid))
13740 die("failure: check ownership");
13743 * A user with fs{g,u}id 1000 must not be allowed to change
13744 * ownership of /target/file1 owned by {g,u}id 1001 in this
13745 * idmapped mount to {g,u}id 1000.
13747 if (!fchownat(open_tree_fd, FILE1, user1_uid, user1_gid,
13748 AT_SYMLINK_NOFOLLOW))
13749 die("failure: change ownership");
13750 if (errno != EPERM)
13751 die("failure: errno");
13753 /* Verify that the ownership is still {g,u}id 1001. */
13754 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13755 user2_uid, user2_gid))
13756 die("failure: check ownership");
13759 * A user with fs{g,u}id 1000 must not be allowed to change
13760 * ownership of /target/file1 owned by {g,u}id 1001 in this
13761 * idmapped mount to {g,u}id 1001.
13763 if (!fchownat(open_tree_fd, FILE1, user2_uid, user2_gid,
13764 AT_SYMLINK_NOFOLLOW))
13765 die("failure: change ownership");
13766 if (errno != EPERM)
13767 die("failure: errno");
13769 /* Verify that the ownership is still {g,u}id 1001. */
13770 if (!expected_uid_gid(open_tree_fd, FILE1, AT_SYMLINK_NOFOLLOW,
13771 user2_uid, user2_gid))
13772 die("failure: check ownership");
13774 exit(EXIT_SUCCESS);
13776 if (wait_for_pid(pid))
13780 log_debug("Ran test");
13782 safe_close(attr.userns_fd);
13783 safe_close(open_tree_fd);
13785 list_for_each_safe(it_cur, &idmap, it_next) {
13787 free(it_cur->elem);
13794 static void usage(void)
13796 fprintf(stderr, "Description:\n");
13797 fprintf(stderr, " Run idmapped mount tests\n\n");
13799 fprintf(stderr, "Arguments:\n");
13800 fprintf(stderr, "--device Device used in the tests\n");
13801 fprintf(stderr, "--fstype Filesystem type used in the tests\n");
13802 fprintf(stderr, "--help Print help\n");
13803 fprintf(stderr, "--mountpoint Mountpoint of device\n");
13804 fprintf(stderr, "--supported Test whether idmapped mounts are supported on this filesystem\n");
13805 fprintf(stderr, "--scratch-mountpoint Mountpoint of scratch device used in the tests\n");
13806 fprintf(stderr, "--scratch-device Scratch device used in the tests\n");
13807 fprintf(stderr, "--test-core Run core idmapped mount testsuite\n");
13808 fprintf(stderr, "--test-fscaps-regression Run fscap regression tests\n");
13809 fprintf(stderr, "--test-nested-userns Run nested userns idmapped mount testsuite\n");
13810 fprintf(stderr, "--test-btrfs Run btrfs specific idmapped mount testsuite\n");
13811 fprintf(stderr, "--test-setattr-fix-968219708108 Run setattr regression tests\n");
13813 _exit(EXIT_SUCCESS);
13816 static const struct option longopts[] = {
13817 {"device", required_argument, 0, 'd'},
13818 {"fstype", required_argument, 0, 'f'},
13819 {"mountpoint", required_argument, 0, 'm'},
13820 {"scratch-mountpoint", required_argument, 0, 'a'},
13821 {"scratch-device", required_argument, 0, 'e'},
13822 {"supported", no_argument, 0, 's'},
13823 {"help", no_argument, 0, 'h'},
13824 {"test-core", no_argument, 0, 'c'},
13825 {"test-fscaps-regression", no_argument, 0, 'g'},
13826 {"test-nested-userns", no_argument, 0, 'n'},
13827 {"test-btrfs", no_argument, 0, 'b'},
13828 {"test-setattr-fix-968219708108", no_argument, 0, 'i'},
13832 /* Flags for which functionality is required by the test */
13833 #define T_REQUIRE_IDMAPPED_MOUNTS (1U << 0)
13835 struct t_idmapped_mounts {
13837 unsigned int support_flags;
13838 const char *description;
13839 } basic_suite[] = {
13840 { acls, T_REQUIRE_IDMAPPED_MOUNTS, "posix acls on regular mounts", },
13841 { create_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "create operations in user namespace", },
13842 { device_node_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "device node in user namespace", },
13843 { expected_uid_gid_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "expected ownership on idmapped mounts", },
13844 { fscaps, 0, "fscaps on regular mounts", },
13845 { fscaps_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "fscaps on idmapped mounts", },
13846 { fscaps_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "fscaps on idmapped mounts in user namespace", },
13847 { fscaps_idmapped_mounts_in_userns_separate_userns, T_REQUIRE_IDMAPPED_MOUNTS, "fscaps on idmapped mounts in user namespace with different id mappings", },
13848 { fsids_mapped, T_REQUIRE_IDMAPPED_MOUNTS, "mapped fsids", },
13849 { fsids_unmapped, T_REQUIRE_IDMAPPED_MOUNTS, "unmapped fsids", },
13850 { hardlink_crossing_mounts, 0, "cross mount hardlink", },
13851 { hardlink_crossing_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "cross idmapped mount hardlink", },
13852 { hardlink_from_idmapped_mount, T_REQUIRE_IDMAPPED_MOUNTS, "hardlinks from idmapped mounts", },
13853 { hardlink_from_idmapped_mount_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "hardlinks from idmapped mounts in user namespace", },
13854 #ifdef HAVE_LIBURING_H
13855 { io_uring, 0, "io_uring", },
13856 { io_uring_userns, 0, "io_uring in user namespace", },
13857 { io_uring_idmapped, T_REQUIRE_IDMAPPED_MOUNTS, "io_uring from idmapped mounts", },
13858 { io_uring_idmapped_userns, T_REQUIRE_IDMAPPED_MOUNTS, "io_uring from idmapped mounts in user namespace", },
13859 { io_uring_idmapped_unmapped, T_REQUIRE_IDMAPPED_MOUNTS, "io_uring from idmapped mounts with unmapped ids", },
13860 { io_uring_idmapped_unmapped_userns, T_REQUIRE_IDMAPPED_MOUNTS, "io_uring from idmapped mounts with unmapped ids in user namespace", },
13862 { protected_symlinks, 0, "following protected symlinks on regular mounts", },
13863 { protected_symlinks_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "following protected symlinks on idmapped mounts", },
13864 { protected_symlinks_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "following protected symlinks on idmapped mounts in user namespace", },
13865 { rename_crossing_mounts, 0, "cross mount rename", },
13866 { rename_crossing_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "cross idmapped mount rename", },
13867 { rename_from_idmapped_mount, T_REQUIRE_IDMAPPED_MOUNTS, "rename from idmapped mounts", },
13868 { rename_from_idmapped_mount_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "rename from idmapped mounts in user namespace", },
13869 { setattr_truncate, 0, "setattr truncate", },
13870 { setattr_truncate_idmapped, T_REQUIRE_IDMAPPED_MOUNTS, "setattr truncate on idmapped mounts", },
13871 { setattr_truncate_idmapped_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "setattr truncate on idmapped mounts in user namespace", },
13872 { setgid_create, 0, "create operations in directories with setgid bit set", },
13873 { setgid_create_idmapped, T_REQUIRE_IDMAPPED_MOUNTS, "create operations in directories with setgid bit set on idmapped mounts", },
13874 { setgid_create_idmapped_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "create operations in directories with setgid bit set on idmapped mounts in user namespace", },
13875 { setid_binaries, 0, "setid binaries on regular mounts", },
13876 { setid_binaries_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "setid binaries on idmapped mounts", },
13877 { setid_binaries_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "setid binaries on idmapped mounts in user namespace", },
13878 { setid_binaries_idmapped_mounts_in_userns_separate_userns, T_REQUIRE_IDMAPPED_MOUNTS, "setid binaries on idmapped mounts in user namespace with different id mappings", },
13879 { sticky_bit_unlink, 0, "sticky bit unlink operations on regular mounts", },
13880 { sticky_bit_unlink_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "sticky bit unlink operations on idmapped mounts", },
13881 { sticky_bit_unlink_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "sticky bit unlink operations on idmapped mounts in user namespace", },
13882 { sticky_bit_rename, 0, "sticky bit rename operations on regular mounts", },
13883 { sticky_bit_rename_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "sticky bit rename operations on idmapped mounts", },
13884 { sticky_bit_rename_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "sticky bit rename operations on idmapped mounts in user namespace", },
13885 { symlink_regular_mounts, 0, "symlink from regular mounts", },
13886 { symlink_idmapped_mounts, T_REQUIRE_IDMAPPED_MOUNTS, "symlink from idmapped mounts", },
13887 { symlink_idmapped_mounts_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "symlink from idmapped mounts in user namespace", },
13888 { threaded_idmapped_mount_interactions, T_REQUIRE_IDMAPPED_MOUNTS, "threaded operations on idmapped mounts", },
13891 struct t_idmapped_mounts fscaps_in_ancestor_userns[] = {
13892 { fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns, true, "fscaps on idmapped mounts in user namespace writing fscap valid in ancestor userns", },
13895 struct t_idmapped_mounts t_nested_userns[] = {
13896 { nested_userns, true, "test that nested user namespaces behave correctly when attached to idmapped mounts", },
13899 struct t_idmapped_mounts t_btrfs[] = {
13900 { btrfs_subvolumes_fsids_mapped, true, "test subvolumes with mapped fsids", },
13901 { btrfs_subvolumes_fsids_mapped_userns, true, "test subvolumes with mapped fsids inside user namespace", },
13902 { btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed, true, "test subvolume deletion with user_subvol_rm_allowed mount option", },
13903 { btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed, true, "test subvolume deletion with user_subvol_rm_allowed mount option inside user namespace", },
13904 { btrfs_subvolumes_fsids_unmapped, true, "test subvolumes with unmapped fsids", },
13905 { btrfs_subvolumes_fsids_unmapped_userns, true, "test subvolumes with unmapped fsids inside user namespace", },
13906 { btrfs_snapshots_fsids_mapped, true, "test snapshots with mapped fsids", },
13907 { btrfs_snapshots_fsids_mapped_userns, true, "test snapshots with mapped fsids inside user namespace", },
13908 { btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed, true, "test snapshots deletion with user_subvol_rm_allowed mount option", },
13909 { btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed, true, "test snapshots deletion with user_subvol_rm_allowed mount option inside user namespace", },
13910 { btrfs_snapshots_fsids_unmapped, true, "test snapshots with unmapped fsids", },
13911 { btrfs_snapshots_fsids_unmapped_userns, true, "test snapshots with unmapped fsids inside user namespace", },
13912 { btrfs_delete_by_spec_id, true, "test subvolume deletion by spec id", },
13913 { btrfs_subvolumes_setflags_fsids_mapped, true, "test subvolume flags with mapped fsids", },
13914 { btrfs_subvolumes_setflags_fsids_mapped_userns, true, "test subvolume flags with mapped fsids inside user namespace", },
13915 { btrfs_subvolumes_setflags_fsids_unmapped, true, "test subvolume flags with unmapped fsids", },
13916 { btrfs_subvolumes_setflags_fsids_unmapped_userns, true, "test subvolume flags with unmapped fsids inside user namespace", },
13917 { btrfs_snapshots_setflags_fsids_mapped, true, "test snapshots flags with mapped fsids", },
13918 { btrfs_snapshots_setflags_fsids_mapped_userns, true, "test snapshots flags with mapped fsids inside user namespace", },
13919 { btrfs_snapshots_setflags_fsids_unmapped, true, "test snapshots flags with unmapped fsids", },
13920 { btrfs_snapshots_setflags_fsids_unmapped_userns, true, "test snapshots flags with unmapped fsids inside user namespace", },
13921 { btrfs_subvolume_lookup_user, true, "test unprivileged subvolume lookup", },
13924 /* Test for commit 968219708108 ("fs: handle circular mappings correctly"). */
13925 struct t_idmapped_mounts t_setattr_fix_968219708108[] = {
13926 { setattr_fix_968219708108, true, "test that setattr works correctly", },
13929 static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size)
13933 for (i = 0; i < suite_size; i++) {
13934 struct t_idmapped_mounts *t = &suite[i];
13939 * If the underlying filesystems does not support idmapped
13940 * mounts only run vfs generic tests.
13942 if (t->support_flags & T_REQUIRE_IDMAPPED_MOUNTS &&
13943 !t_fs_allow_idmap) {
13944 log_debug("Skipping test %s", t->description);
13957 die("failure: %s", t->description);
13959 exit(EXIT_SUCCESS);
13962 ret = wait_for_pid(pid);
13972 static bool fs_allow_idmap(void)
13975 int open_tree_fd = -EBADF;
13976 struct mount_attr attr = {
13977 .attr_set = MOUNT_ATTR_IDMAP,
13978 .userns_fd = -EBADF,
13981 /* Changing mount properties on a detached mount. */
13982 attr.userns_fd = get_userns_fd(0, 1000, 1);
13983 if (attr.userns_fd < 0)
13986 open_tree_fd = sys_open_tree(t_mnt_fd, "",
13987 AT_EMPTY_PATH | AT_NO_AUTOMOUNT |
13988 AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLOEXEC |
13990 if (open_tree_fd < 0)
13993 ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
13995 close(open_tree_fd);
13996 close(attr.userns_fd);
14001 int main(int argc, char *argv[])
14005 bool supported = false, test_btrfs = false, test_core = false,
14006 test_fscaps_regression = false, test_nested_userns = false,
14007 test_setattr_fix_968219708108 = false;
14009 while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) {
14018 t_mountpoint = optarg;
14027 test_fscaps_regression = true;
14030 test_nested_userns = true;
14036 t_mountpoint_scratch = optarg;
14039 t_device_scratch = optarg;
14042 test_setattr_fix_968219708108 = true;
14052 die_errno(EINVAL, "test device missing");
14055 die_errno(EINVAL, "test filesystem type missing");
14058 die_errno(EINVAL, "mountpoint of test device missing");
14060 /* create separate mount namespace */
14061 if (unshare(CLONE_NEWNS))
14062 die("failure: create new mount namespace");
14064 /* turn off mount propagation */
14065 if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
14066 die("failure: turn mount propagation off");
14068 t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
14070 die("failed to open %s", t_mountpoint);
14072 t_mnt_scratch_fd = openat(-EBADF, t_mountpoint_scratch, O_CLOEXEC | O_DIRECTORY);
14074 die("failed to open %s", t_mountpoint_scratch);
14076 t_fs_allow_idmap = fs_allow_idmap();
14079 * Caller just wants to know whether the filesystem we're on
14080 * supports idmapped mounts.
14082 if (!t_fs_allow_idmap)
14083 exit(EXIT_FAILURE);
14085 exit(EXIT_SUCCESS);
14088 stash_overflowuid();
14089 stash_overflowgid();
14091 fret = EXIT_FAILURE;
14093 if (test_core && !run_test(basic_suite, ARRAY_SIZE(basic_suite)))
14096 if (test_fscaps_regression &&
14097 !run_test(fscaps_in_ancestor_userns,
14098 ARRAY_SIZE(fscaps_in_ancestor_userns)))
14101 if (test_nested_userns &&
14102 !run_test(t_nested_userns, ARRAY_SIZE(t_nested_userns)))
14105 if (test_btrfs && !run_test(t_btrfs, ARRAY_SIZE(t_btrfs)))
14108 if (test_setattr_fix_968219708108 &&
14109 !run_test(t_setattr_fix_968219708108,
14110 ARRAY_SIZE(t_setattr_fix_968219708108)))
14113 fret = EXIT_SUCCESS;