1 // SPDX-License-Identifier: GPL-2.0
14 #include <linux/limits.h>
15 #include <linux/types.h>
19 #include <sys/fsuid.h>
21 #include <sys/types.h>
22 #include <sys/xattr.h>
25 #ifdef HAVE_LINUX_BTRFS_H
26 # ifndef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2_SUBVOLID
27 # define btrfs_ioctl_vol_args_v2 override_btrfs_ioctl_vol_args_v2
29 #include <linux/btrfs.h>
30 # undef btrfs_ioctl_vol_args_v2
33 #ifdef HAVE_LINUX_BTRFS_TREE_H
34 #include <linux/btrfs_tree.h>
37 #ifdef HAVE_SYS_CAPABILITY_H
38 #include <sys/capability.h>
41 #ifdef HAVE_LIBURING_H
48 #define T_DIR1 "idmapped_mounts_1"
50 #define FILE1_RENAME "file1_rename"
52 #define FILE2_RENAME "file2_rename"
56 #define DIR1_RENAME "dir1_rename"
57 #define HARDLINK1 "hardlink1"
58 #define SYMLINK1 "symlink1"
59 #define SYMLINK_USER1 "symlink_user1"
60 #define SYMLINK_USER2 "symlink_user2"
61 #define SYMLINK_USER3 "symlink_user3"
62 #define CHRDEV1 "chrdev1"
64 #define log_stderr(format, ...) \
65 fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \
69 #define log_debug(format, ...) \
70 fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \
71 __func__, ##__VA_ARGS__)
73 #define log_debug(format, ...)
76 #define log_error_errno(__ret__, __errno__, format, ...) \
78 typeof(__ret__) __internal_ret__ = (__ret__); \
79 errno = (__errno__); \
80 log_stderr(format, ##__VA_ARGS__); \
84 #define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__)
86 #define die_errno(__errno__, format, ...) \
88 errno = (__errno__); \
89 log_stderr(format, ##__VA_ARGS__); \
93 #define die(format, ...) die_errno(errno, format, ##__VA_ARGS__)
95 #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
97 uid_t t_overflowuid = 65534;
98 gid_t t_overflowgid = 65534;
100 /* path of the test device */
101 const char *t_fstype;
103 /* path of the test device */
104 const char *t_device;
106 /* path of the test scratch device */
107 const char *t_device_scratch;
109 /* mountpoint of the test device */
110 const char *t_mountpoint;
112 /* mountpoint of the test device */
113 const char *t_mountpoint_scratch;
115 /* fd for @t_mountpoint */
118 /* fd for @t_mountpoint_scratch */
119 int t_mnt_scratch_fd;
124 /* temporary buffer */
125 char t_buf[PATH_MAX];
127 static void stash_overflowuid(void)
133 fd = open("/proc/sys/fs/overflowuid", O_RDONLY | O_CLOEXEC);
137 ret = read(fd, buf, sizeof(buf));
142 t_overflowuid = atoi(buf);
145 static void stash_overflowgid(void)
151 fd = open("/proc/sys/fs/overflowgid", O_RDONLY | O_CLOEXEC);
155 ret = read(fd, buf, sizeof(buf));
160 t_overflowgid = atoi(buf);
163 static bool is_xfs(void)
165 static int enabled = -1;
168 enabled = !strcmp(t_fstype, "xfs");
173 static bool protected_symlinks_enabled(void)
175 static int enabled = -1;
184 fd = open("/proc/sys/fs/protected_symlinks", O_RDONLY | O_CLOEXEC);
188 ret = read(fd, buf, sizeof(buf));
200 static bool xfs_irix_sgid_inherit_enabled(void)
202 static int enabled = -1;
212 fd = open("/proc/sys/fs/xfs/irix_sgid_inherit", O_RDONLY | O_CLOEXEC);
216 ret = read(fd, buf, sizeof(buf));
229 static inline bool caps_supported(void)
233 #ifdef HAVE_SYS_CAPABILITY_H
240 /* caps_down - lower all effective caps */
241 static int caps_down(void)
244 #ifdef HAVE_SYS_CAPABILITY_H
248 caps = cap_get_proc();
252 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
256 ret = cap_set_proc(caps);
268 /* caps_up - raise all permitted caps */
269 static int caps_up(void)
272 #ifdef HAVE_SYS_CAPABILITY_H
277 caps = cap_get_proc();
281 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
282 cap_flag_value_t flag;
284 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
292 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
297 ret = cap_set_proc(caps);
308 /* __expected_uid_gid - check whether file is owned by the provided uid and gid */
309 static bool __expected_uid_gid(int dfd, const char *path, int flags,
310 uid_t expected_uid, gid_t expected_gid, bool log)
315 ret = fstatat(dfd, path, &st, flags);
317 return log_errno(false, "failure: fstatat");
319 if (log && st.st_uid != expected_uid)
320 log_stderr("failure: uid(%d) != expected_uid(%d)", st.st_uid, expected_uid);
322 if (log && st.st_gid != expected_gid)
323 log_stderr("failure: gid(%d) != expected_gid(%d)", st.st_gid, expected_gid);
325 errno = 0; /* Don't report misleading errno. */
326 return st.st_uid == expected_uid && st.st_gid == expected_gid;
329 static bool expected_uid_gid(int dfd, const char *path, int flags,
330 uid_t expected_uid, gid_t expected_gid)
332 return __expected_uid_gid(dfd, path, flags,
333 expected_uid, expected_gid, true);
336 static bool expected_file_size(int dfd, const char *path,
337 int flags, off_t expected_size)
342 ret = fstatat(dfd, path, &st, flags);
344 return log_errno(false, "failure: fstatat");
346 if (st.st_size != expected_size)
347 return log_errno(false, "failure: st_size(%zu) != expected_size(%zu)",
348 (size_t)st.st_size, (size_t)expected_size);
353 /* is_setid - check whether file is S_ISUID and S_ISGID */
354 static bool is_setid(int dfd, const char *path, int flags)
359 ret = fstatat(dfd, path, &st, flags);
363 errno = 0; /* Don't report misleading errno. */
364 return (st.st_mode & S_ISUID) || (st.st_mode & S_ISGID);
367 /* is_setgid - check whether file or directory is S_ISGID */
368 static bool is_setgid(int dfd, const char *path, int flags)
373 ret = fstatat(dfd, path, &st, flags);
377 errno = 0; /* Don't report misleading errno. */
378 return (st.st_mode & S_ISGID);
381 /* is_sticky - check whether file is S_ISVTX */
382 static bool is_sticky(int dfd, const char *path, int flags)
387 ret = fstatat(dfd, path, &st, flags);
391 errno = 0; /* Don't report misleading errno. */
392 return (st.st_mode & S_ISVTX) > 0;
395 static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
398 return log_errno(false, "failure: setfsgid");
400 if (setfsgid(-1) != fsgid)
401 return log_errno(false, "failure: setfsgid(-1)");
404 return log_errno(false, "failure: setfsuid");
406 if (setfsuid(-1) != fsuid)
407 return log_errno(false, "failure: setfsuid(-1)");
412 static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
414 if (setns(fd, CLONE_NEWUSER))
415 return log_errno(false, "failure: setns");
417 if (!switch_ids(uid, gid))
418 return log_errno(false, "failure: switch_ids");
420 if (drop_caps && !caps_down())
421 return log_errno(false, "failure: caps_down");
426 /* rm_r - recursively remove all files */
427 static int rm_r(int fd, const char *path)
431 struct dirent *direntp;
433 if (!path || strcmp(path, "") == 0)
436 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
440 dir = fdopendir(dfd);
446 while ((direntp = readdir(dir))) {
449 if (!strcmp(direntp->d_name, ".") ||
450 !strcmp(direntp->d_name, ".."))
453 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
454 if (ret < 0 && errno != ENOENT)
457 if (S_ISDIR(st.st_mode))
458 ret = rm_r(dfd, direntp->d_name);
460 ret = unlinkat(dfd, direntp->d_name, 0);
461 if (ret < 0 && errno != ENOENT)
465 ret = unlinkat(fd, path, AT_REMOVEDIR);
470 /* chown_r - recursively change ownership of all files */
471 static int chown_r(int fd, const char *path, uid_t uid, gid_t gid)
475 struct dirent *direntp;
477 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY);
481 dir = fdopendir(dfd);
487 while ((direntp = readdir(dir))) {
490 if (!strcmp(direntp->d_name, ".") ||
491 !strcmp(direntp->d_name, ".."))
494 ret = fstatat(dfd, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
495 if (ret < 0 && errno != ENOENT)
498 if (S_ISDIR(st.st_mode))
499 ret = chown_r(dfd, direntp->d_name, uid, gid);
501 ret = fchownat(dfd, direntp->d_name, uid, gid, AT_SYMLINK_NOFOLLOW);
502 if (ret < 0 && errno != ENOENT)
506 ret = fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW);
512 * There'll be scenarios where you'll want to see the attributes associated with
513 * a directory tree during debugging or just to make sure things look correct.
514 * Simply uncomment and place the print_r() helper where you need it.
517 static int fd_cloexec(int fd, bool cloexec)
521 oflags = fcntl(fd, F_GETFD, 0);
526 nflags = oflags | FD_CLOEXEC;
528 nflags = oflags & ~FD_CLOEXEC;
530 if (nflags == oflags)
533 if (fcntl(fd, F_SETFD, nflags) < 0)
539 static inline int dup_cloexec(int fd)
547 if (fd_cloexec(fd_dup, true)) {
555 __attribute__((unused)) static int print_r(int fd, const char *path)
560 struct dirent *direntp;
563 if (!path || *path == '\0') {
564 char buf[sizeof("/proc/self/fd/") + 30];
566 ret = snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
567 if (ret < 0 || (size_t)ret >= sizeof(buf))
571 * O_PATH file descriptors can't be used so we need to re-open
574 dfd = openat(-EBADF, buf, O_CLOEXEC | O_DIRECTORY, 0);
576 dfd = openat(fd, path, O_CLOEXEC | O_DIRECTORY, 0);
582 * When fdopendir() below succeeds it assumes ownership of the fd so we
583 * to make sure we always have an fd that fdopendir() can own which is
584 * why we dup() in the case where the caller wants us to operate on the
587 dfd_dup = dup_cloexec(dfd);
593 dir = fdopendir(dfd);
599 /* Transfer ownership to fdopendir(). */
602 while ((direntp = readdir(dir))) {
603 if (!strcmp(direntp->d_name, ".") ||
604 !strcmp(direntp->d_name, ".."))
607 ret = fstatat(dfd_dup, direntp->d_name, &st, AT_SYMLINK_NOFOLLOW);
608 if (ret < 0 && errno != ENOENT)
612 if (S_ISDIR(st.st_mode))
613 ret = print_r(dfd_dup, direntp->d_name);
615 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %d/%s\n",
616 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
617 dfd_dup, direntp->d_name);
618 if (ret < 0 && errno != ENOENT)
622 if (!path || *path == '\0')
623 ret = fstatat(fd, "", &st,
624 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW |
627 ret = fstatat(fd, path, &st,
628 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW);
630 fprintf(stderr, "mode(%o):uid(%d):gid(%d) -> %s\n",
631 (st.st_mode & ~S_IFMT), st.st_uid, st.st_gid,
632 (path && *path) ? path : "(null)");
641 /* fd_to_fd - transfer data from one fd to another */
642 static int fd_to_fd(int from, int to)
645 uint8_t buf[PATH_MAX];
647 ssize_t bytes_to_write;
650 bytes_read = read_nointr(from, buf, sizeof buf);
656 bytes_to_write = (size_t)bytes_read;
658 ssize_t bytes_written;
660 bytes_written = write_nointr(to, p, bytes_to_write);
661 if (bytes_written < 0)
664 bytes_to_write -= bytes_written;
666 } while (bytes_to_write > 0);
672 static int sys_execveat(int fd, const char *path, char **argv, char **envp,
676 return syscall(__NR_execveat, fd, path, argv, envp, flags);
684 #define CAP_NET_RAW 13
687 #ifndef VFS_CAP_FLAGS_EFFECTIVE
688 #define VFS_CAP_FLAGS_EFFECTIVE 0x000001
691 #ifndef VFS_CAP_U32_3
692 #define VFS_CAP_U32_3 2
696 #define VFS_CAP_U32 VFS_CAP_U32_3
699 #ifndef VFS_CAP_REVISION_1
700 #define VFS_CAP_REVISION_1 0x01000000
703 #ifndef VFS_CAP_REVISION_2
704 #define VFS_CAP_REVISION_2 0x02000000
707 #ifndef VFS_CAP_REVISION_3
708 #define VFS_CAP_REVISION_3 0x03000000
709 struct vfs_ns_cap_data {
719 #if __BYTE_ORDER == __BIG_ENDIAN
720 #define cpu_to_le16(w16) le16_to_cpu(w16)
721 #define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
722 #define cpu_to_le32(w32) le32_to_cpu(w32)
723 #define le32_to_cpu(w32) \
724 ((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
725 (u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
726 #elif __BYTE_ORDER == __LITTLE_ENDIAN
727 #define cpu_to_le16(w16) ((u_int16_t)(w16))
728 #define le16_to_cpu(w16) ((u_int16_t)(w16))
729 #define cpu_to_le32(w32) ((u_int32_t)(w32))
730 #define le32_to_cpu(w32) ((u_int32_t)(w32))
732 #error Expected endianess macro to be set
735 /* expected_dummy_vfs_caps_uid - check vfs caps are stored with the provided uid */
736 static bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid)
738 #define __cap_raised_permitted(x, ns_cap_data) \
739 ((ns_cap_data.data[(x) >> 5].permitted) & (1 << ((x)&31)))
740 struct vfs_ns_cap_data ns_xattr = {};
743 ret = fgetxattr(fd, "security.capability", &ns_xattr, sizeof(ns_xattr));
744 if (ret < 0 || ret == 0)
747 if (ns_xattr.magic_etc & VFS_CAP_REVISION_3) {
749 if (le32_to_cpu(ns_xattr.rootid) != expected_uid) {
751 log_stderr("failure: rootid(%d) != expected_rootid(%d)", le32_to_cpu(ns_xattr.rootid), expected_uid);
754 return (le32_to_cpu(ns_xattr.rootid) == expected_uid) &&
755 (__cap_raised_permitted(CAP_NET_RAW, ns_xattr) > 0);
757 log_stderr("failure: fscaps version");
763 /* set_dummy_vfs_caps - set dummy vfs caps for the provided uid */
764 static int set_dummy_vfs_caps(int fd, int flags, int rootuid)
766 #define __raise_cap_permitted(x, ns_cap_data) \
767 ns_cap_data.data[(x) >> 5].permitted |= (1 << ((x)&31))
769 struct vfs_ns_cap_data ns_xattr;
771 memset(&ns_xattr, 0, sizeof(ns_xattr));
772 __raise_cap_permitted(CAP_NET_RAW, ns_xattr);
773 ns_xattr.magic_etc |= VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;
774 ns_xattr.rootid = cpu_to_le32(rootuid);
776 return fsetxattr(fd, "security.capability",
777 &ns_xattr, sizeof(ns_xattr), flags);
780 #define safe_close(fd) \
788 static void test_setup(void)
790 if (mkdirat(t_mnt_fd, T_DIR1, 0777))
791 die("failure: mkdirat");
793 t_dir1_fd = openat(t_mnt_fd, T_DIR1, O_CLOEXEC | O_DIRECTORY);
795 die("failure: openat");
797 if (fchmod(t_dir1_fd, 0777))
798 die("failure: fchmod");
801 static void test_cleanup(void)
803 safe_close(t_dir1_fd);
804 if (rm_r(t_mnt_fd, T_DIR1))
805 die("failure: rm_r");
808 /* Validate that basic file operations on idmapped mounts. */
809 static int fsids_unmapped(void)
812 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
813 struct mount_attr attr = {
814 .attr_set = MOUNT_ATTR_IDMAP,
817 /* create hardlink target */
818 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
819 if (hardlink_target_fd < 0) {
820 log_stderr("failure: openat");
824 /* create directory for rename test */
825 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
826 log_stderr("failure: mkdirat");
830 /* change ownership of all files to uid 0 */
831 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
832 log_stderr("failure: chown_r");
836 /* Changing mount properties on a detached mount. */
837 attr.userns_fd = get_userns_fd(0, 10000, 10000);
838 if (attr.userns_fd < 0) {
839 log_stderr("failure: get_userns_fd");
843 open_tree_fd = sys_open_tree(t_dir1_fd, "",
846 AT_SYMLINK_NOFOLLOW |
849 if (open_tree_fd < 0) {
850 log_stderr("failure: sys_open_tree");
854 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
855 log_stderr("failure: sys_mount_setattr");
859 if (!switch_fsids(0, 0)) {
860 log_stderr("failure: switch_fsids");
864 /* The caller's fsids don't have a mappings in the idmapped mount so any
865 * file creation must fail.
868 /* create hardlink */
869 if (!linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
870 log_stderr("failure: linkat");
873 if (errno != EOVERFLOW) {
874 log_stderr("failure: errno");
878 /* try to rename a file */
879 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
880 log_stderr("failure: renameat");
883 if (errno != EOVERFLOW) {
884 log_stderr("failure: errno");
888 /* try to rename a directory */
889 if (!renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME)) {
890 log_stderr("failure: renameat");
893 if (errno != EOVERFLOW) {
894 log_stderr("failure: errno");
898 /* The caller is privileged over the inode so file deletion must work. */
901 if (unlinkat(open_tree_fd, FILE1, 0)) {
902 log_stderr("failure: unlinkat");
906 /* remove directory */
907 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR)) {
908 log_stderr("failure: unlinkat");
912 /* The caller's fsids don't have a mappings in the idmapped mount so
913 * any file creation must fail.
916 /* create regular file via open() */
917 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
919 log_stderr("failure: create");
922 if (errno != EOVERFLOW) {
923 log_stderr("failure: errno");
927 /* create regular file via mknod */
928 if (!mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0)) {
929 log_stderr("failure: mknodat");
932 if (errno != EOVERFLOW) {
933 log_stderr("failure: errno");
937 /* create character device */
938 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
939 log_stderr("failure: mknodat");
942 if (errno != EOVERFLOW) {
943 log_stderr("failure: errno");
948 if (!symlinkat(FILE2, open_tree_fd, SYMLINK1)) {
949 log_stderr("failure: symlinkat");
952 if (errno != EOVERFLOW) {
953 log_stderr("failure: errno");
957 /* create directory */
958 if (!mkdirat(open_tree_fd, DIR1, 0700)) {
959 log_stderr("failure: mkdirat");
962 if (errno != EOVERFLOW) {
963 log_stderr("failure: errno");
968 log_debug("Ran test");
970 safe_close(attr.userns_fd);
971 safe_close(hardlink_target_fd);
972 safe_close(file1_fd);
973 safe_close(open_tree_fd);
978 static int fsids_mapped(void)
981 int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
982 struct mount_attr attr = {
983 .attr_set = MOUNT_ATTR_IDMAP,
987 if (!caps_supported())
990 /* create hardlink target */
991 hardlink_target_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
992 if (hardlink_target_fd < 0) {
993 log_stderr("failure: openat");
997 /* create directory for rename test */
998 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
999 log_stderr("failure: mkdirat");
1003 /* change ownership of all files to uid 0 */
1004 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1005 log_stderr("failure: chown_r");
1009 /* Changing mount properties on a detached mount. */
1010 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1011 if (attr.userns_fd < 0) {
1012 log_stderr("failure: get_userns_fd");
1016 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1019 AT_SYMLINK_NOFOLLOW |
1022 if (open_tree_fd < 0) {
1023 log_stderr("failure: sys_open_tree");
1027 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1028 log_stderr("failure: sys_mount_setattr");
1034 log_stderr("failure: fork");
1038 if (!switch_fsids(10000, 10000))
1039 die("failure: switch fsids");
1042 die("failure: raise caps");
1044 /* The caller's fsids now have mappings in the idmapped mount so
1045 * any file creation must fail.
1048 /* create hardlink */
1049 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1050 die("failure: create hardlink");
1052 /* try to rename a file */
1053 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1054 die("failure: rename");
1056 /* try to rename a directory */
1057 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1058 die("failure: rename");
1061 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1062 die("failure: delete");
1064 /* remove directory */
1065 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1066 die("failure: delete");
1068 /* The caller's fsids have mappings in the idmapped mount so any
1069 * file creation must fail.
1072 /* create regular file via open() */
1073 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1075 die("failure: create");
1077 /* create regular file via mknod */
1078 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1079 die("failure: create");
1081 /* create character device */
1082 if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
1083 die("failure: create");
1085 /* create symlink */
1086 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1087 die("failure: create");
1089 /* create directory */
1090 if (mkdirat(open_tree_fd, DIR1, 0700))
1091 die("failure: create");
1095 if (wait_for_pid(pid))
1099 log_debug("Ran test");
1101 safe_close(attr.userns_fd);
1102 safe_close(file1_fd);
1103 safe_close(hardlink_target_fd);
1104 safe_close(open_tree_fd);
1109 /* Validate that basic file operations on idmapped mounts from a user namespace. */
1110 static int create_in_userns(void)
1113 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1114 struct mount_attr attr = {
1115 .attr_set = MOUNT_ATTR_IDMAP,
1119 /* change ownership of all files to uid 0 */
1120 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1121 log_stderr("failure: chown_r");
1125 /* Changing mount properties on a detached mount. */
1126 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1127 if (attr.userns_fd < 0) {
1128 log_stderr("failure: get_userns_fd");
1132 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1135 AT_SYMLINK_NOFOLLOW |
1138 if (open_tree_fd < 0) {
1139 log_stderr("failure: sys_open_tree");
1143 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1144 log_stderr("failure: sys_mount_setattr");
1150 log_stderr("failure: fork");
1154 if (!switch_userns(attr.userns_fd, 0, 0, false))
1155 die("failure: switch_userns");
1157 /* create regular file via open() */
1158 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1160 die("failure: open file");
1161 safe_close(file1_fd);
1163 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1164 die("failure: check ownership");
1166 /* create regular file via mknod */
1167 if (mknodat(open_tree_fd, FILE2, S_IFREG | 0000, 0))
1168 die("failure: create");
1170 if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
1171 die("failure: check ownership");
1173 /* create symlink */
1174 if (symlinkat(FILE2, open_tree_fd, SYMLINK1))
1175 die("failure: create");
1177 if (!expected_uid_gid(open_tree_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0))
1178 die("failure: check ownership");
1180 /* create directory */
1181 if (mkdirat(open_tree_fd, DIR1, 0700))
1182 die("failure: create");
1184 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
1185 die("failure: check ownership");
1187 /* try to rename a file */
1188 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1189 die("failure: create");
1191 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1192 die("failure: check ownership");
1194 /* try to rename a file */
1195 if (renameat(open_tree_fd, DIR1, open_tree_fd, DIR1_RENAME))
1196 die("failure: create");
1198 if (!expected_uid_gid(open_tree_fd, DIR1_RENAME, 0, 0, 0))
1199 die("failure: check ownership");
1202 if (unlinkat(open_tree_fd, FILE1_RENAME, 0))
1203 die("failure: remove");
1205 /* remove directory */
1206 if (unlinkat(open_tree_fd, DIR1_RENAME, AT_REMOVEDIR))
1207 die("failure: remove");
1212 if (wait_for_pid(pid))
1216 log_debug("Ran test");
1218 safe_close(attr.userns_fd);
1219 safe_close(file1_fd);
1220 safe_close(open_tree_fd);
1225 static int hardlink_crossing_mounts(void)
1228 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1230 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1231 log_stderr("failure: chown_r");
1235 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1238 AT_SYMLINK_NOFOLLOW |
1241 if (open_tree_fd < 0) {
1242 log_stderr("failure: sys_open_tree");
1246 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1248 log_stderr("failure: openat");
1252 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1253 log_stderr("failure: mkdirat");
1257 /* We're crossing a mountpoint so this must fail.
1259 * Note that this must also fail for non-idmapped mounts but here we're
1260 * interested in making sure we're not introducing an accidental way to
1261 * violate that restriction or that suddenly this becomes possible.
1263 if (!linkat(open_tree_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
1264 log_stderr("failure: linkat");
1267 if (errno != EXDEV) {
1268 log_stderr("failure: errno");
1273 log_debug("Ran test");
1275 safe_close(file1_fd);
1276 safe_close(open_tree_fd);
1281 static int hardlink_crossing_idmapped_mounts(void)
1284 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1285 struct mount_attr attr = {
1286 .attr_set = MOUNT_ATTR_IDMAP,
1289 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1290 log_stderr("failure: chown_r");
1294 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1295 if (attr.userns_fd < 0) {
1296 log_stderr("failure: get_userns_fd");
1300 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1303 AT_SYMLINK_NOFOLLOW |
1306 if (open_tree_fd1 < 0) {
1307 log_stderr("failure: sys_open_tree");
1311 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1312 log_stderr("failure: sys_mount_setattr");
1316 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1318 log_stderr("failure: openat");
1322 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1323 log_stderr("failure: expected_uid_gid");
1327 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1328 log_stderr("failure: expected_uid_gid");
1332 safe_close(file1_fd);
1334 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1335 log_stderr("failure: mkdirat");
1339 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1341 AT_SYMLINK_NOFOLLOW |
1345 if (open_tree_fd2 < 0) {
1346 log_stderr("failure: sys_open_tree");
1350 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1351 log_stderr("failure: sys_mount_setattr");
1355 /* We're crossing a mountpoint so this must fail.
1357 * Note that this must also fail for non-idmapped mounts but here we're
1358 * interested in making sure we're not introducing an accidental way to
1359 * violate that restriction or that suddenly this becomes possible.
1361 if (!linkat(open_tree_fd1, FILE1, open_tree_fd2, HARDLINK1, 0)) {
1362 log_stderr("failure: linkat");
1365 if (errno != EXDEV) {
1366 log_stderr("failure: errno");
1371 log_debug("Ran test");
1373 safe_close(attr.userns_fd);
1374 safe_close(file1_fd);
1375 safe_close(open_tree_fd1);
1376 safe_close(open_tree_fd2);
1381 static int hardlink_from_idmapped_mount(void)
1384 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1385 struct mount_attr attr = {
1386 .attr_set = MOUNT_ATTR_IDMAP,
1389 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1390 log_stderr("failure: chown_r");
1394 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1395 if (attr.userns_fd < 0) {
1396 log_stderr("failure: get_userns_fd");
1400 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1403 AT_SYMLINK_NOFOLLOW |
1406 if (open_tree_fd < 0) {
1407 log_stderr("failure: sys_open_tree");
1411 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1412 log_stderr("failure: sys_mount_setattr");
1416 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1418 log_stderr("failure: openat");
1421 safe_close(file1_fd);
1423 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1424 log_stderr("failure: expected_uid_gid");
1428 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1429 log_stderr("failure: expected_uid_gid");
1433 /* We're not crossing a mountpoint so this must succeed. */
1434 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0)) {
1435 log_stderr("failure: linkat");
1441 log_debug("Ran test");
1443 safe_close(attr.userns_fd);
1444 safe_close(file1_fd);
1445 safe_close(open_tree_fd);
1450 static int hardlink_from_idmapped_mount_in_userns(void)
1453 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1454 struct mount_attr attr = {
1455 .attr_set = MOUNT_ATTR_IDMAP,
1459 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1460 log_stderr("failure: chown_r");
1464 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1465 if (attr.userns_fd < 0) {
1466 log_stderr("failure: get_userns_fd");
1470 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1473 AT_SYMLINK_NOFOLLOW |
1476 if (open_tree_fd < 0) {
1477 log_stderr("failure: sys_open_tree");
1481 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1482 log_stderr("failure: sys_mount_setattr");
1488 log_stderr("failure: fork");
1492 if (!switch_userns(attr.userns_fd, 0, 0, false))
1493 die("failure: switch_userns");
1495 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1497 die("failure: create");
1499 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1500 die("failure: check ownership");
1502 /* We're not crossing a mountpoint so this must succeed. */
1503 if (linkat(open_tree_fd, FILE1, open_tree_fd, HARDLINK1, 0))
1504 die("failure: create");
1506 if (!expected_uid_gid(open_tree_fd, HARDLINK1, 0, 0, 0))
1507 die("failure: check ownership");
1512 if (wait_for_pid(pid))
1516 log_debug("Ran test");
1518 safe_close(attr.userns_fd);
1519 safe_close(file1_fd);
1520 safe_close(open_tree_fd);
1525 static int rename_crossing_mounts(void)
1528 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1530 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1531 log_stderr("failure: chown_r");
1535 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1538 AT_SYMLINK_NOFOLLOW |
1541 if (open_tree_fd < 0) {
1542 log_stderr("failure: sys_open_tree");
1546 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1548 log_stderr("failure: openat");
1552 if (mkdirat(open_tree_fd, DIR1, 0777)) {
1553 log_stderr("failure: mkdirat");
1557 /* We're crossing a mountpoint so this must fail.
1559 * Note that this must also fail for non-idmapped mounts but here we're
1560 * interested in making sure we're not introducing an accidental way to
1561 * violate that restriction or that suddenly this becomes possible.
1563 if (!renameat(open_tree_fd, FILE1, t_dir1_fd, FILE1_RENAME)) {
1564 log_stderr("failure: renameat");
1567 if (errno != EXDEV) {
1568 log_stderr("failure: errno");
1573 log_debug("Ran test");
1575 safe_close(file1_fd);
1576 safe_close(open_tree_fd);
1581 static int rename_crossing_idmapped_mounts(void)
1584 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
1585 struct mount_attr attr = {
1586 .attr_set = MOUNT_ATTR_IDMAP,
1589 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1590 log_stderr("failure: chown_r");
1594 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1595 if (attr.userns_fd < 0) {
1596 log_stderr("failure: get_userns_fd");
1600 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
1603 AT_SYMLINK_NOFOLLOW |
1606 if (open_tree_fd1 < 0) {
1607 log_stderr("failure: sys_open_tree");
1611 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1612 log_stderr("failure: sys_mount_setattr");
1616 file1_fd = openat(open_tree_fd1, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1618 log_stderr("failure: openat");
1622 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 0, 0)) {
1623 log_stderr("failure: expected_uid_gid");
1627 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1628 log_stderr("failure: expected_uid_gid");
1632 if (mkdirat(open_tree_fd1, DIR1, 0777)) {
1633 log_stderr("failure: mkdirat");
1637 open_tree_fd2 = sys_open_tree(t_dir1_fd, DIR1,
1639 AT_SYMLINK_NOFOLLOW |
1643 if (open_tree_fd2 < 0) {
1644 log_stderr("failure: sys_open_tree");
1648 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1649 log_stderr("failure: sys_mount_setattr");
1653 /* We're crossing a mountpoint so this must fail.
1655 * Note that this must also fail for non-idmapped mounts but here we're
1656 * interested in making sure we're not introducing an accidental way to
1657 * violate that restriction or that suddenly this becomes possible.
1659 if (!renameat(open_tree_fd1, FILE1, open_tree_fd2, FILE1_RENAME)) {
1660 log_stderr("failure: renameat");
1663 if (errno != EXDEV) {
1664 log_stderr("failure: errno");
1669 log_debug("Ran test");
1671 safe_close(attr.userns_fd);
1672 safe_close(file1_fd);
1673 safe_close(open_tree_fd1);
1674 safe_close(open_tree_fd2);
1679 static int rename_from_idmapped_mount(void)
1682 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1683 struct mount_attr attr = {
1684 .attr_set = MOUNT_ATTR_IDMAP,
1687 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1688 log_stderr("failure: chown_r");
1692 attr.userns_fd = get_userns_fd(10000, 0, 10000);
1693 if (attr.userns_fd < 0) {
1694 log_stderr("failure: get_userns_fd");
1698 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1701 AT_SYMLINK_NOFOLLOW |
1704 if (open_tree_fd < 0) {
1705 log_stderr("failure: sys_open_tree");
1709 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1710 log_stderr("failure: sys_mount_setattr");
1714 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1716 log_stderr("failure: openat");
1720 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0)) {
1721 log_stderr("failure: expected_uid_gid");
1725 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000)) {
1726 log_stderr("failure: expected_uid_gid");
1730 /* We're not crossing a mountpoint so this must succeed. */
1731 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME)) {
1732 log_stderr("failure: renameat");
1737 log_debug("Ran test");
1739 safe_close(attr.userns_fd);
1740 safe_close(file1_fd);
1741 safe_close(open_tree_fd);
1746 static int rename_from_idmapped_mount_in_userns(void)
1749 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1751 struct mount_attr attr = {
1752 .attr_set = MOUNT_ATTR_IDMAP,
1755 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1756 log_stderr("failure: chown_r");
1760 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1761 if (attr.userns_fd < 0) {
1762 log_stderr("failure: get_userns_fd");
1766 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1769 AT_SYMLINK_NOFOLLOW |
1772 if (open_tree_fd < 0) {
1773 log_stderr("failure: sys_open_tree");
1777 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1778 log_stderr("failure: sys_mount_setattr");
1784 log_stderr("failure: fork");
1788 if (!switch_userns(attr.userns_fd, 0, 0, false))
1789 die("failure: switch_userns");
1791 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1793 die("failure: create");
1795 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
1796 die("failure: check ownership");
1798 /* We're not crossing a mountpoint so this must succeed. */
1799 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
1800 die("failure: create");
1802 if (!expected_uid_gid(open_tree_fd, FILE1_RENAME, 0, 0, 0))
1803 die("failure: check ownership");
1808 if (wait_for_pid(pid))
1812 log_debug("Ran test");
1814 safe_close(attr.userns_fd);
1815 safe_close(file1_fd);
1816 safe_close(open_tree_fd);
1821 static int symlink_regular_mounts(void)
1824 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1827 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1829 log_stderr("failure: openat");
1833 if (chown_r(t_mnt_fd, T_DIR1, 10000, 10000)) {
1834 log_stderr("failure: chown_r");
1838 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1841 AT_SYMLINK_NOFOLLOW |
1844 if (open_tree_fd < 0) {
1845 log_stderr("failure: sys_open_tree");
1849 if (symlinkat(FILE1, open_tree_fd, FILE2)) {
1850 log_stderr("failure: symlinkat");
1854 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW)) {
1855 log_stderr("failure: fchownat");
1859 if (fstatat(open_tree_fd, FILE2, &st, AT_SYMLINK_NOFOLLOW)) {
1860 log_stderr("failure: fstatat");
1864 if (st.st_uid != 15000 || st.st_gid != 15000) {
1865 log_stderr("failure: compare ids");
1869 if (fstatat(open_tree_fd, FILE1, &st, 0)) {
1870 log_stderr("failure: fstatat");
1874 if (st.st_uid != 10000 || st.st_gid != 10000) {
1875 log_stderr("failure: compare ids");
1880 log_debug("Ran test");
1882 safe_close(file1_fd);
1883 safe_close(open_tree_fd);
1888 static int symlink_idmapped_mounts(void)
1891 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1892 struct mount_attr attr = {
1893 .attr_set = MOUNT_ATTR_IDMAP,
1897 if (!caps_supported())
1900 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
1902 log_stderr("failure: openat");
1906 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1907 log_stderr("failure: chown_r");
1911 /* Changing mount properties on a detached mount. */
1912 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1913 if (attr.userns_fd < 0) {
1914 log_stderr("failure: get_userns_fd");
1918 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1921 AT_SYMLINK_NOFOLLOW |
1924 if (open_tree_fd < 0) {
1925 log_stderr("failure: sys_open_tree");
1929 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
1930 log_stderr("failure: sys_mount_setattr");
1936 log_stderr("failure: fork");
1940 if (!switch_fsids(10000, 10000))
1941 die("failure: switch fsids");
1944 die("failure: raise caps");
1946 if (symlinkat(FILE1, open_tree_fd, FILE2))
1947 die("failure: create");
1949 if (fchownat(open_tree_fd, FILE2, 15000, 15000, AT_SYMLINK_NOFOLLOW))
1950 die("failure: change ownership");
1952 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 15000, 15000))
1953 die("failure: check ownership");
1955 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
1956 die("failure: check ownership");
1960 if (wait_for_pid(pid))
1964 log_debug("Ran test");
1966 safe_close(attr.userns_fd);
1967 safe_close(file1_fd);
1968 safe_close(open_tree_fd);
1973 static int symlink_idmapped_mounts_in_userns(void)
1976 int file1_fd = -EBADF, open_tree_fd = -EBADF;
1977 struct mount_attr attr = {
1978 .attr_set = MOUNT_ATTR_IDMAP,
1982 if (chown_r(t_mnt_fd, T_DIR1, 0, 0)) {
1983 log_stderr("failure: chown_r");
1987 /* Changing mount properties on a detached mount. */
1988 attr.userns_fd = get_userns_fd(0, 10000, 10000);
1989 if (attr.userns_fd < 0) {
1990 log_stderr("failure: get_userns_fd");
1994 open_tree_fd = sys_open_tree(t_dir1_fd, "",
1997 AT_SYMLINK_NOFOLLOW |
2000 if (open_tree_fd < 0) {
2001 log_stderr("failure: sys_open_tree");
2005 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2006 log_stderr("failure: sys_mount_setattr");
2012 log_stderr("failure: fork");
2016 if (!switch_userns(attr.userns_fd, 0, 0, false))
2017 die("failure: switch_userns");
2019 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2021 die("failure: create");
2022 safe_close(file1_fd);
2024 if (symlinkat(FILE1, open_tree_fd, FILE2))
2025 die("failure: create");
2027 if (fchownat(open_tree_fd, FILE2, 5000, 5000, AT_SYMLINK_NOFOLLOW))
2028 die("failure: change ownership");
2030 if (!expected_uid_gid(open_tree_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000))
2031 die("failure: check ownership");
2033 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
2034 die("failure: check ownership");
2039 if (wait_for_pid(pid))
2042 if (!expected_uid_gid(t_dir1_fd, FILE2, AT_SYMLINK_NOFOLLOW, 5000, 5000)) {
2043 log_stderr("failure: expected_uid_gid");
2047 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2048 log_stderr("failure: expected_uid_gid");
2053 log_debug("Ran test");
2055 safe_close(attr.userns_fd);
2056 safe_close(file1_fd);
2057 safe_close(open_tree_fd);
2062 /* Validate that a caller whose fsids map into the idmapped mount within it's
2063 * user namespace cannot create any device nodes.
2065 static int device_node_in_userns(void)
2068 int open_tree_fd = -EBADF;
2069 struct mount_attr attr = {
2070 .attr_set = MOUNT_ATTR_IDMAP,
2074 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2075 if (attr.userns_fd < 0) {
2076 log_stderr("failure: get_userns_fd");
2080 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2083 AT_SYMLINK_NOFOLLOW |
2086 if (open_tree_fd < 0) {
2087 log_stderr("failure: sys_open_tree");
2091 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
2092 log_stderr("failure: sys_mount_setattr");
2098 log_stderr("failure: fork");
2102 if (!switch_userns(attr.userns_fd, 0, 0, false))
2103 die("failure: switch_userns");
2105 /* create character device */
2106 if (!mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1)))
2107 die("failure: create");
2112 if (wait_for_pid(pid))
2116 log_debug("Ran test");
2118 safe_close(attr.userns_fd);
2119 safe_close(open_tree_fd);
2125 /* Validate that changing file ownership works correctly on idmapped mounts. */
2126 static int expected_uid_gid_idmapped_mounts(void)
2129 int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
2130 struct mount_attr attr1 = {
2131 .attr_set = MOUNT_ATTR_IDMAP,
2133 struct mount_attr attr2 = {
2134 .attr_set = MOUNT_ATTR_IDMAP,
2138 if (!switch_fsids(0, 0)) {
2139 log_stderr("failure: switch_fsids");
2143 /* create regular file via open() */
2144 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2146 log_stderr("failure: openat");
2150 /* create regular file via mknod */
2151 if (mknodat(t_dir1_fd, FILE2, S_IFREG | 0000, 0)) {
2152 log_stderr("failure: mknodat");
2156 /* create character device */
2157 if (mknodat(t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(5, 1))) {
2158 log_stderr("failure: mknodat");
2162 /* create hardlink */
2163 if (linkat(t_dir1_fd, FILE1, t_dir1_fd, HARDLINK1, 0)) {
2164 log_stderr("failure: linkat");
2168 /* create symlink */
2169 if (symlinkat(FILE2, t_dir1_fd, SYMLINK1)) {
2170 log_stderr("failure: symlinkat");
2174 /* create directory */
2175 if (mkdirat(t_dir1_fd, DIR1, 0700)) {
2176 log_stderr("failure: mkdirat");
2180 /* Changing mount properties on a detached mount. */
2181 attr1.userns_fd = get_userns_fd(0, 10000, 10000);
2182 if (attr1.userns_fd < 0) {
2183 log_stderr("failure: get_userns_fd");
2187 open_tree_fd1 = sys_open_tree(t_dir1_fd, "",
2190 AT_SYMLINK_NOFOLLOW |
2193 if (open_tree_fd1 < 0) {
2194 log_stderr("failure: sys_open_tree");
2198 if (sys_mount_setattr(open_tree_fd1, "", AT_EMPTY_PATH, &attr1, sizeof(attr1))) {
2199 log_stderr("failure: sys_mount_setattr");
2203 /* Validate that all files created through the image mountpoint are
2204 * owned by the callers fsuid and fsgid.
2206 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2207 log_stderr("failure: expected_uid_gid");
2210 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2211 log_stderr("failure: expected_uid_gid");
2214 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2215 log_stderr("failure: expected_uid_gid");
2218 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2219 log_stderr("failure: expected_uid_gid");
2222 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
2223 log_stderr("failure: expected_uid_gid");
2226 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2227 log_stderr("failure: expected_uid_gid");
2230 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2231 log_stderr("failure: expected_uid_gid");
2235 /* Validate that all files are owned by the uid and gid specified in
2236 * the idmapping of the mount they are accessed from.
2238 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2239 log_stderr("failure: expected_uid_gid");
2242 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2243 log_stderr("failure: expected_uid_gid");
2246 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2247 log_stderr("failure: expected_uid_gid");
2250 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2251 log_stderr("failure: expected_uid_gid");
2254 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
2255 log_stderr("failure: expected_uid_gid");
2258 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2259 log_stderr("failure: expected_uid_gid");
2262 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2263 log_stderr("failure: expected_uid_gid");
2267 /* Changing mount properties on a detached mount. */
2268 attr2.userns_fd = get_userns_fd(0, 30000, 2001);
2269 if (attr2.userns_fd < 0) {
2270 log_stderr("failure: get_userns_fd");
2274 open_tree_fd2 = sys_open_tree(t_dir1_fd, "",
2277 AT_SYMLINK_NOFOLLOW |
2280 if (open_tree_fd2 < 0) {
2281 log_stderr("failure: sys_open_tree");
2285 if (sys_mount_setattr(open_tree_fd2, "", AT_EMPTY_PATH, &attr2, sizeof(attr2))) {
2286 log_stderr("failure: sys_mount_setattr");
2290 /* Validate that all files are owned by the uid and gid specified in
2291 * the idmapping of the mount they are accessed from.
2293 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2294 log_stderr("failure: expected_uid_gid");
2297 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2298 log_stderr("failure: expected_uid_gid");
2301 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2302 log_stderr("failure: expected_uid_gid");
2305 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2306 log_stderr("failure: expected_uid_gid");
2309 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 30000, 30000)) {
2310 log_stderr("failure: expected_uid_gid");
2313 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2314 log_stderr("failure: expected_uid_gid");
2317 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2318 log_stderr("failure: expected_uid_gid");
2322 /* Change ownership throught original image mountpoint. */
2323 if (fchownat(t_dir1_fd, FILE1, 2000, 2000, 0)) {
2324 log_stderr("failure: fchownat");
2327 if (fchownat(t_dir1_fd, FILE2, 2000, 2000, 0)) {
2328 log_stderr("failure: fchownat");
2331 if (fchownat(t_dir1_fd, HARDLINK1, 2000, 2000, 0)) {
2332 log_stderr("failure: fchownat");
2335 if (fchownat(t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
2336 log_stderr("failure: fchownat");
2339 if (fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) {
2340 log_stderr("failure: fchownat");
2343 if (fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH)) {
2344 log_stderr("failure: fchownat");
2347 if (fchownat(t_dir1_fd, DIR1, 2000, 2000, AT_EMPTY_PATH)) {
2348 log_stderr("failure: fchownat");
2352 /* Check ownership through original mount. */
2353 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 2000, 2000)) {
2354 log_stderr("failure: expected_uid_gid");
2357 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 2000, 2000)) {
2358 log_stderr("failure: expected_uid_gid");
2361 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 2000, 2000)) {
2362 log_stderr("failure: expected_uid_gid");
2365 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
2366 log_stderr("failure: expected_uid_gid");
2369 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 3000, 3000)) {
2370 log_stderr("failure: expected_uid_gid");
2373 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 2000, 2000)) {
2374 log_stderr("failure: expected_uid_gid");
2377 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 2000, 2000)) {
2378 log_stderr("failure: expected_uid_gid");
2382 /* Check ownership through first idmapped mount. */
2383 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 12000, 12000)) {
2384 log_stderr("failure:expected_uid_gid ");
2387 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 12000, 12000)) {
2388 log_stderr("failure: expected_uid_gid");
2391 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 12000, 12000)) {
2392 log_stderr("failure: expected_uid_gid");
2395 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
2396 log_stderr("failure: expected_uid_gid");
2399 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 13000, 13000)) {
2400 log_stderr("failure: expected_uid_gid");
2403 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 12000, 12000)) {
2404 log_stderr("failure:expected_uid_gid ");
2407 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 12000, 12000)) {
2408 log_stderr("failure: expected_uid_gid");
2412 /* Check ownership through second idmapped mount. */
2413 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 32000, 32000)) {
2414 log_stderr("failure: expected_uid_gid");
2417 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 32000, 32000)) {
2418 log_stderr("failure: expected_uid_gid");
2421 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 32000, 32000)) {
2422 log_stderr("failure: expected_uid_gid");
2425 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
2426 log_stderr("failure: expected_uid_gid");
2429 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid)) {
2430 log_stderr("failure: expected_uid_gid");
2433 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 32000, 32000)) {
2434 log_stderr("failure: expected_uid_gid");
2437 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 32000, 32000)) {
2438 log_stderr("failure: expected_uid_gid");
2444 log_stderr("failure: fork");
2448 if (!switch_userns(attr1.userns_fd, 0, 0, false))
2449 die("failure: switch_userns");
2451 if (!fchownat(t_dir1_fd, FILE1, 1000, 1000, 0))
2452 die("failure: fchownat");
2453 if (!fchownat(t_dir1_fd, FILE2, 1000, 1000, 0))
2454 die("failure: fchownat");
2455 if (!fchownat(t_dir1_fd, HARDLINK1, 1000, 1000, 0))
2456 die("failure: fchownat");
2457 if (!fchownat(t_dir1_fd, CHRDEV1, 1000, 1000, 0))
2458 die("failure: fchownat");
2459 if (!fchownat(t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2460 die("failure: fchownat");
2461 if (!fchownat(t_dir1_fd, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2462 die("failure: fchownat");
2463 if (!fchownat(t_dir1_fd, DIR1, 1000, 1000, AT_EMPTY_PATH))
2464 die("failure: fchownat");
2466 if (!fchownat(open_tree_fd2, FILE1, 1000, 1000, 0))
2467 die("failure: fchownat");
2468 if (!fchownat(open_tree_fd2, FILE2, 1000, 1000, 0))
2469 die("failure: fchownat");
2470 if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
2471 die("failure: fchownat");
2472 if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
2473 die("failure: fchownat");
2474 if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2475 die("failure: fchownat");
2476 if (!fchownat(open_tree_fd2, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2477 die("failure: fchownat");
2478 if (!fchownat(open_tree_fd2, DIR1, 1000, 1000, AT_EMPTY_PATH))
2479 die("failure: fchownat");
2481 if (fchownat(open_tree_fd1, FILE1, 1000, 1000, 0))
2482 die("failure: fchownat");
2483 if (fchownat(open_tree_fd1, FILE2, 1000, 1000, 0))
2484 die("failure: fchownat");
2485 if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
2486 die("failure: fchownat");
2487 if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
2488 die("failure: fchownat");
2489 if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2490 die("failure: fchownat");
2491 if (fchownat(open_tree_fd1, SYMLINK1, 1000, 1000, AT_EMPTY_PATH))
2492 die("failure: fchownat");
2493 if (fchownat(open_tree_fd1, DIR1, 1000, 1000, AT_EMPTY_PATH))
2494 die("failure: fchownat");
2496 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2497 die("failure: expected_uid_gid");
2498 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2499 die("failure: expected_uid_gid");
2500 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2501 die("failure: expected_uid_gid");
2502 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2503 die("failure: expected_uid_gid");
2504 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2505 die("failure: expected_uid_gid");
2506 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2507 die("failure: expected_uid_gid");
2508 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2509 die("failure: expected_uid_gid");
2511 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, t_overflowuid, t_overflowgid))
2512 die("failure: expected_uid_gid");
2513 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, t_overflowuid, t_overflowgid))
2514 die("failure: expected_uid_gid");
2515 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2516 die("failure: expected_uid_gid");
2517 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2518 die("failure: expected_uid_gid");
2519 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2520 die("failure: expected_uid_gid");
2521 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2522 die("failure: expected_uid_gid");
2523 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, t_overflowuid, t_overflowgid))
2524 die("failure: expected_uid_gid");
2526 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 1000, 1000))
2527 die("failure: expected_uid_gid");
2528 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 1000, 1000))
2529 die("failure: expected_uid_gid");
2530 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
2531 die("failure: expected_uid_gid");
2532 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
2533 die("failure: expected_uid_gid");
2534 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2535 die("failure: expected_uid_gid");
2536 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 1000, 1000))
2537 die("failure: expected_uid_gid");
2538 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 1000, 1000))
2539 die("failure: expected_uid_gid");
2544 if (wait_for_pid(pid))
2547 /* Check ownership through original mount. */
2548 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 1000, 1000)) {
2549 log_stderr("failure: expected_uid_gid");
2552 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 1000, 1000)) {
2553 log_stderr("failure: expected_uid_gid");
2556 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 1000, 1000)) {
2557 log_stderr("failure: expected_uid_gid");
2560 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
2561 log_stderr("failure: expected_uid_gid");
2564 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2565 log_stderr("failure: expected_uid_gid");
2568 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 1000, 1000)) {
2569 log_stderr("failure: expected_uid_gid");
2572 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 1000, 1000)) {
2573 log_stderr("failure: expected_uid_gid");
2577 /* Check ownership through first idmapped mount. */
2578 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 11000, 11000)) {
2579 log_stderr("failure: expected_uid_gid");
2582 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 11000, 11000)) {
2583 log_stderr("failure: expected_uid_gid");
2586 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 11000, 11000)) {
2587 log_stderr("failure: expected_uid_gid");
2590 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
2591 log_stderr("failure: expected_uid_gid");
2594 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2595 log_stderr("failure: expected_uid_gid");
2598 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 11000, 11000)) {
2599 log_stderr("failure: expected_uid_gid");
2602 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 11000, 11000)) {
2603 log_stderr("failure: expected_uid_gid");
2607 /* Check ownership through second idmapped mount. */
2608 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 31000, 31000)) {
2609 log_stderr("failure: expected_uid_gid");
2612 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 31000, 31000)) {
2613 log_stderr("failure: expected_uid_gid");
2616 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 31000, 31000)) {
2617 log_stderr("failure: expected_uid_gid");
2620 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
2621 log_stderr("failure: expected_uid_gid");
2624 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2625 log_stderr("failure: expected_uid_gid");
2628 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 31000, 31000)) {
2629 log_stderr("failure: expected_uid_gid");
2632 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 31000, 31000)) {
2633 log_stderr("failure: expected_uid_gid");
2639 log_stderr("failure: fork");
2643 if (!switch_userns(attr2.userns_fd, 0, 0, false))
2644 die("failure: switch_userns");
2646 if (!fchownat(t_dir1_fd, FILE1, 0, 0, 0))
2647 die("failure: fchownat");
2648 if (!fchownat(t_dir1_fd, FILE2, 0, 0, 0))
2649 die("failure: fchownat");
2650 if (!fchownat(t_dir1_fd, HARDLINK1, 0, 0, 0))
2651 die("failure: fchownat");
2652 if (!fchownat(t_dir1_fd, CHRDEV1, 0, 0, 0))
2653 die("failure: fchownat");
2654 if (!fchownat(t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2655 die("failure: fchownat");
2656 if (!fchownat(t_dir1_fd, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2657 die("failure: fchownat");
2658 if (!fchownat(t_dir1_fd, DIR1, 0, 0, AT_EMPTY_PATH))
2659 die("failure: fchownat");
2661 if (!fchownat(open_tree_fd1, FILE1, 0, 0, 0))
2662 die("failure: fchownat");
2663 if (!fchownat(open_tree_fd1, FILE2, 0, 0, 0))
2664 die("failure: fchownat");
2665 if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
2666 die("failure: fchownat");
2667 if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
2668 die("failure: fchownat");
2669 if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2670 die("failure: fchownat");
2671 if (!fchownat(open_tree_fd1, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2672 die("failure: fchownat");
2673 if (!fchownat(open_tree_fd1, DIR1, 0, 0, AT_EMPTY_PATH))
2674 die("failure: fchownat");
2676 if (fchownat(open_tree_fd2, FILE1, 0, 0, 0))
2677 die("failure: fchownat");
2678 if (fchownat(open_tree_fd2, FILE2, 0, 0, 0))
2679 die("failure: fchownat");
2680 if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
2681 die("failure: fchownat");
2682 if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
2683 die("failure: fchownat");
2684 if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
2685 die("failure: fchownat");
2686 if (fchownat(open_tree_fd2, SYMLINK1, 0, 0, AT_EMPTY_PATH))
2687 die("failure: fchownat");
2688 if (fchownat(open_tree_fd2, DIR1, 0, 0, AT_EMPTY_PATH))
2689 die("failure: fchownat");
2691 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, t_overflowuid, t_overflowgid))
2692 die("failure: expected_uid_gid");
2693 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, t_overflowuid, t_overflowgid))
2694 die("failure: expected_uid_gid");
2695 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2696 die("failure: expected_uid_gid");
2697 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2698 die("failure: expected_uid_gid");
2699 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2700 die("failure: expected_uid_gid");
2701 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2702 die("failure: expected_uid_gid");
2703 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, t_overflowuid, t_overflowgid))
2704 die("failure: expected_uid_gid");
2706 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, t_overflowuid, t_overflowgid))
2707 die("failure: expected_uid_gid");
2708 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, t_overflowuid, t_overflowgid))
2709 die("failure: expected_uid_gid");
2710 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, t_overflowuid, t_overflowgid))
2711 die("failure: expected_uid_gid");
2712 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, t_overflowuid, t_overflowgid))
2713 die("failure: expected_uid_gid");
2714 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, t_overflowuid, t_overflowgid))
2715 die("failure: expected_uid_gid");
2716 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, t_overflowuid, t_overflowgid))
2717 die("failure: expected_uid_gid");
2718 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, t_overflowuid, t_overflowgid))
2719 die("failure: expected_uid_gid");
2721 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 0, 0))
2722 die("failure: expected_uid_gid");
2723 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 0, 0))
2724 die("failure: expected_uid_gid");
2725 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
2726 die("failure: expected_uid_gid");
2727 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
2728 die("failure: expected_uid_gid");
2729 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
2730 die("failure: expected_uid_gid");
2731 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 0, 0))
2732 die("failure: expected_uid_gid");
2733 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 0, 0))
2734 die("failure: expected_uid_gid");
2739 if (wait_for_pid(pid))
2742 /* Check ownership through original mount. */
2743 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
2744 log_stderr("failure: expected_uid_gid");
2747 if (!expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0)) {
2748 log_stderr("failure: expected_uid_gid");
2751 if (!expected_uid_gid(t_dir1_fd, HARDLINK1, 0, 0, 0)) {
2752 log_stderr("failure: expected_uid_gid");
2755 if (!expected_uid_gid(t_dir1_fd, CHRDEV1, 0, 0, 0)) {
2756 log_stderr("failure: expected_uid_gid");
2759 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
2760 log_stderr("failure: expected_uid_gid");
2763 if (!expected_uid_gid(t_dir1_fd, SYMLINK1, 0, 0, 0)) {
2764 log_stderr("failure: expected_uid_gid");
2767 if (!expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0)) {
2768 log_stderr("failure: expected_uid_gid");
2772 /* Check ownership through first idmapped mount. */
2773 if (!expected_uid_gid(open_tree_fd1, FILE1, 0, 10000, 10000)) {
2774 log_stderr("failure: expected_uid_gid");
2777 if (!expected_uid_gid(open_tree_fd1, FILE2, 0, 10000, 10000)) {
2778 log_stderr("failure: expected_uid_gid");
2781 if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 10000, 10000)) {
2782 log_stderr("failure: expected_uid_gid");
2785 if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
2786 log_stderr("failure: expected_uid_gid");
2789 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
2790 log_stderr("failure: expected_uid_gid");
2793 if (!expected_uid_gid(open_tree_fd1, SYMLINK1, 0, 10000, 10000)) {
2794 log_stderr("failure: expected_uid_gid");
2797 if (!expected_uid_gid(open_tree_fd1, DIR1, 0, 10000, 10000)) {
2798 log_stderr("failure: expected_uid_gid");
2802 /* Check ownership through second idmapped mount. */
2803 if (!expected_uid_gid(open_tree_fd2, FILE1, 0, 30000, 30000)) {
2804 log_stderr("failure: expected_uid_gid");
2807 if (!expected_uid_gid(open_tree_fd2, FILE2, 0, 30000, 30000)) {
2808 log_stderr("failure: expected_uid_gid");
2811 if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 30000, 30000)) {
2812 log_stderr("failure: expected_uid_gid");
2815 if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
2816 log_stderr("failure: expected_uid_gid");
2819 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 32000, 32000)) {
2820 log_stderr("failure: expected_uid_gid");
2823 if (!expected_uid_gid(open_tree_fd2, SYMLINK1, 0, 30000, 30000)) {
2824 log_stderr("failure: expected_uid_gid");
2827 if (!expected_uid_gid(open_tree_fd2, DIR1, 0, 30000, 30000)) {
2828 log_stderr("failure: expected_uid_gid");
2833 log_debug("Ran test");
2835 safe_close(attr1.userns_fd);
2836 safe_close(attr2.userns_fd);
2837 safe_close(file1_fd);
2838 safe_close(open_tree_fd1);
2839 safe_close(open_tree_fd2);
2844 static int fscaps(void)
2847 int file1_fd = -EBADF;
2848 struct mount_attr attr = {
2849 .attr_set = MOUNT_ATTR_IDMAP,
2853 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2855 log_stderr("failure: openat");
2859 /* Skip if vfs caps are unsupported. */
2860 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2863 /* Changing mount properties on a detached mount. */
2864 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2865 if (attr.userns_fd < 0) {
2866 log_stderr("failure: get_userns_fd");
2870 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
2871 log_stderr("failure: expected_dummy_vfs_caps_uid");
2877 log_stderr("failure: fork");
2881 if (!switch_userns(attr.userns_fd, 0, 0, false))
2882 die("failure: switch_userns");
2885 * On kernels before 5.12 this would succeed and return the
2886 * unconverted caps. Then - for whatever reason - this behavior
2887 * got changed and since 5.12 EOVERFLOW is returned when the
2888 * rootid stored alongside the vfs caps does not map to uid 0 in
2889 * the caller's user namespace.
2891 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
2892 die("failure: expected_dummy_vfs_caps_uid");
2897 if (wait_for_pid(pid))
2900 if (fremovexattr(file1_fd, "security.capability")) {
2901 log_stderr("failure: fremovexattr");
2904 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2905 log_stderr("failure: expected_dummy_vfs_caps_uid");
2908 if (errno != ENODATA) {
2909 log_stderr("failure: errno");
2913 if (set_dummy_vfs_caps(file1_fd, 0, 10000)) {
2914 log_stderr("failure: set_dummy_vfs_caps");
2918 if (!expected_dummy_vfs_caps_uid(file1_fd, 10000)) {
2919 log_stderr("failure: expected_dummy_vfs_caps_uid");
2925 log_stderr("failure: fork");
2929 if (!switch_userns(attr.userns_fd, 0, 0, false))
2930 die("failure: switch_userns");
2932 if (!expected_dummy_vfs_caps_uid(file1_fd, 0))
2933 die("failure: expected_dummy_vfs_caps_uid");
2938 if (wait_for_pid(pid))
2941 if (fremovexattr(file1_fd, "security.capability")) {
2942 log_stderr("failure: fremovexattr");
2945 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
2946 log_stderr("failure: expected_dummy_vfs_caps_uid");
2949 if (errno != ENODATA) {
2950 log_stderr("failure: errno");
2955 log_debug("Ran test");
2957 safe_close(attr.userns_fd);
2958 safe_close(file1_fd);
2963 static int fscaps_idmapped_mounts(void)
2966 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
2967 struct mount_attr attr = {
2968 .attr_set = MOUNT_ATTR_IDMAP,
2972 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
2974 log_stderr("failure: openat");
2978 /* Skip if vfs caps are unsupported. */
2979 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
2982 if (fremovexattr(file1_fd, "security.capability")) {
2983 log_stderr("failure: fremovexattr");
2987 /* Changing mount properties on a detached mount. */
2988 attr.userns_fd = get_userns_fd(0, 10000, 10000);
2989 if (attr.userns_fd < 0) {
2990 log_stderr("failure: get_userns_fd");
2994 open_tree_fd = sys_open_tree(t_dir1_fd, "",
2997 AT_SYMLINK_NOFOLLOW |
3000 if (open_tree_fd < 0) {
3001 log_stderr("failure: sys_open_tree");
3005 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3006 log_stderr("failure: sys_mount_setattr");
3010 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3011 if (file1_fd2 < 0) {
3012 log_stderr("failure: openat");
3016 if (!set_dummy_vfs_caps(file1_fd2, 0, 1000)) {
3017 log_stderr("failure: set_dummy_vfs_caps");
3021 if (set_dummy_vfs_caps(file1_fd2, 0, 10000)) {
3022 log_stderr("failure: set_dummy_vfs_caps");
3026 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3027 log_stderr("failure: expected_dummy_vfs_caps_uid");
3031 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3032 log_stderr("failure: expected_dummy_vfs_caps_uid");
3038 log_stderr("failure: fork");
3042 if (!switch_userns(attr.userns_fd, 0, 0, false))
3043 die("failure: switch_userns");
3045 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3046 die("failure: expected_dummy_vfs_caps_uid");
3051 if (wait_for_pid(pid))
3054 if (fremovexattr(file1_fd2, "security.capability")) {
3055 log_stderr("failure: fremovexattr");
3058 if (expected_dummy_vfs_caps_uid(file1_fd2, -1)) {
3059 log_stderr("failure: expected_dummy_vfs_caps_uid");
3062 if (errno != ENODATA) {
3063 log_stderr("failure: errno");
3067 if (set_dummy_vfs_caps(file1_fd2, 0, 12000)) {
3068 log_stderr("failure: set_dummy_vfs_caps");
3072 if (!expected_dummy_vfs_caps_uid(file1_fd2, 12000)) {
3073 log_stderr("failure: expected_dummy_vfs_caps_uid");
3077 if (!expected_dummy_vfs_caps_uid(file1_fd, 2000)) {
3078 log_stderr("failure: expected_dummy_vfs_caps_uid");
3084 log_stderr("failure: fork");
3088 if (!switch_userns(attr.userns_fd, 0, 0, false))
3089 die("failure: switch_userns");
3091 if (!expected_dummy_vfs_caps_uid(file1_fd2, 2000))
3092 die("failure: expected_dummy_vfs_caps_uid");
3097 if (wait_for_pid(pid))
3101 log_debug("Ran test");
3103 safe_close(attr.userns_fd);
3104 safe_close(file1_fd);
3105 safe_close(file1_fd2);
3106 safe_close(open_tree_fd);
3111 static int fscaps_idmapped_mounts_in_userns(void)
3114 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3115 struct mount_attr attr = {
3116 .attr_set = MOUNT_ATTR_IDMAP,
3120 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3122 log_stderr("failure: openat");
3126 /* Skip if vfs caps are unsupported. */
3127 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3130 if (fremovexattr(file1_fd, "security.capability")) {
3131 log_stderr("failure: fremovexattr");
3135 /* Changing mount properties on a detached mount. */
3136 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3137 if (attr.userns_fd < 0) {
3138 log_stderr("failure: get_userns_fd");
3142 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3145 AT_SYMLINK_NOFOLLOW |
3148 if (open_tree_fd < 0) {
3149 log_stderr("failure: sys_open_tree");
3153 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3154 log_stderr("failure: sys_mount_setattr");
3158 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3159 if (file1_fd2 < 0) {
3160 log_stderr("failure: openat");
3166 log_stderr("failure: fork");
3170 if (!switch_userns(attr.userns_fd, 0, 0, false))
3171 die("failure: switch_userns");
3173 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3174 die("failure: expected_dummy_vfs_caps_uid");
3175 if (errno != ENODATA)
3176 die("failure: errno");
3178 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3179 die("failure: set_dummy_vfs_caps");
3181 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3182 die("failure: expected_dummy_vfs_caps_uid");
3184 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000) && errno != EOVERFLOW)
3185 die("failure: expected_dummy_vfs_caps_uid");
3190 if (wait_for_pid(pid))
3193 if (!expected_dummy_vfs_caps_uid(file1_fd, 1000)) {
3194 log_stderr("failure: expected_dummy_vfs_caps_uid");
3199 log_debug("Ran test");
3201 safe_close(attr.userns_fd);
3202 safe_close(file1_fd);
3203 safe_close(file1_fd2);
3204 safe_close(open_tree_fd);
3209 static int fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns(void)
3212 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3213 struct mount_attr attr = {
3214 .attr_set = MOUNT_ATTR_IDMAP,
3218 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3220 log_stderr("failure: openat");
3224 /* Skip if vfs caps are unsupported. */
3225 if (set_dummy_vfs_caps(file1_fd, 0, 1000))
3228 if (fremovexattr(file1_fd, "security.capability")) {
3229 log_stderr("failure: fremovexattr");
3232 if (expected_dummy_vfs_caps_uid(file1_fd, -1)) {
3233 log_stderr("failure: expected_dummy_vfs_caps_uid");
3236 if (errno != ENODATA) {
3237 log_stderr("failure: errno");
3241 /* Changing mount properties on a detached mount. */
3242 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3243 if (attr.userns_fd < 0) {
3244 log_stderr("failure: get_userns_fd");
3248 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3251 AT_SYMLINK_NOFOLLOW |
3254 if (open_tree_fd < 0) {
3255 log_stderr("failure: sys_open_tree");
3259 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3260 log_stderr("failure: sys_mount_setattr");
3264 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3265 if (file1_fd2 < 0) {
3266 log_stderr("failure: openat");
3271 * Verify we can set an v3 fscap for real root this was regressed at
3272 * some point. Make sure this doesn't happen again!
3276 log_stderr("failure: fork");
3280 if (!switch_userns(attr.userns_fd, 0, 0, false))
3281 die("failure: switch_userns");
3283 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3284 die("failure: expected_dummy_vfs_caps_uid");
3285 if (errno != ENODATA)
3286 die("failure: errno");
3288 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3289 die("failure: set_dummy_vfs_caps");
3291 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3292 die("failure: expected_dummy_vfs_caps_uid");
3294 if (!expected_dummy_vfs_caps_uid(file1_fd, 0) && errno != EOVERFLOW)
3295 die("failure: expected_dummy_vfs_caps_uid");
3300 if (wait_for_pid(pid))
3303 if (!expected_dummy_vfs_caps_uid(file1_fd2, 10000)) {
3304 log_stderr("failure: expected_dummy_vfs_caps_uid");
3308 if (!expected_dummy_vfs_caps_uid(file1_fd, 0)) {
3309 log_stderr("failure: expected_dummy_vfs_caps_uid");
3314 log_debug("Ran test");
3316 safe_close(attr.userns_fd);
3317 safe_close(file1_fd);
3318 safe_close(file1_fd2);
3319 safe_close(open_tree_fd);
3324 static int fscaps_idmapped_mounts_in_userns_separate_userns(void)
3327 int file1_fd = -EBADF, file1_fd2 = -EBADF, open_tree_fd = -EBADF;
3328 struct mount_attr attr = {
3329 .attr_set = MOUNT_ATTR_IDMAP,
3333 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, 0644);
3335 log_stderr("failure: openat");
3339 /* Skip if vfs caps are unsupported. */
3340 if (set_dummy_vfs_caps(file1_fd, 0, 1000)) {
3341 log_stderr("failure: set_dummy_vfs_caps");
3345 if (fremovexattr(file1_fd, "security.capability")) {
3346 log_stderr("failure: fremovexattr");
3350 /* change ownership of all files to uid 0 */
3351 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
3352 log_stderr("failure: chown_r");
3356 /* Changing mount properties on a detached mount. */
3357 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
3358 if (attr.userns_fd < 0) {
3359 log_stderr("failure: get_userns_fd");
3363 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3366 AT_SYMLINK_NOFOLLOW |
3369 if (open_tree_fd < 0) {
3370 log_stderr("failure: sys_open_tree");
3374 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3375 log_stderr("failure: sys_mount_setattr");
3379 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, 0);
3380 if (file1_fd2 < 0) {
3381 log_stderr("failure: openat");
3387 log_stderr("failure: fork");
3393 userns_fd = get_userns_fd(0, 10000, 10000);
3395 die("failure: get_userns_fd");
3397 if (!switch_userns(userns_fd, 0, 0, false))
3398 die("failure: switch_userns");
3400 if (set_dummy_vfs_caps(file1_fd2, 0, 0))
3401 die("failure: set fscaps");
3403 if (!expected_dummy_vfs_caps_uid(file1_fd2, 0))
3404 die("failure: expected_dummy_vfs_caps_uid");
3406 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000) && errno != EOVERFLOW)
3407 die("failure: expected_dummy_vfs_caps_uid");
3412 if (wait_for_pid(pid))
3415 if (!expected_dummy_vfs_caps_uid(file1_fd, 20000)) {
3416 log_stderr("failure: expected_dummy_vfs_caps_uid");
3422 log_stderr("failure: fork");
3428 userns_fd = get_userns_fd(0, 10000, 10000);
3430 die("failure: get_userns_fd");
3432 if (!switch_userns(userns_fd, 0, 0, false))
3433 die("failure: switch_userns");
3435 if (fremovexattr(file1_fd2, "security.capability"))
3436 die("failure: fremovexattr");
3437 if (expected_dummy_vfs_caps_uid(file1_fd2, -1))
3438 die("failure: expected_dummy_vfs_caps_uid");
3439 if (errno != ENODATA)
3440 die("failure: errno");
3442 if (set_dummy_vfs_caps(file1_fd2, 0, 1000))
3443 die("failure: set_dummy_vfs_caps");
3445 if (!expected_dummy_vfs_caps_uid(file1_fd2, 1000))
3446 die("failure: expected_dummy_vfs_caps_uid");
3448 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000) && errno != EOVERFLOW)
3449 die("failure: expected_dummy_vfs_caps_uid");
3454 if (wait_for_pid(pid))
3457 if (!expected_dummy_vfs_caps_uid(file1_fd, 21000)) {
3458 log_stderr("failure: expected_dummy_vfs_caps_uid");
3463 log_debug("Ran test");
3465 safe_close(attr.userns_fd);
3466 safe_close(file1_fd);
3467 safe_close(file1_fd2);
3468 safe_close(open_tree_fd);
3473 /* Validate that when the IDMAP_MOUNT_TEST_RUN_SETID environment variable is set
3474 * to 1 that we are executed with setid privileges and if set to 0 we are not.
3475 * If the env variable isn't set the tests are not run.
3477 static void __attribute__((constructor)) setuid_rexec(void)
3479 const char *expected_euid_str, *expected_egid_str, *rexec;
3481 rexec = getenv("IDMAP_MOUNT_TEST_RUN_SETID");
3482 /* This is a regular test-suite run. */
3486 expected_euid_str = getenv("EXPECTED_EUID");
3487 expected_egid_str = getenv("EXPECTED_EGID");
3489 if (expected_euid_str && expected_egid_str) {
3490 uid_t expected_euid;
3491 gid_t expected_egid;
3493 expected_euid = atoi(expected_euid_str);
3494 expected_egid = atoi(expected_egid_str);
3496 if (strcmp(rexec, "1") == 0) {
3497 /* we're expecting to run setid */
3498 if ((getuid() != geteuid()) && (expected_euid == geteuid()) &&
3499 (getgid() != getegid()) && (expected_egid == getegid()))
3501 } else if (strcmp(rexec, "0") == 0) {
3502 /* we're expecting to not run setid */
3503 if ((getuid() == geteuid()) && (expected_euid == geteuid()) &&
3504 (getgid() == getegid()) && (expected_egid == getegid()))
3507 die("failure: non-setid");
3514 /* Validate that setid transitions are handled correctly. */
3515 static int setid_binaries(void)
3518 int file1_fd = -EBADF, exec_fd = -EBADF;
3521 /* create a file to be used as setuid binary */
3522 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3524 log_stderr("failure: openat");
3528 /* open our own executable */
3529 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3531 log_stderr("failure: openat");
3535 /* copy our own executable into the file we created */
3536 if (fd_to_fd(exec_fd, file1_fd)) {
3537 log_stderr("failure: fd_to_fd");
3541 /* chown the file to the uid and gid we want to assume */
3542 if (fchown(file1_fd, 5000, 5000)) {
3543 log_stderr("failure: fchown");
3547 /* set the setid bits and grant execute permissions to the group */
3548 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3549 log_stderr("failure: fchmod");
3553 /* Verify that the sid bits got raised. */
3554 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3555 log_stderr("failure: is_setid");
3559 safe_close(exec_fd);
3560 safe_close(file1_fd);
3562 /* Verify we run setid binary as uid and gid 5000 from the original
3567 log_stderr("failure: fork");
3571 static char *envp[] = {
3572 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3573 "EXPECTED_EUID=5000",
3574 "EXPECTED_EGID=5000",
3577 static char *argv[] = {
3581 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 5000, 5000))
3582 die("failure: expected_uid_gid");
3584 sys_execveat(t_dir1_fd, FILE1, argv, envp, 0);
3585 die("failure: sys_execveat");
3589 if (wait_for_pid(pid))
3593 log_debug("Ran test");
3599 /* Validate that setid transitions are handled correctly on idmapped mounts. */
3600 static int setid_binaries_idmapped_mounts(void)
3603 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3604 struct mount_attr attr = {
3605 .attr_set = MOUNT_ATTR_IDMAP,
3609 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3610 log_stderr("failure: mkdirat");
3614 /* create a file to be used as setuid binary */
3615 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3617 log_stderr("failure: openat");
3621 /* open our own executable */
3622 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3624 log_stderr("failure:openat ");
3628 /* copy our own executable into the file we created */
3629 if (fd_to_fd(exec_fd, file1_fd)) {
3630 log_stderr("failure: fd_to_fd");
3634 /* chown the file to the uid and gid we want to assume */
3635 if (fchown(file1_fd, 5000, 5000)) {
3636 log_stderr("failure: fchown");
3640 /* set the setid bits and grant execute permissions to the group */
3641 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3642 log_stderr("failure: fchmod");
3646 /* Verify that the sid bits got raised. */
3647 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3648 log_stderr("failure: is_setid");
3652 safe_close(exec_fd);
3653 safe_close(file1_fd);
3655 /* Changing mount properties on a detached mount. */
3656 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3657 if (attr.userns_fd < 0) {
3658 log_stderr("failure: get_userns_fd");
3662 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3665 AT_SYMLINK_NOFOLLOW |
3668 if (open_tree_fd < 0) {
3669 log_stderr("failure: sys_open_tree");
3673 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3674 log_stderr("failure: sys_mount_setattr");
3678 /* A detached mount will have an anonymous mount namespace attached to
3679 * it. This means that we can't execute setid binaries on a detached
3680 * mount because the mnt_may_suid() helper will fail the check_mount()
3681 * part of its check which compares the caller's mount namespace to the
3682 * detached mount's mount namespace. Since by definition an anonymous
3683 * mount namespace is not equale to any mount namespace currently in
3684 * use this can't work. So attach the mount to the filesystem first
3685 * before performing this check.
3687 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3688 log_stderr("failure: sys_move_mount");
3692 /* Verify we run setid binary as uid and gid 10000 from idmapped mount mount. */
3695 log_stderr("failure: fork");
3699 static char *envp[] = {
3700 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3701 "EXPECTED_EUID=15000",
3702 "EXPECTED_EGID=15000",
3705 static char *argv[] = {
3709 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 15000, 15000))
3710 die("failure: expected_uid_gid");
3712 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3713 die("failure: sys_execveat");
3718 if (wait_for_pid(pid))
3722 log_debug("Ran test");
3724 safe_close(exec_fd);
3725 safe_close(file1_fd);
3726 safe_close(open_tree_fd);
3728 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
3729 sys_umount2(t_buf, MNT_DETACH);
3730 rm_r(t_mnt_fd, DIR1);
3735 /* Validate that setid transitions are handled correctly on idmapped mounts
3736 * running in a user namespace where the uid and gid of the setid binary have no
3739 static int setid_binaries_idmapped_mounts_in_userns(void)
3742 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
3743 struct mount_attr attr = {
3744 .attr_set = MOUNT_ATTR_IDMAP,
3748 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
3749 log_stderr("failure: ");
3753 /* create a file to be used as setuid binary */
3754 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
3756 log_stderr("failure: openat");
3760 /* open our own executable */
3761 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
3763 log_stderr("failure: openat");
3767 /* copy our own executable into the file we created */
3768 if (fd_to_fd(exec_fd, file1_fd)) {
3769 log_stderr("failure: fd_to_fd");
3773 safe_close(exec_fd);
3775 /* chown the file to the uid and gid we want to assume */
3776 if (fchown(file1_fd, 5000, 5000)) {
3777 log_stderr("failure: fchown");
3781 /* set the setid bits and grant execute permissions to the group */
3782 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3783 log_stderr("failure: fchmod");
3787 /* Verify that the sid bits got raised. */
3788 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3789 log_stderr("failure: is_setid");
3793 safe_close(file1_fd);
3795 /* Changing mount properties on a detached mount. */
3796 attr.userns_fd = get_userns_fd(0, 10000, 10000);
3797 if (attr.userns_fd < 0) {
3798 log_stderr("failure: get_userns_fd");
3802 open_tree_fd = sys_open_tree(t_dir1_fd, "",
3805 AT_SYMLINK_NOFOLLOW |
3808 if (open_tree_fd < 0) {
3809 log_stderr("failure: sys_open_tree");
3813 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
3814 log_stderr("failure: sys_mount_setattr");
3818 /* A detached mount will have an anonymous mount namespace attached to
3819 * it. This means that we can't execute setid binaries on a detached
3820 * mount because the mnt_may_suid() helper will fail the check_mount()
3821 * part of its check which compares the caller's mount namespace to the
3822 * detached mount's mount namespace. Since by definition an anonymous
3823 * mount namespace is not equale to any mount namespace currently in
3824 * use this can't work. So attach the mount to the filesystem first
3825 * before performing this check.
3827 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
3828 log_stderr("failure: sys_move_mount");
3834 log_stderr("failure: fork");
3838 static char *envp[] = {
3839 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3840 "EXPECTED_EUID=5000",
3841 "EXPECTED_EGID=5000",
3844 static char *argv[] = {
3848 if (!switch_userns(attr.userns_fd, 0, 0, false))
3849 die("failure: switch_userns");
3851 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
3852 die("failure: expected_uid_gid");
3854 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3855 die("failure: sys_execveat");
3860 if (wait_for_pid(pid)) {
3861 log_stderr("failure: wait_for_pid");
3865 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3867 log_stderr("failure: openat");
3871 /* chown the file to the uid and gid we want to assume */
3872 if (fchown(file1_fd, 0, 0)) {
3873 log_stderr("failure: fchown");
3877 /* set the setid bits and grant execute permissions to the group */
3878 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
3879 log_stderr("failure: fchmod");
3883 /* Verify that the sid bits got raised. */
3884 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3885 log_stderr("failure: is_setid");
3889 safe_close(file1_fd);
3893 log_stderr("failure: fork");
3897 static char *envp[] = {
3898 "IDMAP_MOUNT_TEST_RUN_SETID=1",
3903 static char *argv[] = {
3907 if (!caps_supported()) {
3908 log_debug("skip: capability library not installed");
3912 if (!switch_userns(attr.userns_fd, 5000, 5000, true))
3913 die("failure: switch_userns");
3915 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
3916 die("failure: expected_uid_gid");
3918 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3919 die("failure: sys_execveat");
3924 if (wait_for_pid(pid)) {
3925 log_stderr("failure: wait_for_pid");
3929 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
3931 log_stderr("failure: openat");
3935 /* chown the file to the uid and gid we want to assume */
3936 if (fchown(file1_fd, 30000, 30000)) {
3937 log_stderr("failure: fchown");
3941 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
3942 log_stderr("failure: fchmod");
3946 /* Verify that the sid bits got raised. */
3947 if (!is_setid(t_dir1_fd, FILE1, 0)) {
3948 log_stderr("failure: is_setid");
3952 safe_close(file1_fd);
3954 /* Verify that we can't assume a uid and gid of a setid binary for which
3955 * we have no mapping in our user namespace.
3959 log_stderr("failure: fork");
3963 char expected_euid[100];
3964 char expected_egid[100];
3965 static char *envp[4] = {
3971 static char *argv[] = {
3975 if (!switch_userns(attr.userns_fd, 0, 0, false))
3976 die("failure: switch_userns");
3978 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
3979 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
3980 envp[1] = expected_euid;
3981 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
3982 envp[2] = expected_egid;
3984 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
3985 die("failure: expected_uid_gid");
3987 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
3988 die("failure: sys_execveat");
3993 if (wait_for_pid(pid)) {
3994 log_stderr("failure: wait_for_pid");
3999 log_debug("Ran test");
4001 safe_close(attr.userns_fd);
4002 safe_close(exec_fd);
4003 safe_close(file1_fd);
4004 safe_close(open_tree_fd);
4006 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4007 sys_umount2(t_buf, MNT_DETACH);
4008 rm_r(t_mnt_fd, DIR1);
4013 /* Validate that setid transitions are handled correctly on idmapped mounts
4014 * running in a user namespace where the uid and gid of the setid binary have no
4017 static int setid_binaries_idmapped_mounts_in_userns_separate_userns(void)
4020 int file1_fd = -EBADF, exec_fd = -EBADF, open_tree_fd = -EBADF;
4021 struct mount_attr attr = {
4022 .attr_set = MOUNT_ATTR_IDMAP,
4026 if (mkdirat(t_mnt_fd, DIR1, 0777)) {
4027 log_stderr("failure: mkdirat");
4031 /* create a file to be used as setuid binary */
4032 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC | O_RDWR, 0644);
4034 log_stderr("failure: openat");
4038 /* open our own executable */
4039 exec_fd = openat(-EBADF, "/proc/self/exe", O_RDONLY | O_CLOEXEC, 0000);
4041 log_stderr("failure: openat");
4045 /* copy our own executable into the file we created */
4046 if (fd_to_fd(exec_fd, file1_fd)) {
4047 log_stderr("failure: fd_to_fd");
4051 safe_close(exec_fd);
4053 /* change ownership of all files to uid 0 */
4054 if (chown_r(t_mnt_fd, T_DIR1, 20000, 20000)) {
4055 log_stderr("failure: chown_r");
4059 /* chown the file to the uid and gid we want to assume */
4060 if (fchown(file1_fd, 25000, 25000)) {
4061 log_stderr("failure: fchown");
4065 /* set the setid bits and grant execute permissions to the group */
4066 if (fchmod(file1_fd, S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4067 log_stderr("failure: fchmod");
4071 /* Verify that the sid bits got raised. */
4072 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4073 log_stderr("failure: is_setid");
4077 safe_close(file1_fd);
4079 /* Changing mount properties on a detached mount. */
4080 attr.userns_fd = get_userns_fd(20000, 10000, 10000);
4081 if (attr.userns_fd < 0) {
4082 log_stderr("failure: get_userns_fd");
4086 open_tree_fd = sys_open_tree(t_dir1_fd, "",
4089 AT_SYMLINK_NOFOLLOW |
4092 if (open_tree_fd < 0) {
4093 log_stderr("failure: sys_open_tree");
4097 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4098 log_stderr("failure: sys_mount_setattr");
4102 /* A detached mount will have an anonymous mount namespace attached to
4103 * it. This means that we can't execute setid binaries on a detached
4104 * mount because the mnt_may_suid() helper will fail the check_mount()
4105 * part of its check which compares the caller's mount namespace to the
4106 * detached mount's mount namespace. Since by definition an anonymous
4107 * mount namespace is not equale to any mount namespace currently in
4108 * use this can't work. So attach the mount to the filesystem first
4109 * before performing this check.
4111 if (sys_move_mount(open_tree_fd, "", t_mnt_fd, DIR1, MOVE_MOUNT_F_EMPTY_PATH)) {
4112 log_stderr("failure: sys_move_mount");
4118 log_stderr("failure: fork");
4123 static char *envp[] = {
4124 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4125 "EXPECTED_EUID=5000",
4126 "EXPECTED_EGID=5000",
4129 static char *argv[] = {
4133 userns_fd = get_userns_fd(0, 10000, 10000);
4135 die("failure: get_userns_fd");
4137 if (!switch_userns(userns_fd, 0, 0, false))
4138 die("failure: switch_userns");
4140 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 5000, 5000))
4141 die("failure: expected_uid_gid");
4143 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4144 die("failure: sys_execveat");
4149 if (wait_for_pid(pid)) {
4150 log_stderr("failure: wait_for_pid");
4154 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4156 log_stderr("failure: openat");
4160 /* chown the file to the uid and gid we want to assume */
4161 if (fchown(file1_fd, 20000, 20000)) {
4162 log_stderr("failure: fchown");
4166 /* set the setid bits and grant execute permissions to the group */
4167 if (fchmod(file1_fd, S_IXOTH | S_IXGRP | S_IEXEC | S_ISUID | S_ISGID), 0) {
4168 log_stderr("failure: fchmod");
4172 /* Verify that the sid bits got raised. */
4173 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4174 log_stderr("failure: is_setid");
4178 safe_close(file1_fd);
4182 log_stderr("failure: fork");
4187 static char *envp[] = {
4188 "IDMAP_MOUNT_TEST_RUN_SETID=1",
4193 static char *argv[] = {
4197 userns_fd = get_userns_fd(0, 10000, 10000);
4199 die("failure: get_userns_fd");
4201 if (!caps_supported()) {
4202 log_debug("skip: capability library not installed");
4206 if (!switch_userns(userns_fd, 1000, 1000, true))
4207 die("failure: switch_userns");
4209 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
4210 die("failure: expected_uid_gid");
4212 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4213 die("failure: sys_execveat");
4217 if (wait_for_pid(pid)) {
4218 log_stderr("failure: wait_for_pid");
4222 file1_fd = openat(t_dir1_fd, FILE1, O_RDWR | O_CLOEXEC, 0644);
4224 log_stderr("failure: openat");
4228 /* chown the file to the uid and gid we want to assume */
4229 if (fchown(file1_fd, 0, 0)) {
4230 log_stderr("failure: fchown");
4234 if (fchmod(file1_fd, S_IXOTH | S_IEXEC | S_ISUID | S_ISGID), 0) {
4235 log_stderr("failure: fchmod");
4239 /* Verify that the sid bits got raised. */
4240 if (!is_setid(t_dir1_fd, FILE1, 0)) {
4241 log_stderr("failure: is_setid");
4245 safe_close(file1_fd);
4247 /* Verify that we can't assume a uid and gid of a setid binary for
4248 * which we have no mapping in our user namespace.
4252 log_stderr("failure: fork");
4257 char expected_euid[100];
4258 char expected_egid[100];
4259 static char *envp[4] = {
4265 static char *argv[] = {
4269 userns_fd = get_userns_fd(0, 10000, 10000);
4271 die("failure: get_userns_fd");
4273 if (!switch_userns(userns_fd, 0, 0, false))
4274 die("failure: switch_userns");
4276 envp[0] = "IDMAP_MOUNT_TEST_RUN_SETID=0";
4277 snprintf(expected_euid, sizeof(expected_euid), "EXPECTED_EUID=%d", geteuid());
4278 envp[1] = expected_euid;
4279 snprintf(expected_egid, sizeof(expected_egid), "EXPECTED_EGID=%d", getegid());
4280 envp[2] = expected_egid;
4282 if (!expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid))
4283 die("failure: expected_uid_gid");
4285 sys_execveat(open_tree_fd, FILE1, argv, envp, 0);
4286 die("failure: sys_execveat");
4290 if (wait_for_pid(pid)) {
4291 log_stderr("failure: wait_for_pid");
4296 log_debug("Ran test");
4298 safe_close(attr.userns_fd);
4299 safe_close(exec_fd);
4300 safe_close(file1_fd);
4301 safe_close(open_tree_fd);
4303 snprintf(t_buf, sizeof(t_buf), "%s/" DIR1, t_mountpoint);
4304 sys_umount2(t_buf, MNT_DETACH);
4305 rm_r(t_mnt_fd, DIR1);
4310 static int sticky_bit_unlink(void)
4313 int dir_fd = -EBADF;
4316 if (!caps_supported())
4319 /* create directory */
4320 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4321 log_stderr("failure: mkdirat");
4325 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4327 log_stderr("failure: openat");
4331 if (fchown(dir_fd, 0, 0)) {
4332 log_stderr("failure: fchown");
4336 if (fchmod(dir_fd, 0777)) {
4337 log_stderr("failure: fchmod");
4341 /* create regular file via mknod */
4342 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4343 log_stderr("failure: mknodat");
4346 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4347 log_stderr("failure: fchownat");
4350 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4351 log_stderr("failure: fchmodat");
4355 /* create regular file via mknod */
4356 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4357 log_stderr("failure: mknodat");
4360 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4361 log_stderr("failure: fchownat");
4364 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4365 log_stderr("failure: fchmodat");
4369 /* The sticky bit is not set so we must be able to delete files not
4374 log_stderr("failure: fork");
4378 if (!switch_ids(1000, 1000))
4379 die("failure: switch_ids");
4381 if (unlinkat(dir_fd, FILE1, 0))
4382 die("failure: unlinkat");
4384 if (unlinkat(dir_fd, FILE2, 0))
4385 die("failure: unlinkat");
4389 if (wait_for_pid(pid)) {
4390 log_stderr("failure: wait_for_pid");
4394 /* set sticky bit */
4395 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4396 log_stderr("failure: fchmod");
4400 /* validate sticky bit is set */
4401 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4402 log_stderr("failure: is_sticky");
4406 /* create regular file via mknod */
4407 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4408 log_stderr("failure: mknodat");
4411 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4412 log_stderr("failure: fchownat");
4415 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4416 log_stderr("failure: fchmodat");
4420 /* create regular file via mknod */
4421 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4422 log_stderr("failure: mknodat");
4425 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4426 log_stderr("failure: fchownat");
4429 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4430 log_stderr("failure: fchmodat");
4434 /* The sticky bit is set so we must not be able to delete files not
4439 log_stderr("failure: fork");
4443 if (!switch_ids(1000, 1000))
4444 die("failure: switch_ids");
4446 if (!unlinkat(dir_fd, FILE1, 0))
4447 die("failure: unlinkat");
4449 die("failure: errno");
4451 if (!unlinkat(dir_fd, FILE2, 0))
4452 die("failure: unlinkat");
4454 die("failure: errno");
4458 if (wait_for_pid(pid)) {
4459 log_stderr("failure: wait_for_pid");
4463 /* The sticky bit is set and we own the files so we must be able to
4464 * delete the files now.
4468 log_stderr("failure: fork");
4472 /* change ownership */
4473 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
4474 die("failure: fchownat");
4475 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
4476 die("failure: expected_uid_gid");
4477 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
4478 die("failure: fchownat");
4479 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
4480 die("failure: expected_uid_gid");
4482 if (!switch_ids(1000, 1000))
4483 die("failure: switch_ids");
4485 if (unlinkat(dir_fd, FILE1, 0))
4486 die("failure: unlinkat");
4488 if (unlinkat(dir_fd, FILE2, 0))
4489 die("failure: unlinkat");
4493 if (wait_for_pid(pid)) {
4494 log_stderr("failure: wait_for_pid");
4498 /* change uid to unprivileged user */
4499 if (fchown(dir_fd, 1000, -1)) {
4500 log_stderr("failure: fchown");
4503 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4504 log_stderr("failure: fchmod");
4507 /* validate sticky bit is set */
4508 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4509 log_stderr("failure: is_sticky");
4513 /* create regular file via mknod */
4514 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4515 log_stderr("failure: mknodat");
4518 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4519 log_stderr("failure: fchownat");
4522 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4523 log_stderr("failure: fchmodat");
4527 /* create regular file via mknod */
4528 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4529 log_stderr("failure: mknodat");
4532 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4533 log_stderr("failure: fchownat");
4536 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4537 log_stderr("failure: fchmodat");
4541 /* The sticky bit is set and we own the directory so we must be able to
4542 * delete the files now.
4546 log_stderr("failure: fork");
4550 if (!switch_ids(1000, 1000))
4551 die("failure: switch_ids");
4553 if (unlinkat(dir_fd, FILE1, 0))
4554 die("failure: unlinkat");
4556 if (unlinkat(dir_fd, FILE2, 0))
4557 die("failure: unlinkat");
4561 if (wait_for_pid(pid)) {
4562 log_stderr("failure: wait_for_pid");
4567 log_debug("Ran test");
4574 static int sticky_bit_unlink_idmapped_mounts(void)
4577 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4578 struct mount_attr attr = {
4579 .attr_set = MOUNT_ATTR_IDMAP,
4583 if (!caps_supported())
4586 /* create directory */
4587 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4588 log_stderr("failure: mkdirat");
4592 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4594 log_stderr("failure: openat");
4597 if (fchown(dir_fd, 10000, 10000)) {
4598 log_stderr("failure: fchown");
4601 if (fchmod(dir_fd, 0777)) {
4602 log_stderr("failure: fchmod");
4606 /* create regular file via mknod */
4607 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4608 log_stderr("failure: mknodat");
4611 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4612 log_stderr("failure: fchownat");
4615 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4616 log_stderr("failure: fchmodat");
4620 /* create regular file via mknod */
4621 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4622 log_stderr("failure: mknodat");
4625 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4626 log_stderr("failure: fchownat");
4629 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4630 log_stderr("failure: fchmodat");
4634 /* Changing mount properties on a detached mount. */
4635 attr.userns_fd = get_userns_fd(10000, 0, 10000);
4636 if (attr.userns_fd < 0) {
4637 log_stderr("failure: get_userns_fd");
4641 open_tree_fd = sys_open_tree(dir_fd, "",
4644 AT_SYMLINK_NOFOLLOW |
4647 if (open_tree_fd < 0) {
4648 log_stderr("failure: sys_open_tree");
4652 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4653 log_stderr("failure: sys_mount_setattr");
4657 /* The sticky bit is not set so we must be able to delete files not
4662 log_stderr("failure: fork");
4666 if (!switch_ids(1000, 1000))
4667 die("failure: switch_ids");
4669 if (unlinkat(open_tree_fd, FILE1, 0))
4670 die("failure: unlinkat");
4672 if (unlinkat(open_tree_fd, FILE2, 0))
4673 die("failure: unlinkat");
4677 if (wait_for_pid(pid)) {
4678 log_stderr("failure: wait_for_pid");
4682 /* set sticky bit */
4683 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4684 log_stderr("failure: fchmod");
4688 /* validate sticky bit is set */
4689 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4690 log_stderr("failure: is_sticky");
4694 /* create regular file via mknod */
4695 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4696 log_stderr("failure: mknodat");
4699 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4700 log_stderr("failure: fchownat");
4703 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4704 log_stderr("failure: fchmodat");
4708 /* create regular file via mknod */
4709 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4710 log_stderr("failure: mknodat");
4713 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4714 log_stderr("failure: fchownat");
4717 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4718 log_stderr("failure: fchmodat");
4722 /* The sticky bit is set so we must not be able to delete files not
4727 log_stderr("failure: fork");
4731 if (!switch_ids(1000, 1000))
4732 die("failure: switch_ids");
4734 if (!unlinkat(open_tree_fd, FILE1, 0))
4735 die("failure: unlinkat");
4737 die("failure: errno");
4739 if (!unlinkat(open_tree_fd, FILE2, 0))
4740 die("failure: unlinkat");
4742 die("failure: errno");
4746 if (wait_for_pid(pid)) {
4747 log_stderr("failure: wait_for_pid");
4751 /* The sticky bit is set and we own the files so we must be able to
4752 * delete the files now.
4756 log_stderr("failure: fork");
4760 /* change ownership */
4761 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
4762 die("failure: fchownat");
4763 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
4764 die("failure: expected_uid_gid");
4765 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
4766 die("failure: fchownat");
4767 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
4768 die("failure: expected_uid_gid");
4770 if (!switch_ids(1000, 1000))
4771 die("failure: switch_ids");
4773 if (unlinkat(open_tree_fd, FILE1, 0))
4774 die("failure: unlinkat");
4776 if (unlinkat(open_tree_fd, FILE2, 0))
4777 die("failure: unlinkat");
4781 if (wait_for_pid(pid)) {
4782 log_stderr("failure: wait_for_pid");
4786 /* change uid to unprivileged user */
4787 if (fchown(dir_fd, 11000, -1)) {
4788 log_stderr("failure: fchown");
4791 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4792 log_stderr("failure: fchmod");
4795 /* validate sticky bit is set */
4796 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4797 log_stderr("failure: is_sticky");
4801 /* create regular file via mknod */
4802 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4803 log_stderr("failure: mknodat");
4806 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
4807 log_stderr("failure: fchownat");
4810 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4811 log_stderr("failure: fchmodat");
4815 /* create regular file via mknod */
4816 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4817 log_stderr("failure: mknodat");
4820 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
4821 log_stderr("failure: fchownat");
4824 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4825 log_stderr("failure: fchmodat");
4829 /* The sticky bit is set and we own the directory so we must be able to
4830 * delete the files now.
4834 log_stderr("failure: fork");
4838 if (!switch_ids(1000, 1000))
4839 die("failure: switch_ids");
4841 if (unlinkat(open_tree_fd, FILE1, 0))
4842 die("failure: unlinkat");
4844 if (unlinkat(open_tree_fd, FILE2, 0))
4845 die("failure: unlinkat");
4849 if (wait_for_pid(pid)) {
4850 log_stderr("failure: wait_for_pid");
4855 log_debug("Ran test");
4857 safe_close(attr.userns_fd);
4859 safe_close(open_tree_fd);
4864 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
4865 * operations in a user namespace.
4867 static int sticky_bit_unlink_idmapped_mounts_in_userns(void)
4870 int dir_fd = -EBADF, open_tree_fd = -EBADF;
4871 struct mount_attr attr = {
4872 .attr_set = MOUNT_ATTR_IDMAP,
4876 if (!caps_supported())
4879 /* create directory */
4880 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
4881 log_stderr("failure: mkdirat");
4885 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
4887 log_stderr("failure: openat");
4890 if (fchown(dir_fd, 0, 0)) {
4891 log_stderr("failure: fchown");
4894 if (fchmod(dir_fd, 0777)) {
4895 log_stderr("failure: fchmod");
4899 /* create regular file via mknod */
4900 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4901 log_stderr("failure: mknodat");
4904 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4905 log_stderr("failure: fchownat");
4908 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
4909 log_stderr("failure: fchmodat");
4913 /* create regular file via mknod */
4914 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
4915 log_stderr("failure: mknodat");
4918 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
4919 log_stderr("failure: fchownat");
4922 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
4923 log_stderr("failure: fchmodat");
4927 /* Changing mount properties on a detached mount. */
4928 attr.userns_fd = get_userns_fd(0, 10000, 10000);
4929 if (attr.userns_fd < 0) {
4930 log_stderr("failure: get_userns_fd");
4934 open_tree_fd = sys_open_tree(dir_fd, "",
4937 AT_SYMLINK_NOFOLLOW |
4940 if (open_tree_fd < 0) {
4941 log_stderr("failure: sys_open_tree");
4945 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
4946 log_stderr("failure: sys_mount_setattr");
4950 /* The sticky bit is not set so we must be able to delete files not
4955 log_stderr("failure: fork");
4959 if (!caps_supported()) {
4960 log_debug("skip: capability library not installed");
4964 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
4965 die("failure: switch_userns");
4967 if (unlinkat(dir_fd, FILE1, 0))
4968 die("failure: unlinkat");
4970 if (unlinkat(dir_fd, FILE2, 0))
4971 die("failure: unlinkat");
4975 if (wait_for_pid(pid)) {
4976 log_stderr("failure: wait_for_pid");
4980 /* set sticky bit */
4981 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
4982 log_stderr("failure: fchmod");
4986 /* validate sticky bit is set */
4987 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
4988 log_stderr("failure: is_sticky");
4992 /* create regular file via mknod */
4993 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
4994 log_stderr("failure: mknodat");
4997 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
4998 log_stderr("failure: fchownat");
5001 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5002 log_stderr("failure: fchmodat");
5006 /* create regular file via mknod */
5007 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5008 log_stderr("failure: mknodat");
5011 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5012 log_stderr("failure: fchownat");
5015 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5016 log_stderr("failure: fchmodat");
5020 /* The sticky bit is set so we must not be able to delete files not
5025 log_stderr("failure: fork");
5029 if (!caps_supported()) {
5030 log_debug("skip: capability library not installed");
5034 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5035 die("failure: switch_userns");
5037 if (!unlinkat(dir_fd, FILE1, 0))
5038 die("failure: unlinkat");
5040 die("failure: errno");
5042 if (!unlinkat(dir_fd, FILE2, 0))
5043 die("failure: unlinkat");
5045 die("failure: errno");
5047 if (!unlinkat(open_tree_fd, FILE1, 0))
5048 die("failure: unlinkat");
5050 die("failure: errno");
5052 if (!unlinkat(open_tree_fd, FILE2, 0))
5053 die("failure: unlinkat");
5055 die("failure: errno");
5059 if (wait_for_pid(pid)) {
5060 log_stderr("failure: wait_for_pid");
5064 /* The sticky bit is set and we own the files so we must be able to
5065 * delete the files now.
5069 log_stderr("failure: fork");
5073 /* change ownership */
5074 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5075 die("failure: fchownat");
5076 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5077 die("failure: expected_uid_gid");
5078 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5079 die("failure: fchownat");
5080 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5081 die("failure: expected_uid_gid");
5083 if (!caps_supported()) {
5084 log_debug("skip: capability library not installed");
5088 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5089 die("failure: switch_userns");
5091 if (!unlinkat(dir_fd, FILE1, 0))
5092 die("failure: unlinkat");
5094 die("failure: errno");
5096 if (!unlinkat(dir_fd, FILE2, 0))
5097 die("failure: unlinkat");
5099 die("failure: errno");
5101 if (unlinkat(open_tree_fd, FILE1, 0))
5102 die("failure: unlinkat");
5104 if (unlinkat(open_tree_fd, FILE2, 0))
5105 die("failure: unlinkat");
5109 if (wait_for_pid(pid)) {
5110 log_stderr("failure: wait_for_pid");
5114 /* change uid to unprivileged user */
5115 if (fchown(dir_fd, 1000, -1)) {
5116 log_stderr("failure: fchown");
5119 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5120 log_stderr("failure: fchmod");
5123 /* validate sticky bit is set */
5124 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5125 log_stderr("failure: is_sticky");
5129 /* create regular file via mknod */
5130 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5131 log_stderr("failure: mknodat");
5134 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5135 log_stderr("failure: fchownat");
5138 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5139 log_stderr("failure: fchmodat");
5143 /* create regular file via mknod */
5144 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5145 log_stderr("failure: mknodat");
5148 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5149 log_stderr("failure: fchownat");
5152 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5153 log_stderr("failure: fchmodat");
5157 /* The sticky bit is set and we own the directory so we must be able to
5158 * delete the files now.
5162 log_stderr("failure: fork");
5166 if (!caps_supported()) {
5167 log_debug("skip: capability library not installed");
5171 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5172 die("failure: switch_userns");
5174 /* we don't own the directory from the original mount */
5175 if (!unlinkat(dir_fd, FILE1, 0))
5176 die("failure: unlinkat");
5178 die("failure: errno");
5180 if (!unlinkat(dir_fd, FILE2, 0))
5181 die("failure: unlinkat");
5183 die("failure: errno");
5185 /* we own the file from the idmapped mount */
5186 if (unlinkat(open_tree_fd, FILE1, 0))
5187 die("failure: unlinkat");
5188 if (unlinkat(open_tree_fd, FILE2, 0))
5189 die("failure: unlinkat");
5193 if (wait_for_pid(pid)) {
5194 log_stderr("failure: wait_for_pid");
5199 log_debug("Ran test");
5201 safe_close(attr.userns_fd);
5203 safe_close(open_tree_fd);
5208 static int sticky_bit_rename(void)
5211 int dir_fd = -EBADF;
5214 if (!caps_supported())
5217 /* create directory */
5218 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5219 log_stderr("failure: mkdirat");
5223 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5225 log_stderr("failure: openat");
5228 if (fchown(dir_fd, 0, 0)) {
5229 log_stderr("failure: fchown");
5232 if (fchmod(dir_fd, 0777)) {
5233 log_stderr("failure: fchmod");
5237 /* create regular file via mknod */
5238 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5239 log_stderr("failure: mknodat");
5242 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5243 log_stderr("failure: fchownat");
5246 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5247 log_stderr("failure: fchmodat");
5251 /* create regular file via mknod */
5252 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5253 log_stderr("failure: mknodat");
5256 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5257 log_stderr("failure: fchownat");
5260 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5261 log_stderr("failure: fchmodat");
5265 /* The sticky bit is not set so we must be able to delete files not
5270 log_stderr("failure: fork");
5274 if (!switch_ids(1000, 1000))
5275 die("failure: switch_ids");
5277 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5278 die("failure: renameat");
5280 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5281 die("failure: renameat");
5283 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5284 die("failure: renameat");
5286 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5287 die("failure: renameat");
5291 if (wait_for_pid(pid)) {
5292 log_stderr("failure: wait_for_pid");
5296 /* set sticky bit */
5297 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5298 log_stderr("failure: fchmod");
5302 /* validate sticky bit is set */
5303 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5304 log_stderr("failure: is_sticky");
5308 /* The sticky bit is set so we must not be able to delete files not
5313 log_stderr("failure: fork");
5317 if (!switch_ids(1000, 1000))
5318 die("failure: switch_ids");
5320 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5321 die("failure: renameat");
5323 die("failure: errno");
5325 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5326 die("failure: renameat");
5328 die("failure: errno");
5332 if (wait_for_pid(pid)) {
5333 log_stderr("failure: wait_for_pid");
5337 /* The sticky bit is set and we own the files so we must be able to
5338 * delete the files now.
5342 log_stderr("failure: fork");
5346 /* change ownership */
5347 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5348 die("failure: fchownat");
5349 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5350 die("failure: expected_uid_gid");
5351 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5352 die("failure: fchownat");
5353 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5354 die("failure: expected_uid_gid");
5356 if (!switch_ids(1000, 1000))
5357 die("failure: switch_ids");
5359 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5360 die("failure: renameat");
5362 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5363 die("failure: renameat");
5365 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5366 die("failure: renameat");
5368 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5369 die("failure: renameat");
5373 if (wait_for_pid(pid)) {
5374 log_stderr("failure: wait_for_pid");
5378 /* change uid to unprivileged user */
5379 if (fchown(dir_fd, 1000, -1)) {
5380 log_stderr("failure: fchown");
5383 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5384 log_stderr("failure: fchmod");
5387 /* validate sticky bit is set */
5388 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5389 log_stderr("failure: is_sticky");
5394 /* The sticky bit is set and we own the directory so we must be able to
5395 * delete the files now.
5399 log_stderr("failure: fork");
5403 if (!switch_ids(1000, 1000))
5404 die("failure: switch_ids");
5406 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5407 die("failure: renameat");
5409 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5410 die("failure: renameat");
5412 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5413 die("failure: renameat");
5415 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5416 die("failure: renameat");
5420 if (wait_for_pid(pid)) {
5421 log_stderr("failure: wait_for_pid");
5426 log_debug("Ran test");
5433 static int sticky_bit_rename_idmapped_mounts(void)
5436 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5437 struct mount_attr attr = {
5438 .attr_set = MOUNT_ATTR_IDMAP,
5442 if (!caps_supported())
5445 /* create directory */
5446 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5447 log_stderr("failure: mkdirat");
5451 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5453 log_stderr("failure: openat");
5457 if (fchown(dir_fd, 10000, 10000)) {
5458 log_stderr("failure: fchown");
5462 if (fchmod(dir_fd, 0777)) {
5463 log_stderr("failure: fchmod");
5467 /* create regular file via mknod */
5468 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5469 log_stderr("failure: mknodat");
5472 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
5473 log_stderr("failure: fchownat");
5476 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5477 log_stderr("failure: fchmodat");
5481 /* create regular file via mknod */
5482 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5483 log_stderr("failure: mknodat");
5486 if (fchownat(dir_fd, FILE2, 12000, 12000, 0)) {
5487 log_stderr("failure: fchownat");
5490 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5491 log_stderr("failure: fchmodat");
5495 /* Changing mount properties on a detached mount. */
5496 attr.userns_fd = get_userns_fd(10000, 0, 10000);
5497 if (attr.userns_fd < 0) {
5498 log_stderr("failure: get_userns_fd");
5502 open_tree_fd = sys_open_tree(dir_fd, "",
5505 AT_SYMLINK_NOFOLLOW |
5508 if (open_tree_fd < 0) {
5509 log_stderr("failure: sys_open_tree");
5513 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5514 log_stderr("failure: sys_mount_setattr");
5518 /* The sticky bit is not set so we must be able to delete files not
5523 log_stderr("failure: fork");
5527 if (!switch_ids(1000, 1000))
5528 die("failure: switch_ids");
5530 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5531 die("failure: renameat");
5533 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5534 die("failure: renameat");
5536 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5537 die("failure: renameat");
5539 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5540 die("failure: renameat");
5544 if (wait_for_pid(pid)) {
5545 log_stderr("failure: wait_for_pid");
5549 /* set sticky bit */
5550 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5551 log_stderr("failure: fchmod");
5555 /* validate sticky bit is set */
5556 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5557 log_stderr("failure: is_sticky");
5561 /* The sticky bit is set so we must not be able to delete files not
5566 log_stderr("failure: fork");
5570 if (!switch_ids(1000, 1000))
5571 die("failure: switch_ids");
5573 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5574 die("failure: renameat");
5576 die("failure: errno");
5578 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5579 die("failure: renameat");
5581 die("failure: errno");
5585 if (wait_for_pid(pid)) {
5586 log_stderr("failure: wait_for_pid");
5590 /* The sticky bit is set and we own the files so we must be able to
5591 * delete the files now.
5595 log_stderr("failure: fork");
5599 /* change ownership */
5600 if (fchownat(dir_fd, FILE1, 11000, -1, 0))
5601 die("failure: fchownat");
5602 if (!expected_uid_gid(dir_fd, FILE1, 0, 11000, 10000))
5603 die("failure: expected_uid_gid");
5604 if (fchownat(dir_fd, FILE2, 11000, -1, 0))
5605 die("failure: fchownat");
5606 if (!expected_uid_gid(dir_fd, FILE2, 0, 11000, 12000))
5607 die("failure: expected_uid_gid");
5609 if (!switch_ids(1000, 1000))
5610 die("failure: switch_ids");
5612 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5613 die("failure: renameat");
5615 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5616 die("failure: renameat");
5618 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5619 die("failure: renameat");
5621 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5622 die("failure: renameat");
5626 if (wait_for_pid(pid)) {
5627 log_stderr("failure: wait_for_pid");
5631 /* change uid to unprivileged user */
5632 if (fchown(dir_fd, 11000, -1)) {
5633 log_stderr("failure: fchown");
5636 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5637 log_stderr("failure: fchmod");
5640 /* validate sticky bit is set */
5641 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5642 log_stderr("failure: is_sticky");
5646 /* The sticky bit is set and we own the directory so we must be able to
5647 * delete the files now.
5651 log_stderr("failure: fork");
5655 if (!switch_ids(1000, 1000))
5656 die("failure: switch_ids");
5658 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5659 die("failure: renameat");
5661 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5662 die("failure: renameat");
5664 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5665 die("failure: renameat");
5667 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5668 die("failure: renameat");
5672 if (wait_for_pid(pid)) {
5673 log_stderr("failure: wait_for_pid");
5678 log_debug("Ran test");
5680 safe_close(attr.userns_fd);
5682 safe_close(open_tree_fd);
5687 /* Validate that the sticky bit behaves correctly on idmapped mounts for unlink
5688 * operations in a user namespace.
5690 static int sticky_bit_rename_idmapped_mounts_in_userns(void)
5693 int dir_fd = -EBADF, open_tree_fd = -EBADF;
5694 struct mount_attr attr = {
5695 .attr_set = MOUNT_ATTR_IDMAP,
5699 if (!caps_supported())
5702 /* create directory */
5703 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
5704 log_stderr("failure: mkdirat");
5708 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
5710 log_stderr("failure: openat");
5713 if (fchown(dir_fd, 0, 0)) {
5714 log_stderr("failure: fchown");
5717 if (fchmod(dir_fd, 0777)) {
5718 log_stderr("failure: fchmod");
5722 /* create regular file via mknod */
5723 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
5724 log_stderr("failure: mknodat");
5727 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
5728 log_stderr("failure: fchownat");
5731 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
5732 log_stderr("failure: fchmodat");
5736 /* create regular file via mknod */
5737 if (mknodat(dir_fd, FILE2, S_IFREG | 0000, 0)) {
5738 log_stderr("failure: mknodat");
5741 if (fchownat(dir_fd, FILE2, 2000, 2000, 0)) {
5742 log_stderr("failure: fchownat");
5745 if (fchmodat(dir_fd, FILE2, 0644, 0)) {
5746 log_stderr("failure: fchmodat");
5750 /* Changing mount properties on a detached mount. */
5751 attr.userns_fd = get_userns_fd(0, 10000, 10000);
5752 if (attr.userns_fd < 0) {
5753 log_stderr("failure: get_userns_fd");
5757 open_tree_fd = sys_open_tree(dir_fd, "",
5760 AT_SYMLINK_NOFOLLOW |
5763 if (open_tree_fd < 0) {
5764 log_stderr("failure: sys_open_tree");
5768 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
5769 log_stderr("failure: sys_mount_setattr");
5773 /* The sticky bit is not set so we must be able to delete files not
5778 log_stderr("failure: fork");
5782 if (!caps_supported()) {
5783 log_debug("skip: capability library not installed");
5787 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5788 die("failure: switch_userns");
5790 if (renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5791 die("failure: renameat");
5793 if (renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5794 die("failure: renameat");
5796 if (renameat(dir_fd, FILE1_RENAME, dir_fd, FILE1))
5797 die("failure: renameat");
5799 if (renameat(dir_fd, FILE2_RENAME, dir_fd, FILE2))
5800 die("failure: renameat");
5804 if (wait_for_pid(pid)) {
5805 log_stderr("failure: wait_for_pid");
5809 /* set sticky bit */
5810 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5811 log_stderr("failure: fchmod");
5815 /* validate sticky bit is set */
5816 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5817 log_stderr("failure: is_sticky");
5821 /* The sticky bit is set so we must not be able to delete files not
5826 log_stderr("failure: fork");
5830 if (!caps_supported()) {
5831 log_debug("skip: capability library not installed");
5835 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5836 die("failure: switch_userns");
5838 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5839 die("failure: renameat");
5841 die("failure: errno");
5843 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5844 die("failure: renameat");
5846 die("failure: errno");
5848 if (!renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5849 die("failure: renameat");
5851 die("failure: errno");
5853 if (!renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5854 die("failure: renameat");
5856 die("failure: errno");
5860 if (wait_for_pid(pid)) {
5861 log_stderr("failure: wait_for_pid");
5865 /* The sticky bit is set and we own the files so we must be able to
5866 * delete the files now.
5870 log_stderr("failure: fork");
5874 /* change ownership */
5875 if (fchownat(dir_fd, FILE1, 1000, -1, 0))
5876 die("failure: fchownat");
5877 if (!expected_uid_gid(dir_fd, FILE1, 0, 1000, 0))
5878 die("failure: expected_uid_gid");
5879 if (fchownat(dir_fd, FILE2, 1000, -1, 0))
5880 die("failure: fchownat");
5881 if (!expected_uid_gid(dir_fd, FILE2, 0, 1000, 2000))
5882 die("failure: expected_uid_gid");
5884 if (!caps_supported()) {
5885 log_debug("skip: capability library not installed");
5889 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5890 die("failure: switch_userns");
5892 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5893 die("failure: renameat");
5895 die("failure: errno");
5897 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5898 die("failure: renameat");
5900 die("failure: errno");
5902 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5903 die("failure: renameat");
5905 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5906 die("failure: renameat");
5908 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5909 die("failure: renameat");
5911 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5912 die("failure: renameat");
5916 if (wait_for_pid(pid)) {
5917 log_stderr("failure: wait_for_pid");
5921 /* change uid to unprivileged user */
5922 if (fchown(dir_fd, 1000, -1)) {
5923 log_stderr("failure: fchown");
5926 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
5927 log_stderr("failure: fchmod");
5930 /* validate sticky bit is set */
5931 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
5932 log_stderr("failure: is_sticky");
5936 /* The sticky bit is set and we own the directory so we must be able to
5937 * delete the files now.
5941 log_stderr("failure: fork");
5945 if (!caps_supported()) {
5946 log_debug("skip: capability library not installed");
5950 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
5951 die("failure: switch_userns");
5953 /* we don't own the directory from the original mount */
5954 if (!renameat(dir_fd, FILE1, dir_fd, FILE1_RENAME))
5955 die("failure: renameat");
5957 die("failure: errno");
5959 if (!renameat(dir_fd, FILE2, dir_fd, FILE2_RENAME))
5960 die("failure: renameat");
5962 die("failure: errno");
5964 /* we own the file from the idmapped mount */
5965 if (renameat(open_tree_fd, FILE1, open_tree_fd, FILE1_RENAME))
5966 die("failure: renameat");
5968 if (renameat(open_tree_fd, FILE2, open_tree_fd, FILE2_RENAME))
5969 die("failure: renameat");
5971 if (renameat(open_tree_fd, FILE1_RENAME, open_tree_fd, FILE1))
5972 die("failure: renameat");
5974 if (renameat(open_tree_fd, FILE2_RENAME, open_tree_fd, FILE2))
5975 die("failure: renameat");
5979 if (wait_for_pid(pid)) {
5980 log_stderr("failure: wait_for_pid");
5985 log_debug("Ran test");
5987 safe_close(open_tree_fd);
5988 safe_close(attr.userns_fd);
5994 /* Validate that protected symlinks work correctly. */
5995 static int protected_symlinks(void)
5998 int dir_fd = -EBADF, fd = -EBADF;
6001 if (!protected_symlinks_enabled())
6004 if (!caps_supported())
6007 /* create directory */
6008 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6009 log_stderr("failure: mkdirat");
6013 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6015 log_stderr("failure: openat");
6018 if (fchown(dir_fd, 0, 0)) {
6019 log_stderr("failure: fchown");
6022 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6023 log_stderr("failure: fchmod");
6026 /* validate sticky bit is set */
6027 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6028 log_stderr("failure: is_sticky");
6032 /* create regular file via mknod */
6033 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6034 log_stderr("failure: mknodat");
6037 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6038 log_stderr("failure: fchownat");
6041 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6042 log_stderr("failure: fchmodat");
6046 /* create symlinks */
6047 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6048 log_stderr("failure: symlinkat");
6051 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6052 log_stderr("failure: fchownat");
6055 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6056 log_stderr("failure: expected_uid_gid");
6059 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6060 log_stderr("failure: expected_uid_gid");
6064 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6065 log_stderr("failure: symlinkat");
6068 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6069 log_stderr("failure: fchownat");
6072 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6073 log_stderr("failure: expected_uid_gid");
6076 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6077 log_stderr("failure: expected_uid_gid");
6081 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6082 log_stderr("failure: symlinkat");
6085 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6086 log_stderr("failure: fchownat");
6089 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6090 log_stderr("failure: expected_uid_gid");
6093 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6094 log_stderr("failure: expected_uid_gid");
6098 /* validate file can be directly read */
6099 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6101 log_stderr("failure: openat");
6106 /* validate file can be read through own symlink */
6107 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6109 log_stderr("failure: openat");
6116 log_stderr("failure: fork");
6120 if (!switch_ids(1000, 1000))
6121 die("failure: switch_ids");
6123 /* validate file can be directly read */
6124 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6126 die("failure: openat");
6129 /* validate file can be read through own symlink */
6130 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6132 die("failure: openat");
6135 /* validate file can be read through root symlink */
6136 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6138 die("failure: openat");
6141 /* validate file can't be read through other users symlink */
6142 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6144 die("failure: openat");
6145 if (errno != EACCES)
6146 die("failure: errno");
6150 if (wait_for_pid(pid)) {
6151 log_stderr("failure: wait_for_pid");
6157 log_stderr("failure: fork");
6161 if (!switch_ids(2000, 2000))
6162 die("failure: switch_ids");
6164 /* validate file can be directly read */
6165 fd = openat(dir_fd, FILE1, O_RDONLY | O_CLOEXEC, 0);
6167 die("failure: openat");
6170 /* validate file can be read through own symlink */
6171 fd = openat(dir_fd, SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6173 die("failure: openat");
6176 /* validate file can be read through root symlink */
6177 fd = openat(dir_fd, SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6179 die("failure: openat");
6182 /* validate file can't be read through other users symlink */
6183 fd = openat(dir_fd, SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6185 die("failure: openat");
6186 if (errno != EACCES)
6187 die("failure: errno");
6191 if (wait_for_pid(pid)) {
6192 log_stderr("failure: wait_for_pid");
6197 log_debug("Ran test");
6205 /* Validate that protected symlinks work correctly on idmapped mounts. */
6206 static int protected_symlinks_idmapped_mounts(void)
6209 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6210 struct mount_attr attr = {
6211 .attr_set = MOUNT_ATTR_IDMAP,
6215 if (!protected_symlinks_enabled())
6218 if (!caps_supported())
6221 /* create directory */
6222 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6223 log_stderr("failure: mkdirat");
6227 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6229 log_stderr("failure: openat");
6232 if (fchown(dir_fd, 10000, 10000)) {
6233 log_stderr("failure: fchown");
6236 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6237 log_stderr("failure: fchmod");
6240 /* validate sticky bit is set */
6241 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6242 log_stderr("failure: is_sticky");
6246 /* create regular file via mknod */
6247 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6248 log_stderr("failure: mknodat");
6251 if (fchownat(dir_fd, FILE1, 10000, 10000, 0)) {
6252 log_stderr("failure: fchownat");
6255 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6256 log_stderr("failure: fchmodat");
6260 /* create symlinks */
6261 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6262 log_stderr("failure: symlinkat");
6265 if (fchownat(dir_fd, SYMLINK_USER1, 10000, 10000, AT_SYMLINK_NOFOLLOW)) {
6266 log_stderr("failure: fchownat");
6269 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 10000, 10000)) {
6270 log_stderr("failure: expected_uid_gid");
6273 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6274 log_stderr("failure: expected_uid_gid");
6278 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6279 log_stderr("failure: symlinkat");
6282 if (fchownat(dir_fd, SYMLINK_USER2, 11000, 11000, AT_SYMLINK_NOFOLLOW)) {
6283 log_stderr("failure: fchownat");
6286 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 11000, 11000)) {
6287 log_stderr("failure: expected_uid_gid");
6290 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6291 log_stderr("failure: expected_uid_gid");
6295 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6296 log_stderr("failure: symlinkat");
6299 if (fchownat(dir_fd, SYMLINK_USER3, 12000, 12000, AT_SYMLINK_NOFOLLOW)) {
6300 log_stderr("failure: fchownat");
6303 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 12000, 12000)) {
6304 log_stderr("failure: expected_uid_gid");
6307 if (!expected_uid_gid(dir_fd, FILE1, 0, 10000, 10000)) {
6308 log_stderr("failure: expected_uid_gid");
6312 /* Changing mount properties on a detached mount. */
6313 attr.userns_fd = get_userns_fd(10000, 0, 10000);
6314 if (attr.userns_fd < 0) {
6315 log_stderr("failure: get_userns_fd");
6319 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6322 AT_SYMLINK_NOFOLLOW |
6325 if (open_tree_fd < 0) {
6326 log_stderr("failure: open_tree_fd");
6330 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6331 log_stderr("failure: sys_mount_setattr");
6335 /* validate file can be directly read */
6336 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6338 log_stderr("failure: openat");
6343 /* validate file can be read through own symlink */
6344 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6346 log_stderr("failure: openat");
6353 log_stderr("failure: fork");
6357 if (!switch_ids(1000, 1000))
6358 die("failure: switch_ids");
6360 /* validate file can be directly read */
6361 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6363 die("failure: openat");
6366 /* validate file can be read through own symlink */
6367 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6369 die("failure: openat");
6372 /* validate file can be read through root symlink */
6373 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6375 die("failure: openat");
6378 /* validate file can't be read through other users symlink */
6379 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6381 die("failure: openat");
6382 if (errno != EACCES)
6383 die("failure: errno");
6387 if (wait_for_pid(pid)) {
6388 log_stderr("failure: wait_for_pid");
6394 log_stderr("failure: fork");
6398 if (!switch_ids(2000, 2000))
6399 die("failure: switch_ids");
6401 /* validate file can be directly read */
6402 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6404 die("failure: openat");
6407 /* validate file can be read through own symlink */
6408 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6410 die("failure: openat");
6413 /* validate file can be read through root symlink */
6414 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6416 die("failure: openat");
6419 /* validate file can't be read through other users symlink */
6420 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6422 die("failure: openat");
6423 if (errno != EACCES)
6424 die("failure: errno");
6428 if (wait_for_pid(pid)) {
6429 log_stderr("failure: wait_for_pid");
6434 log_debug("Ran test");
6436 safe_close(attr.userns_fd);
6439 safe_close(open_tree_fd);
6444 /* Validate that protected symlinks work correctly on idmapped mounts inside a
6447 static int protected_symlinks_idmapped_mounts_in_userns(void)
6450 int dir_fd = -EBADF, fd = -EBADF, open_tree_fd = -EBADF;
6451 struct mount_attr attr = {
6452 .attr_set = MOUNT_ATTR_IDMAP,
6456 if (!protected_symlinks_enabled())
6459 if (!caps_supported())
6462 /* create directory */
6463 if (mkdirat(t_dir1_fd, DIR1, 0000)) {
6464 log_stderr("failure: mkdirat");
6468 dir_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6470 log_stderr("failure: openat");
6473 if (fchown(dir_fd, 0, 0)) {
6474 log_stderr("failure: fchown");
6477 if (fchmod(dir_fd, 0777 | S_ISVTX)) {
6478 log_stderr("failure: fchmod");
6481 /* validate sticky bit is set */
6482 if (!is_sticky(t_dir1_fd, DIR1, 0)) {
6483 log_stderr("failure: is_sticky");
6487 /* create regular file via mknod */
6488 if (mknodat(dir_fd, FILE1, S_IFREG | 0000, 0)) {
6489 log_stderr("failure: mknodat");
6492 if (fchownat(dir_fd, FILE1, 0, 0, 0)) {
6493 log_stderr("failure: fchownat");
6496 if (fchmodat(dir_fd, FILE1, 0644, 0)) {
6497 log_stderr("failure: fchmodat");
6501 /* create symlinks */
6502 if (symlinkat(FILE1, dir_fd, SYMLINK_USER1)) {
6503 log_stderr("failure: symlinkat");
6506 if (fchownat(dir_fd, SYMLINK_USER1, 0, 0, AT_SYMLINK_NOFOLLOW)) {
6507 log_stderr("failure: fchownat");
6510 if (!expected_uid_gid(dir_fd, SYMLINK_USER1, AT_SYMLINK_NOFOLLOW, 0, 0)) {
6511 log_stderr("failure: expected_uid_gid");
6514 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6515 log_stderr("failure: expected_uid_gid");
6519 if (symlinkat(FILE1, dir_fd, SYMLINK_USER2)) {
6520 log_stderr("failure: symlinkat");
6523 if (fchownat(dir_fd, SYMLINK_USER2, 1000, 1000, AT_SYMLINK_NOFOLLOW)) {
6524 log_stderr("failure: fchownat");
6527 if (!expected_uid_gid(dir_fd, SYMLINK_USER2, AT_SYMLINK_NOFOLLOW, 1000, 1000)) {
6528 log_stderr("failure: expected_uid_gid");
6531 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6532 log_stderr("failure: expected_uid_gid");
6536 if (symlinkat(FILE1, dir_fd, SYMLINK_USER3)) {
6537 log_stderr("failure: symlinkat");
6540 if (fchownat(dir_fd, SYMLINK_USER3, 2000, 2000, AT_SYMLINK_NOFOLLOW)) {
6541 log_stderr("failure: fchownat");
6544 if (!expected_uid_gid(dir_fd, SYMLINK_USER3, AT_SYMLINK_NOFOLLOW, 2000, 2000)) {
6545 log_stderr("failure: expected_uid_gid");
6548 if (!expected_uid_gid(dir_fd, FILE1, 0, 0, 0)) {
6549 log_stderr("failure: expected_uid_gid");
6553 /* Changing mount properties on a detached mount. */
6554 attr.userns_fd = get_userns_fd(0, 10000, 10000);
6555 if (attr.userns_fd < 0) {
6556 log_stderr("failure: get_userns_fd");
6560 open_tree_fd = sys_open_tree(t_dir1_fd, "",
6563 AT_SYMLINK_NOFOLLOW |
6566 if (open_tree_fd < 0) {
6567 log_stderr("failure: sys_open_tree");
6571 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6572 log_stderr("failure: sys_mount_setattr");
6576 /* validate file can be directly read */
6577 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6579 log_stderr("failure: openat");
6584 /* validate file can be read through own symlink */
6585 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6587 log_stderr("failure: openat");
6594 log_stderr("failure: fork");
6598 if (!caps_supported()) {
6599 log_debug("skip: capability library not installed");
6603 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
6604 die("failure: switch_userns");
6606 /* validate file can be directly read */
6607 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6609 die("failure: openat");
6612 /* validate file can be read through own symlink */
6613 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6615 die("failure: openat");
6618 /* validate file can be read through root symlink */
6619 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6621 die("failure: openat");
6624 /* validate file can't be read through other users symlink */
6625 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6627 die("failure: openat");
6628 if (errno != EACCES)
6629 die("failure: errno");
6633 if (wait_for_pid(pid)) {
6634 log_stderr("failure: wait_for_pid");
6640 log_stderr("failure: fork");
6644 if (!caps_supported()) {
6645 log_debug("skip: capability library not installed");
6649 if (!switch_userns(attr.userns_fd, 2000, 2000, true))
6650 die("failure: switch_userns");
6652 /* validate file can be directly read */
6653 fd = openat(open_tree_fd, DIR1 "/" FILE1, O_RDONLY | O_CLOEXEC, 0);
6655 die("failure: openat");
6658 /* validate file can be read through own symlink */
6659 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER3, O_RDONLY | O_CLOEXEC, 0);
6661 die("failure: openat");
6664 /* validate file can be read through root symlink */
6665 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER1, O_RDONLY | O_CLOEXEC, 0);
6667 die("failure: openat");
6670 /* validate file can't be read through other users symlink */
6671 fd = openat(open_tree_fd, DIR1 "/" SYMLINK_USER2, O_RDONLY | O_CLOEXEC, 0);
6673 die("failure: openat");
6674 if (errno != EACCES)
6675 die("failure: errno");
6679 if (wait_for_pid(pid)) {
6680 log_stderr("failure: wait_for_pid");
6685 log_debug("Ran test");
6688 safe_close(open_tree_fd);
6689 safe_close(attr.userns_fd);
6694 static int acls(void)
6697 int dir1_fd = -EBADF, open_tree_fd = -EBADF;
6698 struct mount_attr attr = {
6699 .attr_set = MOUNT_ATTR_IDMAP,
6703 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
6704 log_stderr("failure: mkdirat");
6707 if (fchmodat(t_dir1_fd, DIR1, 0777, 0)) {
6708 log_stderr("failure: fchmodat");
6712 if (mkdirat(t_dir1_fd, DIR2, 0777)) {
6713 log_stderr("failure: mkdirat");
6716 if (fchmodat(t_dir1_fd, DIR2, 0777, 0)) {
6717 log_stderr("failure: fchmodat");
6721 /* Changing mount properties on a detached mount. */
6722 attr.userns_fd = get_userns_fd(100010, 100020, 5);
6723 if (attr.userns_fd < 0) {
6724 log_stderr("failure: get_userns_fd");
6728 open_tree_fd = sys_open_tree(t_dir1_fd, DIR1,
6730 AT_SYMLINK_NOFOLLOW |
6733 if (open_tree_fd < 0) {
6734 log_stderr("failure: sys_open_tree");
6738 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
6739 log_stderr("failure: sys_mount_setattr");
6743 if (sys_move_mount(open_tree_fd, "", t_dir1_fd, DIR2, MOVE_MOUNT_F_EMPTY_PATH)) {
6744 log_stderr("failure: sys_move_mount");
6748 dir1_fd = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
6750 log_stderr("failure: openat");
6754 if (mkdirat(dir1_fd, DIR3, 0000)) {
6755 log_stderr("failure: mkdirat");
6758 if (fchown(dir1_fd, 100010, 100010)) {
6759 log_stderr("failure: fchown");
6762 if (fchmod(dir1_fd, 0777)) {
6763 log_stderr("failure: fchmod");
6767 snprintf(t_buf, sizeof(t_buf), "setfacl -m u:100010:rwx %s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6768 if (system(t_buf)) {
6769 log_stderr("failure: system");
6773 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100010:rwx", t_mountpoint, T_DIR1, DIR1, DIR3);
6774 if (system(t_buf)) {
6775 log_stderr("failure: system");
6779 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:100020:rwx", t_mountpoint, T_DIR1, DIR2, DIR3);
6780 if (system(t_buf)) {
6781 log_stderr("failure: system");
6787 log_stderr("failure: fork");
6791 if (!caps_supported()) {
6792 log_debug("skip: capability library not installed");
6796 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6797 die("failure: switch_userns");
6799 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6800 t_mountpoint, T_DIR1, DIR1, DIR3, 4294967295LU);
6802 die("failure: system");
6806 if (wait_for_pid(pid)) {
6807 log_stderr("failure: wait_for_pid");
6813 log_stderr("failure: fork");
6817 if (!caps_supported()) {
6818 log_debug("skip: capability library not installed");
6822 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6823 die("failure: switch_userns");
6825 snprintf(t_buf, sizeof(t_buf), "getfacl -p %s/%s/%s/%s | grep -q user:%lu:rwx",
6826 t_mountpoint, T_DIR1, DIR2, DIR3, 100010LU);
6828 die("failure: system");
6832 if (wait_for_pid(pid)) {
6833 log_stderr("failure: wait_for_pid");
6837 /* Now, dir is owned by someone else in the user namespace, but we can
6838 * still read it because of acls.
6840 if (fchown(dir1_fd, 100012, 100012)) {
6841 log_stderr("failure: fchown");
6847 log_stderr("failure: fork");
6853 if (!caps_supported()) {
6854 log_debug("skip: capability library not installed");
6858 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6859 die("failure: switch_userns");
6861 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6863 die("failure: openat");
6867 if (wait_for_pid(pid)) {
6868 log_stderr("failure: wait_for_pid");
6872 /* if we delete the acls, the ls should fail because it's 700. */
6873 snprintf(t_buf, sizeof(t_buf), "%s/%s/%s/%s", t_mountpoint, T_DIR1, DIR1, DIR3);
6874 if (removexattr(t_buf, "system.posix_acl_access")) {
6875 log_stderr("failure: removexattr");
6881 log_stderr("failure: fork");
6887 if (!caps_supported()) {
6888 log_debug("skip: capability library not installed");
6892 if (!switch_userns(attr.userns_fd, 100010, 100010, true))
6893 die("failure: switch_userns");
6895 fd = openat(open_tree_fd, DIR3, O_CLOEXEC | O_DIRECTORY);
6897 die("failure: openat");
6901 if (wait_for_pid(pid)) {
6902 log_stderr("failure: wait_for_pid");
6906 snprintf(t_buf, sizeof(t_buf), "%s/" T_DIR1 "/" DIR2, t_mountpoint);
6907 sys_umount2(t_buf, MNT_DETACH);
6910 log_debug("Ran test");
6912 safe_close(attr.userns_fd);
6913 safe_close(dir1_fd);
6914 safe_close(open_tree_fd);
6919 #ifdef HAVE_LIBURING_H
6920 static int io_uring_openat_with_creds(struct io_uring *ring, int dfd, const char *path, int cred_id,
6921 bool with_link, int *ret_cqe)
6923 struct io_uring_cqe *cqe;
6924 struct io_uring_sqe *sqe;
6925 int ret, i, to_submit = 1;
6928 sqe = io_uring_get_sqe(ring);
6930 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6931 io_uring_prep_nop(sqe);
6932 sqe->flags |= IOSQE_IO_LINK;
6937 sqe = io_uring_get_sqe(ring);
6939 return log_error_errno(-EINVAL, EINVAL, "failure: io_uring_sqe");
6940 io_uring_prep_openat(sqe, dfd, path, O_RDONLY | O_CLOEXEC, 0);
6944 sqe->personality = cred_id;
6946 ret = io_uring_submit(ring);
6947 if (ret != to_submit) {
6948 log_stderr("failure: io_uring_submit");
6952 for (i = 0; i < to_submit; i++) {
6953 ret = io_uring_wait_cqe(ring, &cqe);
6955 log_stderr("failure: io_uring_wait_cqe");
6961 * Make sure caller can identify that this is a proper io_uring
6962 * failure and not some earlier error.
6966 io_uring_cqe_seen(ring, cqe);
6968 log_debug("Ran test");
6973 static int io_uring(void)
6976 int file1_fd = -EBADF;
6977 struct io_uring *ring;
6978 int cred_id, ret, ret_cqe;
6981 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
6982 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
6984 return log_errno(-1, "failure: io_uring_queue_init");
6986 ret = io_uring_queue_init(8, ring, 0);
6988 log_stderr("failure: io_uring_queue_init");
6992 ret = io_uring_register_personality(ring);
6995 goto out_unmap; /* personalities not supported */
6999 /* create file only owner can open */
7000 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7002 log_stderr("failure: openat");
7005 if (fchown(file1_fd, 0, 0)) {
7006 log_stderr("failure: fchown");
7009 if (fchmod(file1_fd, 0600)) {
7010 log_stderr("failure: fchmod");
7013 safe_close(file1_fd);
7017 log_stderr("failure: fork");
7021 /* Verify we can open it with our current credentials. */
7022 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7025 die("failure: io_uring_open_file");
7029 if (wait_for_pid(pid)) {
7030 log_stderr("failure: wait_for_pid");
7036 log_stderr("failure: fork");
7040 if (!switch_ids(1000, 1000))
7041 die("failure: switch_ids");
7043 /* Verify we can't open it with our current credentials. */
7045 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7046 -1, false, &ret_cqe);
7048 die("failure: io_uring_open_file");
7050 die("failure: non-open() related io_uring_open_file failure %d", ret_cqe);
7051 if (ret_cqe != -EACCES)
7052 die("failure: errno(%d)", abs(ret_cqe));
7056 if (wait_for_pid(pid)) {
7057 log_stderr("failure: wait_for_pid");
7063 log_stderr("failure: fork");
7067 if (!switch_ids(1000, 1000))
7068 die("failure: switch_ids");
7070 /* Verify we can open it with the registered credentials. */
7071 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7072 cred_id, false, NULL);
7074 die("failure: io_uring_open_file");
7076 /* Verify we can open it with the registered credentials and as
7079 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7080 cred_id, true, NULL);
7082 die("failure: io_uring_open_file");
7086 if (wait_for_pid(pid)) {
7087 log_stderr("failure: wait_for_pid");
7092 log_debug("Ran test");
7094 ret = io_uring_unregister_personality(ring, cred_id);
7096 log_stderr("failure: io_uring_unregister_personality");
7099 munmap(ring, sizeof(struct io_uring));
7101 safe_close(file1_fd);
7106 static int io_uring_userns(void)
7109 int file1_fd = -EBADF, userns_fd = -EBADF;
7110 struct io_uring *ring;
7111 int cred_id, ret, ret_cqe;
7114 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7115 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7117 return log_errno(-1, "failure: io_uring_queue_init");
7119 ret = io_uring_queue_init(8, ring, 0);
7121 log_stderr("failure: io_uring_queue_init");
7125 ret = io_uring_register_personality(ring);
7128 goto out_unmap; /* personalities not supported */
7132 /* create file only owner can open */
7133 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7135 log_stderr("failure: openat");
7138 if (fchown(file1_fd, 0, 0)) {
7139 log_stderr("failure: fchown");
7142 if (fchmod(file1_fd, 0600)) {
7143 log_stderr("failure: fchmod");
7146 safe_close(file1_fd);
7148 userns_fd = get_userns_fd(0, 10000, 10000);
7149 if (userns_fd < 0) {
7150 log_stderr("failure: get_userns_fd");
7156 log_stderr("failure: fork");
7160 /* Verify we can open it with our current credentials. */
7161 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7164 die("failure: io_uring_open_file");
7168 if (wait_for_pid(pid)) {
7169 log_stderr("failure: wait_for_pid");
7175 log_stderr("failure: fork");
7179 if (!switch_userns(userns_fd, 0, 0, false))
7180 die("failure: switch_userns");
7182 /* Verify we can't open it with our current credentials. */
7184 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7185 -1, false, &ret_cqe);
7187 die("failure: io_uring_open_file");
7189 die("failure: non-open() related io_uring_open_file failure");
7190 if (ret_cqe != -EACCES)
7191 die("failure: errno(%d)", abs(ret_cqe));
7195 if (wait_for_pid(pid)) {
7196 log_stderr("failure: wait_for_pid");
7202 log_stderr("failure: fork");
7206 if (!switch_userns(userns_fd, 0, 0, false))
7207 die("failure: switch_userns");
7209 /* Verify we can open it with the registered credentials. */
7210 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7211 cred_id, false, NULL);
7213 die("failure: io_uring_open_file");
7215 /* Verify we can open it with the registered credentials and as
7218 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7219 cred_id, true, NULL);
7221 die("failure: io_uring_open_file");
7225 if (wait_for_pid(pid)) {
7226 log_stderr("failure: wait_for_pid");
7231 log_debug("Ran test");
7233 ret = io_uring_unregister_personality(ring, cred_id);
7235 log_stderr("failure: io_uring_unregister_personality");
7238 munmap(ring, sizeof(struct io_uring));
7240 safe_close(file1_fd);
7241 safe_close(userns_fd);
7246 static int io_uring_idmapped(void)
7249 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7250 struct io_uring *ring;
7251 struct mount_attr attr = {
7252 .attr_set = MOUNT_ATTR_IDMAP,
7257 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7258 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7260 return log_errno(-1, "failure: io_uring_queue_init");
7262 ret = io_uring_queue_init(8, ring, 0);
7264 log_stderr("failure: io_uring_queue_init");
7268 ret = io_uring_register_personality(ring);
7271 goto out_unmap; /* personalities not supported */
7275 /* create file only owner can open */
7276 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7278 log_stderr("failure: openat");
7281 if (fchown(file1_fd, 0, 0)) {
7282 log_stderr("failure: fchown");
7285 if (fchmod(file1_fd, 0600)) {
7286 log_stderr("failure: fchmod");
7289 safe_close(file1_fd);
7291 /* Changing mount properties on a detached mount. */
7292 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7293 if (attr.userns_fd < 0)
7294 return log_errno(-1, "failure: create user namespace");
7296 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7299 AT_SYMLINK_NOFOLLOW |
7302 if (open_tree_fd < 0)
7303 return log_errno(-1, "failure: create detached mount");
7305 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7306 return log_errno(-1, "failure: set mount attributes");
7310 log_stderr("failure: fork");
7314 if (!switch_ids(10000, 10000))
7315 die("failure: switch_ids");
7317 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7320 die("failure: io_uring_open_file");
7324 if (wait_for_pid(pid)) {
7325 log_stderr("failure: wait_for_pid");
7331 log_stderr("failure: fork");
7335 if (!switch_ids(10001, 10001))
7336 die("failure: switch_ids");
7338 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7339 cred_id, false, NULL);
7341 die("failure: io_uring_open_file");
7343 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7344 cred_id, true, NULL);
7346 die("failure: io_uring_open_file");
7350 if (wait_for_pid(pid)) {
7351 log_stderr("failure: wait_for_pid");
7356 log_debug("Ran test");
7358 ret = io_uring_unregister_personality(ring, cred_id);
7360 log_stderr("failure: io_uring_unregister_personality");
7363 munmap(ring, sizeof(struct io_uring));
7365 safe_close(attr.userns_fd);
7366 safe_close(file1_fd);
7367 safe_close(open_tree_fd);
7373 * Create an idmapped mount where the we leave the owner of the file unmapped.
7374 * In no circumstances, even with recorded credentials can it be allowed to
7377 static int io_uring_idmapped_unmapped(void)
7380 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7381 struct io_uring *ring;
7382 struct mount_attr attr = {
7383 .attr_set = MOUNT_ATTR_IDMAP,
7385 int cred_id, ret, ret_cqe;
7388 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7389 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7391 return log_errno(-1, "failure: io_uring_queue_init");
7393 ret = io_uring_queue_init(8, ring, 0);
7395 log_stderr("failure: io_uring_queue_init");
7399 ret = io_uring_register_personality(ring);
7402 goto out_unmap; /* personalities not supported */
7406 /* create file only owner can open */
7407 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7409 log_stderr("failure: openat");
7412 if (fchown(file1_fd, 0, 0)) {
7413 log_stderr("failure: fchown");
7416 if (fchmod(file1_fd, 0600)) {
7417 log_stderr("failure: fchmod");
7420 safe_close(file1_fd);
7422 /* Changing mount properties on a detached mount. */
7423 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7424 if (attr.userns_fd < 0)
7425 return log_errno(-1, "failure: create user namespace");
7427 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7430 AT_SYMLINK_NOFOLLOW |
7433 if (open_tree_fd < 0)
7434 return log_errno(-1, "failure: create detached mount");
7436 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7437 return log_errno(-1, "failure: set mount attributes");
7441 log_stderr("failure: fork");
7445 if (!switch_ids(10000, 10000))
7446 die("failure: switch_ids");
7449 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7450 cred_id, false, &ret_cqe);
7452 die("failure: io_uring_open_file");
7454 die("failure: non-open() related io_uring_open_file failure");
7455 if (ret_cqe != -EACCES)
7456 die("failure: errno(%d)", abs(ret_cqe));
7459 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7460 cred_id, true, &ret_cqe);
7462 die("failure: io_uring_open_file");
7464 die("failure: non-open() related io_uring_open_file failure");
7465 if (ret_cqe != -EACCES)
7466 die("failure: errno(%d)", abs(ret_cqe));
7470 if (wait_for_pid(pid)) {
7471 log_stderr("failure: wait_for_pid");
7476 log_debug("Ran test");
7478 ret = io_uring_unregister_personality(ring, cred_id);
7480 log_stderr("failure: io_uring_unregister_personality");
7483 munmap(ring, sizeof(struct io_uring));
7485 safe_close(attr.userns_fd);
7486 safe_close(file1_fd);
7487 safe_close(open_tree_fd);
7492 static int io_uring_idmapped_userns(void)
7495 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7496 struct io_uring *ring;
7497 struct mount_attr attr = {
7498 .attr_set = MOUNT_ATTR_IDMAP,
7500 int cred_id, ret, ret_cqe;
7503 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7504 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7506 return log_errno(-1, "failure: io_uring_queue_init");
7508 ret = io_uring_queue_init(8, ring, 0);
7510 log_stderr("failure: io_uring_queue_init");
7514 ret = io_uring_register_personality(ring);
7517 goto out_unmap; /* personalities not supported */
7521 /* create file only owner can open */
7522 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7524 log_stderr("failure: openat");
7527 if (fchown(file1_fd, 0, 0)) {
7528 log_stderr("failure: fchown");
7531 if (fchmod(file1_fd, 0600)) {
7532 log_stderr("failure: fchmod");
7535 safe_close(file1_fd);
7537 /* Changing mount properties on a detached mount. */
7538 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7539 if (attr.userns_fd < 0)
7540 return log_errno(-1, "failure: create user namespace");
7542 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7545 AT_SYMLINK_NOFOLLOW |
7548 if (open_tree_fd < 0)
7549 return log_errno(-1, "failure: create detached mount");
7551 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7552 return log_errno(-1, "failure: set mount attributes");
7556 log_stderr("failure: fork");
7560 if (!switch_userns(attr.userns_fd, 0, 0, false))
7561 die("failure: switch_userns");
7563 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7566 die("failure: io_uring_open_file");
7570 if (wait_for_pid(pid)) {
7571 log_stderr("failure: wait_for_pid");
7577 log_stderr("failure: fork");
7581 if (!caps_supported()) {
7582 log_debug("skip: capability library not installed");
7586 if (!switch_userns(attr.userns_fd, 1000, 1000, true))
7587 die("failure: switch_userns");
7590 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7591 -1, false, &ret_cqe);
7593 die("failure: io_uring_open_file");
7595 die("failure: non-open() related io_uring_open_file failure");
7596 if (ret_cqe != -EACCES)
7597 die("failure: errno(%d)", abs(ret_cqe));
7600 file1_fd = io_uring_openat_with_creds(ring, t_dir1_fd, FILE1,
7601 -1, true, &ret_cqe);
7603 die("failure: io_uring_open_file");
7605 die("failure: non-open() related io_uring_open_file failure");
7606 if (ret_cqe != -EACCES)
7607 die("failure: errno(%d)", abs(ret_cqe));
7610 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7611 -1, false, &ret_cqe);
7613 die("failure: io_uring_open_file");
7615 die("failure: non-open() related io_uring_open_file failure");
7616 if (ret_cqe != -EACCES)
7617 die("failure: errno(%d)", abs(ret_cqe));
7620 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7621 -1, true, &ret_cqe);
7623 die("failure: io_uring_open_file");
7625 die("failure: non-open() related io_uring_open_file failure");
7626 if (ret_cqe != -EACCES)
7627 die("failure: errno(%d)", abs(ret_cqe));
7629 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7630 cred_id, false, NULL);
7632 die("failure: io_uring_open_file");
7634 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7635 cred_id, true, NULL);
7637 die("failure: io_uring_open_file");
7641 if (wait_for_pid(pid)) {
7642 log_stderr("failure: wait_for_pid");
7647 log_debug("Ran test");
7649 ret = io_uring_unregister_personality(ring, cred_id);
7651 log_stderr("failure: io_uring_unregister_personality");
7654 munmap(ring, sizeof(struct io_uring));
7656 safe_close(attr.userns_fd);
7657 safe_close(file1_fd);
7658 safe_close(open_tree_fd);
7663 static int io_uring_idmapped_unmapped_userns(void)
7666 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7667 struct io_uring *ring;
7668 struct mount_attr attr = {
7669 .attr_set = MOUNT_ATTR_IDMAP,
7671 int cred_id, ret, ret_cqe;
7674 ring = mmap(0, sizeof(struct io_uring), PROT_READ|PROT_WRITE,
7675 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
7677 return log_errno(-1, "failure: io_uring_queue_init");
7679 ret = io_uring_queue_init(8, ring, 0);
7681 log_stderr("failure: io_uring_queue_init");
7685 ret = io_uring_register_personality(ring);
7688 goto out_unmap; /* personalities not supported */
7692 /* create file only owner can open */
7693 file1_fd = openat(t_dir1_fd, FILE1, O_RDONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
7695 log_stderr("failure: openat");
7698 if (fchown(file1_fd, 0, 0)) {
7699 log_stderr("failure: fchown");
7702 if (fchmod(file1_fd, 0600)) {
7703 log_stderr("failure: fchmod");
7706 safe_close(file1_fd);
7708 /* Changing mount properties on a detached mount. */
7709 attr.userns_fd = get_userns_fd(1, 10000, 10000);
7710 if (attr.userns_fd < 0)
7711 return log_errno(-1, "failure: create user namespace");
7713 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7716 AT_SYMLINK_NOFOLLOW |
7719 if (open_tree_fd < 0)
7720 return log_errno(-1, "failure: create detached mount");
7722 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)))
7723 return log_errno(-1, "failure: set mount attributes");
7727 log_stderr("failure: fork");
7731 if (!caps_supported()) {
7732 log_debug("skip: capability library not installed");
7736 if (!switch_userns(attr.userns_fd, 10000, 10000, true))
7737 die("failure: switch_ids");
7740 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7741 cred_id, false, &ret_cqe);
7743 die("failure: io_uring_open_file");
7745 die("failure: non-open() related io_uring_open_file failure");
7746 if (ret_cqe != -EACCES)
7747 die("failure: errno(%d)", abs(ret_cqe));
7750 file1_fd = io_uring_openat_with_creds(ring, open_tree_fd, FILE1,
7751 cred_id, true, &ret_cqe);
7753 die("failure: io_uring_open_file");
7755 die("failure: non-open() related io_uring_open_file failure");
7756 if (ret_cqe != -EACCES)
7757 die("failure: errno(%d)", abs(ret_cqe));
7761 if (wait_for_pid(pid)) {
7762 log_stderr("failure: wait_for_pid");
7767 log_debug("Ran test");
7769 ret = io_uring_unregister_personality(ring, cred_id);
7771 log_stderr("failure: io_uring_unregister_personality");
7774 munmap(ring, sizeof(struct io_uring));
7776 safe_close(attr.userns_fd);
7777 safe_close(file1_fd);
7778 safe_close(open_tree_fd);
7782 #endif /* HAVE_LIBURING_H */
7784 /* The following tests are concerned with setgid inheritance. These can be
7785 * filesystem type specific. For xfs, if a new file or directory is created
7786 * within a setgid directory and irix_sgid_inhiert is set then inherit the
7787 * setgid bit if the caller is in the group of the directory.
7789 static int setgid_create(void)
7792 int file1_fd = -EBADF;
7795 if (!caps_supported())
7798 if (fchmod(t_dir1_fd, S_IRUSR |
7808 log_stderr("failure: fchmod");
7812 /* Verify that the setgid bit got raised. */
7813 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7814 log_stderr("failure: is_setgid");
7820 log_stderr("failure: fork");
7824 /* create regular file via open() */
7825 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7827 die("failure: create");
7829 /* We're capable_wrt_inode_uidgid() and also our fsgid matches
7830 * the directories gid.
7832 if (!is_setgid(t_dir1_fd, FILE1, 0))
7833 die("failure: is_setgid");
7835 /* create directory */
7836 if (mkdirat(t_dir1_fd, DIR1, 0000))
7837 die("failure: create");
7839 /* Directories always inherit the setgid bit. */
7840 if (!is_setgid(t_dir1_fd, DIR1, 0))
7841 die("failure: is_setgid");
7843 if (unlinkat(t_dir1_fd, FILE1, 0))
7844 die("failure: delete");
7846 if (unlinkat(t_dir1_fd, DIR1, AT_REMOVEDIR))
7847 die("failure: delete");
7851 if (wait_for_pid(pid))
7856 log_stderr("failure: fork");
7860 if (!switch_ids(0, 10000))
7861 die("failure: switch_ids");
7864 die("failure: caps_down");
7866 /* create regular file via open() */
7867 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7869 die("failure: create");
7871 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7872 * bit needs to be stripped.
7874 if (is_setgid(t_dir1_fd, FILE1, 0))
7875 die("failure: is_setgid");
7877 /* create directory */
7878 if (mkdirat(t_dir1_fd, DIR1, 0000))
7879 die("failure: create");
7881 if (xfs_irix_sgid_inherit_enabled()) {
7882 /* We're not in_group_p(). */
7883 if (is_setgid(t_dir1_fd, DIR1, 0))
7884 die("failure: is_setgid");
7886 /* Directories always inherit the setgid bit. */
7887 if (!is_setgid(t_dir1_fd, DIR1, 0))
7888 die("failure: is_setgid");
7893 if (wait_for_pid(pid))
7897 log_debug("Ran test");
7899 safe_close(file1_fd);
7904 static int setgid_create_idmapped(void)
7907 int file1_fd = -EBADF, open_tree_fd = -EBADF;
7908 struct mount_attr attr = {
7909 .attr_set = MOUNT_ATTR_IDMAP,
7913 if (!caps_supported())
7916 if (fchmod(t_dir1_fd, S_IRUSR |
7926 log_stderr("failure: fchmod");
7930 /* Verify that the sid bits got raised. */
7931 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
7932 log_stderr("failure: is_setgid");
7936 /* Changing mount properties on a detached mount. */
7937 attr.userns_fd = get_userns_fd(0, 10000, 10000);
7938 if (attr.userns_fd < 0) {
7939 log_stderr("failure: get_userns_fd");
7943 open_tree_fd = sys_open_tree(t_dir1_fd, "",
7946 AT_SYMLINK_NOFOLLOW |
7949 if (open_tree_fd < 0) {
7950 log_stderr("failure: sys_open_tree");
7954 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
7955 log_stderr("failure: sys_mount_setattr");
7961 log_stderr("failure: fork");
7965 if (!switch_ids(10000, 11000))
7966 die("failure: switch fsids");
7968 /* create regular file via open() */
7969 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
7971 die("failure: create");
7973 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
7974 * bit needs to be stripped.
7976 if (is_setgid(open_tree_fd, FILE1, 0))
7977 die("failure: is_setgid");
7979 /* create directory */
7980 if (mkdirat(open_tree_fd, DIR1, 0000))
7981 die("failure: create");
7983 if (xfs_irix_sgid_inherit_enabled()) {
7984 /* We're not in_group_p(). */
7985 if (is_setgid(open_tree_fd, DIR1, 0))
7986 die("failure: is_setgid");
7988 /* Directories always inherit the setgid bit. */
7989 if (!is_setgid(open_tree_fd, DIR1, 0))
7990 die("failure: is_setgid");
7995 if (wait_for_pid(pid))
7999 log_debug("Ran test");
8001 safe_close(attr.userns_fd);
8002 safe_close(file1_fd);
8003 safe_close(open_tree_fd);
8008 static int setgid_create_idmapped_in_userns(void)
8011 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8012 struct mount_attr attr = {
8013 .attr_set = MOUNT_ATTR_IDMAP,
8017 if (!caps_supported())
8020 if (fchmod(t_dir1_fd, S_IRUSR |
8030 log_stderr("failure: fchmod");
8034 /* Verify that the sid bits got raised. */
8035 if (!is_setgid(t_dir1_fd, "", AT_EMPTY_PATH)) {
8036 log_stderr("failure: is_setgid");
8040 /* Changing mount properties on a detached mount. */
8041 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8042 if (attr.userns_fd < 0) {
8043 log_stderr("failure: get_userns_fd");
8047 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8050 AT_SYMLINK_NOFOLLOW |
8053 if (open_tree_fd < 0) {
8054 log_stderr("failure: sys_open_tree");
8058 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8059 log_stderr("failure: sys_mount_setattr");
8065 log_stderr("failure: fork");
8069 if (!switch_userns(attr.userns_fd, 0, 0, false))
8070 die("failure: switch_userns");
8072 /* create regular file via open() */
8073 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8075 die("failure: create");
8077 /* We're in_group_p() and capable_wrt_inode_uidgid() so setgid
8078 * bit needs to be set.
8080 if (!is_setgid(open_tree_fd, FILE1, 0))
8081 die("failure: is_setgid");
8083 /* create directory */
8084 if (mkdirat(open_tree_fd, DIR1, 0000))
8085 die("failure: create");
8087 /* Directories always inherit the setgid bit. */
8088 if (!is_setgid(open_tree_fd, DIR1, 0))
8089 die("failure: is_setgid");
8091 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8092 die("failure: check ownership");
8094 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8095 die("failure: check ownership");
8097 if (unlinkat(open_tree_fd, FILE1, 0))
8098 die("failure: delete");
8100 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8101 die("failure: delete");
8105 if (wait_for_pid(pid))
8108 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8109 log_stderr("failure: fchownat");
8113 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8114 log_stderr("failure: fchownat");
8120 log_stderr("failure: fork");
8124 if (!caps_supported()) {
8125 log_debug("skip: capability library not installed");
8129 if (!switch_userns(attr.userns_fd, 0, 0, true))
8130 die("failure: switch_userns");
8132 /* create regular file via open() */
8133 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8135 die("failure: create");
8137 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8138 * bit needs to be stripped.
8140 if (is_setgid(open_tree_fd, FILE1, 0))
8141 die("failure: is_setgid");
8143 /* create directory */
8144 if (mkdirat(open_tree_fd, DIR1, 0000))
8145 die("failure: create");
8147 if (xfs_irix_sgid_inherit_enabled()) {
8148 /* We're not in_group_p(). */
8149 if (is_setgid(open_tree_fd, DIR1, 0))
8150 die("failure: is_setgid");
8152 /* Directories always inherit the setgid bit. */
8153 if (!is_setgid(open_tree_fd, DIR1, 0))
8154 die("failure: is_setgid");
8157 /* Files and directories created in setgid directories inherit
8158 * the i_gid of the parent directory.
8160 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8161 die("failure: check ownership");
8163 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
8164 die("failure: check ownership");
8166 if (unlinkat(open_tree_fd, FILE1, 0))
8167 die("failure: delete");
8169 if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
8170 die("failure: delete");
8174 if (wait_for_pid(pid))
8177 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8178 log_stderr("failure: fchownat");
8182 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8183 log_stderr("failure: fchownat");
8189 log_stderr("failure: fork");
8193 if (!caps_supported()) {
8194 log_debug("skip: capability library not installed");
8198 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8199 die("failure: switch_userns");
8201 /* create regular file via open() */
8202 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
8204 die("failure: create");
8206 /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
8207 * bit needs to be stripped.
8209 if (is_setgid(open_tree_fd, FILE1, 0))
8210 die("failure: is_setgid");
8212 /* create directory */
8213 if (mkdirat(open_tree_fd, DIR1, 0000))
8214 die("failure: create");
8216 /* Directories always inherit the setgid bit. */
8217 if (xfs_irix_sgid_inherit_enabled()) {
8218 /* We're not in_group_p(). */
8219 if (is_setgid(open_tree_fd, DIR1, 0))
8220 die("failure: is_setgid");
8222 /* Directories always inherit the setgid bit. */
8223 if (!is_setgid(open_tree_fd, DIR1, 0))
8224 die("failure: is_setgid");
8227 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8228 die("failure: check ownership");
8230 if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0))
8231 die("failure: check ownership");
8235 if (wait_for_pid(pid))
8239 log_debug("Ran test");
8241 safe_close(attr.userns_fd);
8242 safe_close(file1_fd);
8243 safe_close(open_tree_fd);
8248 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
8249 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
8251 static void *idmapped_mount_create_cb(void *data)
8253 int fret = EXIT_FAILURE, open_tree_fd = PTR_TO_INT(data);
8254 struct mount_attr attr = {
8255 .attr_set = MOUNT_ATTR_IDMAP,
8258 /* Changing mount properties on a detached mount. */
8259 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8260 if (attr.userns_fd < 0) {
8261 log_stderr("failure: get_userns_fd");
8265 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8266 log_stderr("failure: sys_mount_setattr");
8270 fret = EXIT_SUCCESS;
8273 safe_close(attr.userns_fd);
8274 pthread_exit(INT_TO_PTR(fret));
8277 /* This tries to verify that we never see an inconistent ownership on-disk and
8278 * can't write invalid ids to disk. To do this we create a race between
8279 * idmapping a mount and creating files on it.
8280 * Note, while it is perfectly fine to see overflowuid and overflowgid as owner
8281 * if we create files through the open_tree_fd before the mount is idmapped but
8282 * look at the files after the mount has been idmapped in this test it can never
8283 * be the case that we see overflowuid and overflowgid when we access the file
8284 * through a non-idmapped mount (in the initial user namespace).
8286 static void *idmapped_mount_operations_cb(void *data)
8288 int file1_fd = -EBADF, file2_fd = -EBADF, dir1_fd = -EBADF,
8289 dir1_fd2 = -EBADF, fret = EXIT_FAILURE,
8290 open_tree_fd = PTR_TO_INT(data);
8292 if (!switch_fsids(10000, 10000)) {
8293 log_stderr("failure: switch fsids");
8297 file1_fd = openat(open_tree_fd, FILE1,
8298 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8300 log_stderr("failure: openat");
8304 file2_fd = openat(open_tree_fd, FILE2,
8305 O_CREAT | O_EXCL | O_CLOEXEC, 0644);
8307 log_stderr("failure: openat");
8311 if (mkdirat(open_tree_fd, DIR1, 0777)) {
8312 log_stderr("failure: mkdirat");
8316 dir1_fd = openat(open_tree_fd, DIR1,
8317 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8319 log_stderr("failure: openat");
8323 if (!__expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0, false) &&
8324 !__expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000, false) &&
8325 !__expected_uid_gid(open_tree_fd, FILE1, 0, t_overflowuid, t_overflowgid, false)) {
8326 log_stderr("failure: expected_uid_gid");
8330 if (!__expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0, false) &&
8331 !__expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000, false) &&
8332 !__expected_uid_gid(open_tree_fd, FILE2, 0, t_overflowuid, t_overflowgid, false)) {
8333 log_stderr("failure: expected_uid_gid");
8337 if (!__expected_uid_gid(open_tree_fd, DIR1, 0, 0, 0, false) &&
8338 !__expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000, false) &&
8339 !__expected_uid_gid(open_tree_fd, DIR1, 0, t_overflowuid, t_overflowgid, false)) {
8340 log_stderr("failure: expected_uid_gid");
8344 if (!__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 0, 0, false) &&
8345 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, 10000, 10000, false) &&
8346 !__expected_uid_gid(dir1_fd, "", AT_EMPTY_PATH, t_overflowuid, t_overflowgid, false)) {
8347 log_stderr("failure: expected_uid_gid");
8351 dir1_fd2 = openat(t_dir1_fd, DIR1,
8352 O_RDONLY | O_DIRECTORY | O_CLOEXEC);
8354 log_stderr("failure: openat");
8358 if (!__expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0, false) &&
8359 !__expected_uid_gid(t_dir1_fd, FILE1, 0, 10000, 10000, false)) {
8360 log_stderr("failure: expected_uid_gid");
8364 if (!__expected_uid_gid(t_dir1_fd, FILE2, 0, 0, 0, false) &&
8365 !__expected_uid_gid(t_dir1_fd, FILE2, 0, 10000, 10000, false)) {
8366 log_stderr("failure: expected_uid_gid");
8370 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8371 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8372 log_stderr("failure: expected_uid_gid");
8376 if (!__expected_uid_gid(t_dir1_fd, DIR1, 0, 0, 0, false) &&
8377 !__expected_uid_gid(t_dir1_fd, DIR1, 0, 10000, 10000, false)) {
8378 log_stderr("failure: expected_uid_gid");
8382 if (!__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 0, 0, false) &&
8383 !__expected_uid_gid(dir1_fd2, "", AT_EMPTY_PATH, 10000, 10000, false)) {
8384 log_stderr("failure: expected_uid_gid");
8388 fret = EXIT_SUCCESS;
8391 safe_close(file1_fd);
8392 safe_close(file2_fd);
8393 safe_close(dir1_fd);
8394 safe_close(dir1_fd2);
8396 pthread_exit(INT_TO_PTR(fret));
8399 static int threaded_idmapped_mount_interactions(void)
8404 pthread_attr_t thread_attr;
8405 pthread_t threads[2];
8407 pthread_attr_init(&thread_attr);
8409 for (i = 0; i < 1000; i++) {
8410 int ret1 = 0, ret2 = 0, tret1 = 0, tret2 = 0;
8414 log_stderr("failure: fork");
8418 int open_tree_fd = -EBADF;
8420 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8423 AT_SYMLINK_NOFOLLOW |
8426 if (open_tree_fd < 0)
8427 die("failure: sys_open_tree");
8429 if (pthread_create(&threads[0], &thread_attr,
8430 idmapped_mount_create_cb,
8431 INT_TO_PTR(open_tree_fd)))
8432 die("failure: pthread_create");
8434 if (pthread_create(&threads[1], &thread_attr,
8435 idmapped_mount_operations_cb,
8436 INT_TO_PTR(open_tree_fd)))
8437 die("failure: pthread_create");
8439 ret1 = pthread_join(threads[0], INT_TO_PTR(tret1));
8440 ret2 = pthread_join(threads[1], INT_TO_PTR(tret2));
8444 die("failure: pthread_join");
8449 die("failure: pthread_join");
8459 if (wait_for_pid(pid)) {
8460 log_stderr("failure: iteration %d", i);
8464 rm_r(t_dir1_fd, ".");
8469 log_debug("Ran test");
8475 static int setattr_truncate(void)
8478 int file1_fd = -EBADF;
8480 /* create regular file via open() */
8481 file1_fd = openat(t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8483 log_stderr("failure: create");
8487 if (ftruncate(file1_fd, 10000)) {
8488 log_stderr("failure: ftruncate");
8492 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8493 log_stderr("failure: check ownership");
8497 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 10000)) {
8498 log_stderr("failure: expected_file_size");
8502 if (ftruncate(file1_fd, 0)) {
8503 log_stderr("failure: ftruncate");
8507 if (!expected_uid_gid(t_dir1_fd, FILE1, 0, 0, 0)) {
8508 log_stderr("failure: check ownership");
8512 if (!expected_file_size(file1_fd, "", AT_EMPTY_PATH, 0)) {
8513 log_stderr("failure: expected_file_size");
8517 if (unlinkat(t_dir1_fd, FILE1, 0)) {
8518 log_stderr("failure: remove");
8523 log_debug("Ran test");
8525 safe_close(file1_fd);
8530 static int setattr_truncate_idmapped(void)
8533 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8535 struct mount_attr attr = {
8536 .attr_set = MOUNT_ATTR_IDMAP,
8539 /* Changing mount properties on a detached mount. */
8540 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8541 if (attr.userns_fd < 0) {
8542 log_stderr("failure: get_userns_fd");
8546 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8549 AT_SYMLINK_NOFOLLOW |
8552 if (open_tree_fd < 0) {
8553 log_stderr("failure: sys_open_tree");
8557 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8558 log_stderr("failure: sys_mount_setattr");
8564 log_stderr("failure: fork");
8568 if (!switch_ids(10000, 10000))
8569 die("failure: switch_ids");
8571 /* create regular file via open() */
8572 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8574 die("failure: create");
8576 if (ftruncate(file1_fd, 10000))
8577 die("failure: ftruncate");
8579 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8580 die("failure: check ownership");
8582 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8583 die("failure: expected_file_size");
8585 if (ftruncate(file1_fd, 0))
8586 die("failure: ftruncate");
8588 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8589 die("failure: check ownership");
8591 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8592 die("failure: expected_file_size");
8596 if (wait_for_pid(pid))
8601 log_stderr("failure: fork");
8605 int file1_fd2 = -EBADF;
8607 /* create regular file via open() */
8608 file1_fd2 = openat(open_tree_fd, FILE1, O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8610 die("failure: create");
8612 if (ftruncate(file1_fd2, 10000))
8613 die("failure: ftruncate");
8615 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8616 die("failure: check ownership");
8618 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8619 die("failure: expected_file_size");
8621 if (ftruncate(file1_fd2, 0))
8622 die("failure: ftruncate");
8624 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
8625 die("failure: check ownership");
8627 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8628 die("failure: expected_file_size");
8632 if (wait_for_pid(pid))
8636 log_debug("Ran test");
8638 safe_close(file1_fd);
8639 safe_close(open_tree_fd);
8644 static int setattr_truncate_idmapped_in_userns(void)
8647 int file1_fd = -EBADF, open_tree_fd = -EBADF;
8648 struct mount_attr attr = {
8649 .attr_set = MOUNT_ATTR_IDMAP,
8653 /* Changing mount properties on a detached mount. */
8654 attr.userns_fd = get_userns_fd(0, 10000, 10000);
8655 if (attr.userns_fd < 0) {
8656 log_stderr("failure: get_userns_fd");
8660 open_tree_fd = sys_open_tree(t_dir1_fd, "",
8663 AT_SYMLINK_NOFOLLOW |
8666 if (open_tree_fd < 0) {
8667 log_stderr("failure: sys_open_tree");
8671 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
8672 log_stderr("failure: sys_mount_setattr");
8678 log_stderr("failure: fork");
8682 if (!switch_userns(attr.userns_fd, 0, 0, false))
8683 die("failure: switch_userns");
8685 /* create regular file via open() */
8686 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8688 die("failure: create");
8690 if (ftruncate(file1_fd, 10000))
8691 die("failure: ftruncate");
8693 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8694 die("failure: check ownership");
8696 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8697 die("failure: expected_file_size");
8699 if (ftruncate(file1_fd, 0))
8700 die("failure: ftruncate");
8702 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8703 die("failure: check ownership");
8705 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8706 die("failure: expected_file_size");
8708 if (unlinkat(open_tree_fd, FILE1, 0))
8709 die("failure: delete");
8713 if (wait_for_pid(pid))
8716 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8717 log_stderr("failure: fchownat");
8721 if (fchownat(t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8722 log_stderr("failure: fchownat");
8728 log_stderr("failure: fork");
8732 if (!caps_supported()) {
8733 log_debug("skip: capability library not installed");
8737 if (!switch_userns(attr.userns_fd, 0, 0, true))
8738 die("failure: switch_userns");
8740 /* create regular file via open() */
8741 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8743 die("failure: create");
8745 if (ftruncate(file1_fd, 10000))
8746 die("failure: ftruncate");
8748 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8749 die("failure: check ownership");
8751 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8752 die("failure: expected_file_size");
8754 if (ftruncate(file1_fd, 0))
8755 die("failure: ftruncate");
8757 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
8758 die("failure: check ownership");
8760 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8761 die("failure: expected_file_size");
8763 if (unlinkat(open_tree_fd, FILE1, 0))
8764 die("failure: delete");
8768 if (wait_for_pid(pid))
8771 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8772 log_stderr("failure: fchownat");
8776 if (fchownat(t_dir1_fd, "", -1, 0, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
8777 log_stderr("failure: fchownat");
8783 log_stderr("failure: fork");
8787 if (!caps_supported()) {
8788 log_debug("skip: capability library not installed");
8792 if (!switch_userns(attr.userns_fd, 0, 1000, true))
8793 die("failure: switch_userns");
8795 /* create regular file via open() */
8796 file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, S_IXGRP | S_ISGID);
8798 die("failure: create");
8800 if (ftruncate(file1_fd, 10000))
8801 die("failure: ftruncate");
8803 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8804 die("failure: check ownership");
8806 if (!expected_file_size(open_tree_fd, FILE1, 0, 10000))
8807 die("failure: expected_file_size");
8809 if (ftruncate(file1_fd, 0))
8810 die("failure: ftruncate");
8812 if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
8813 die("failure: check ownership");
8815 if (!expected_file_size(open_tree_fd, FILE1, 0, 0))
8816 die("failure: expected_file_size");
8818 if (unlinkat(open_tree_fd, FILE1, 0))
8819 die("failure: delete");
8823 if (wait_for_pid(pid))
8827 log_debug("Ran test");
8829 safe_close(attr.userns_fd);
8830 safe_close(file1_fd);
8831 safe_close(open_tree_fd);
8836 static int nested_userns(void)
8842 struct list *it, *next;
8843 struct userns_hierarchy hierarchy[] = {
8844 { .level = 1, .fd_userns = -EBADF, },
8845 { .level = 2, .fd_userns = -EBADF, },
8846 { .level = 3, .fd_userns = -EBADF, },
8847 { .level = 4, .fd_userns = -EBADF, },
8848 /* Dummy entry that marks the end. */
8849 { .level = MAX_USERNS_LEVEL, .fd_userns = -EBADF, },
8851 struct mount_attr attr_level1 = {
8852 .attr_set = MOUNT_ATTR_IDMAP,
8853 .userns_fd = -EBADF,
8855 struct mount_attr attr_level2 = {
8856 .attr_set = MOUNT_ATTR_IDMAP,
8857 .userns_fd = -EBADF,
8859 struct mount_attr attr_level3 = {
8860 .attr_set = MOUNT_ATTR_IDMAP,
8861 .userns_fd = -EBADF,
8863 struct mount_attr attr_level4 = {
8864 .attr_set = MOUNT_ATTR_IDMAP,
8865 .userns_fd = -EBADF,
8867 int fd_dir1 = -EBADF,
8868 fd_open_tree_level1 = -EBADF,
8869 fd_open_tree_level2 = -EBADF,
8870 fd_open_tree_level3 = -EBADF,
8871 fd_open_tree_level4 = -EBADF;
8872 const unsigned int id_file_range = 10000;
8874 list_init(&hierarchy[0].id_map);
8875 list_init(&hierarchy[1].id_map);
8876 list_init(&hierarchy[2].id_map);
8877 list_init(&hierarchy[3].id_map);
8880 * Give a large map to the outermost user namespace so we can create
8881 * comfortable nested maps.
8883 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_UID);
8885 log_stderr("failure: adding uidmap for userns at level 1");
8889 ret = add_map_entry(&hierarchy[0].id_map, 1000000, 0, 1000000000, ID_TYPE_GID);
8891 log_stderr("failure: adding gidmap for userns at level 1");
8895 /* This is uid:0->2000000:100000000 in init userns. */
8896 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_UID);
8898 log_stderr("failure: adding uidmap for userns at level 2");
8902 /* This is gid:0->2000000:100000000 in init userns. */
8903 ret = add_map_entry(&hierarchy[1].id_map, 1000000, 0, 100000000, ID_TYPE_GID);
8905 log_stderr("failure: adding gidmap for userns at level 2");
8909 /* This is uid:0->3000000:999 in init userns. */
8910 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_UID);
8912 log_stderr("failure: adding uidmap for userns at level 3");
8916 /* This is gid:0->3000000:999 in the init userns. */
8917 ret = add_map_entry(&hierarchy[2].id_map, 1000000, 0, 999, ID_TYPE_GID);
8919 log_stderr("failure: adding gidmap for userns at level 3");
8923 /* id 999 will remain unmapped. */
8925 /* This is uid:1000->2001000:1 in init userns. */
8926 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_UID);
8928 log_stderr("failure: adding uidmap for userns at level 3");
8932 /* This is gid:1000->2001000:1 in init userns. */
8933 ret = add_map_entry(&hierarchy[2].id_map, 1000, 1000, 1, ID_TYPE_GID);
8935 log_stderr("failure: adding gidmap for userns at level 3");
8939 /* This is uid:1001->3001001:10000 in init userns. */
8940 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_UID);
8942 log_stderr("failure: adding uidmap for userns at level 3");
8946 /* This is gid:1001->3001001:10000 in init userns. */
8947 ret = add_map_entry(&hierarchy[2].id_map, 1001001, 1001, 10000000, ID_TYPE_GID);
8949 log_stderr("failure: adding gidmap for userns at level 3");
8953 /* Don't write a mapping in the 4th userns. */
8954 list_empty(&hierarchy[4].id_map);
8956 /* Create the actual userns hierarchy. */
8957 ret = create_userns_hierarchy(hierarchy);
8959 log_stderr("failure: create userns hierarchy");
8963 attr_level1.userns_fd = hierarchy[0].fd_userns;
8964 attr_level2.userns_fd = hierarchy[1].fd_userns;
8965 attr_level3.userns_fd = hierarchy[2].fd_userns;
8966 attr_level4.userns_fd = hierarchy[3].fd_userns;
8969 * Create one directory where we create files for each uid/gid within
8972 if (mkdirat(t_dir1_fd, DIR1, 0777)) {
8973 log_stderr("failure: mkdirat");
8977 fd_dir1 = openat(t_dir1_fd, DIR1, O_DIRECTORY | O_CLOEXEC);
8979 log_stderr("failure: openat");
8983 for (id = 0; id <= id_file_range; id++) {
8986 snprintf(file, sizeof(file), DIR1 "/" FILE1 "_%u", id);
8988 if (mknodat(t_dir1_fd, file, S_IFREG | 0644, 0)) {
8989 log_stderr("failure: create %s", file);
8993 if (fchownat(t_dir1_fd, file, id, id, AT_SYMLINK_NOFOLLOW)) {
8994 log_stderr("failure: fchownat %s", file);
8998 if (!expected_uid_gid(t_dir1_fd, file, 0, id, id)) {
8999 log_stderr("failure: check ownership %s", file);
9004 /* Create detached mounts for all the user namespaces. */
9005 fd_open_tree_level1 = sys_open_tree(t_dir1_fd, DIR1,
9007 AT_SYMLINK_NOFOLLOW |
9010 if (fd_open_tree_level1 < 0) {
9011 log_stderr("failure: sys_open_tree");
9015 fd_open_tree_level2 = sys_open_tree(t_dir1_fd, DIR1,
9017 AT_SYMLINK_NOFOLLOW |
9020 if (fd_open_tree_level2 < 0) {
9021 log_stderr("failure: sys_open_tree");
9025 fd_open_tree_level3 = sys_open_tree(t_dir1_fd, DIR1,
9027 AT_SYMLINK_NOFOLLOW |
9030 if (fd_open_tree_level3 < 0) {
9031 log_stderr("failure: sys_open_tree");
9035 fd_open_tree_level4 = sys_open_tree(t_dir1_fd, DIR1,
9037 AT_SYMLINK_NOFOLLOW |
9040 if (fd_open_tree_level4 < 0) {
9041 log_stderr("failure: sys_open_tree");
9045 /* Turn detached mounts into detached idmapped mounts. */
9046 if (sys_mount_setattr(fd_open_tree_level1, "", AT_EMPTY_PATH,
9047 &attr_level1, sizeof(attr_level1))) {
9048 log_stderr("failure: sys_mount_setattr");
9052 if (sys_mount_setattr(fd_open_tree_level2, "", AT_EMPTY_PATH,
9053 &attr_level2, sizeof(attr_level2))) {
9054 log_stderr("failure: sys_mount_setattr");
9058 if (sys_mount_setattr(fd_open_tree_level3, "", AT_EMPTY_PATH,
9059 &attr_level3, sizeof(attr_level3))) {
9060 log_stderr("failure: sys_mount_setattr");
9064 if (sys_mount_setattr(fd_open_tree_level4, "", AT_EMPTY_PATH,
9065 &attr_level4, sizeof(attr_level4))) {
9066 log_stderr("failure: sys_mount_setattr");
9070 /* Verify that ownership looks correct for callers in the init userns. */
9071 for (id = 0; id <= id_file_range; id++) {
9073 unsigned int id_level1, id_level2, id_level3;
9076 snprintf(file, sizeof(file), FILE1 "_%u", id);
9078 id_level1 = id + 1000000;
9079 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1)) {
9080 log_stderr("failure: check ownership %s", file);
9084 id_level2 = id + 2000000;
9085 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2)) {
9086 log_stderr("failure: check ownership %s", file);
9091 /* This id is unmapped. */
9092 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9093 } else if (id == 1000) {
9094 id_level3 = id + 2000000; /* We punched a hole in the map at 1000. */
9095 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9097 id_level3 = id + 3000000; /* Rest is business as usual. */
9098 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9101 log_stderr("failure: check ownership %s", file);
9105 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid)) {
9106 log_stderr("failure: check ownership %s", file);
9111 /* Verify that ownership looks correct for callers in the first userns. */
9114 log_stderr("failure: fork");
9118 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9119 die("failure: switch_userns");
9121 for (id = 0; id <= id_file_range; id++) {
9123 unsigned int id_level1, id_level2, id_level3;
9126 snprintf(file, sizeof(file), FILE1 "_%u", id);
9129 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9130 die("failure: check ownership %s", file);
9132 id_level2 = id + 1000000;
9133 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9134 die("failure: check ownership %s", file);
9137 /* This id is unmapped. */
9138 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9139 } else if (id == 1000) {
9140 id_level3 = id + 1000000; /* We punched a hole in the map at 1000. */
9141 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9143 id_level3 = id + 2000000; /* Rest is business as usual. */
9144 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9147 die("failure: check ownership %s", file);
9149 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9150 die("failure: check ownership %s", file);
9155 if (wait_for_pid(pid))
9158 /* Verify that ownership looks correct for callers in the second userns. */
9161 log_stderr("failure: fork");
9165 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9166 die("failure: switch_userns");
9168 for (id = 0; id <= id_file_range; id++) {
9170 unsigned int id_level2, id_level3;
9173 snprintf(file, sizeof(file), FILE1 "_%u", id);
9175 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9176 die("failure: check ownership %s", file);
9179 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9180 die("failure: check ownership %s", file);
9183 /* This id is unmapped. */
9184 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9185 } else if (id == 1000) {
9186 id_level3 = id; /* We punched a hole in the map at 1000. */
9187 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9189 id_level3 = id + 1000000; /* Rest is business as usual. */
9190 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9193 die("failure: check ownership %s", file);
9195 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9196 die("failure: check ownership %s", file);
9201 if (wait_for_pid(pid))
9204 /* Verify that ownership looks correct for callers in the third userns. */
9207 log_stderr("failure: fork");
9211 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9212 die("failure: switch_userns");
9214 for (id = 0; id <= id_file_range; id++) {
9216 unsigned int id_level2, id_level3;
9219 snprintf(file, sizeof(file), FILE1 "_%u", id);
9221 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9222 die("failure: check ownership %s", file);
9226 * The idmapping of the third userns has a hole
9227 * at uid/gid 1000. That means:
9228 * - 1000->userns_0(2000000) // init userns
9229 * - 1000->userns_1(2000000) // level 1
9230 * - 1000->userns_2(1000000) // level 2
9231 * - 1000->userns_3(1000) // level 3 (because level 3 has a hole)
9234 bret = expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2);
9236 bret = expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid);
9239 die("failure: check ownership %s", file);
9243 /* This id is unmapped. */
9244 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9246 id_level3 = id; /* Rest is business as usual. */
9247 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9250 die("failure: check ownership %s", file);
9252 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9253 die("failure: check ownership %s", file);
9258 if (wait_for_pid(pid))
9261 /* Verify that ownership looks correct for callers in the fourth userns. */
9264 log_stderr("failure: fork");
9268 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9269 die("failure: switch_userns");
9271 for (id = 0; id <= id_file_range; id++) {
9274 snprintf(file, sizeof(file), FILE1 "_%u", id);
9276 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9277 die("failure: check ownership %s", file);
9279 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9280 die("failure: check ownership %s", file);
9282 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9283 die("failure: check ownership %s", file);
9285 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9286 die("failure: check ownership %s", file);
9291 if (wait_for_pid(pid))
9294 /* Verify that chown works correctly for callers in the first userns. */
9297 log_stderr("failure: fork");
9301 if (!switch_userns(attr_level1.userns_fd, 0, 0, false))
9302 die("failure: switch_userns");
9304 for (id = 0; id <= id_file_range; id++) {
9306 unsigned int id_level1, id_level2, id_level3, id_new;
9309 snprintf(file, sizeof(file), FILE1 "_%u", id);
9312 if (fchownat(fd_open_tree_level1, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9313 die("failure: fchownat %s", file);
9316 if (!expected_uid_gid(fd_open_tree_level1, file, 0, id_level1, id_level1))
9317 die("failure: check ownership %s", file);
9319 id_level2 = id_new + 1000000;
9320 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9321 die("failure: check ownership %s", file);
9323 if (id_new == 999) {
9324 /* This id is unmapped. */
9325 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9326 } else if (id_new == 1000) {
9327 id_level3 = id_new + 1000000; /* We punched a hole in the map at 1000. */
9328 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9330 id_level3 = id_new + 2000000; /* Rest is business as usual. */
9331 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9334 die("failure: check ownership %s", file);
9336 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9337 die("failure: check ownership %s", file);
9339 /* Revert ownership. */
9340 if (fchownat(fd_open_tree_level1, file, id, id, AT_SYMLINK_NOFOLLOW))
9341 die("failure: fchownat %s", file);
9346 if (wait_for_pid(pid))
9349 /* Verify that chown works correctly for callers in the second userns. */
9352 log_stderr("failure: fork");
9356 if (!switch_userns(attr_level2.userns_fd, 0, 0, false))
9357 die("failure: switch_userns");
9359 for (id = 0; id <= id_file_range; id++) {
9361 unsigned int id_level2, id_level3, id_new;
9364 snprintf(file, sizeof(file), FILE1 "_%u", id);
9367 if (fchownat(fd_open_tree_level2, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9368 die("failure: fchownat %s", file);
9370 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9371 die("failure: check ownership %s", file);
9374 if (!expected_uid_gid(fd_open_tree_level2, file, 0, id_level2, id_level2))
9375 die("failure: check ownership %s", file);
9377 if (id_new == 999) {
9378 /* This id is unmapped. */
9379 bret = expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid);
9380 } else if (id_new == 1000) {
9381 id_level3 = id_new; /* We punched a hole in the map at 1000. */
9382 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9384 id_level3 = id_new + 1000000; /* Rest is business as usual. */
9385 bret = expected_uid_gid(fd_open_tree_level3, file, 0, id_level3, id_level3);
9388 die("failure: check ownership %s", file);
9390 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9391 die("failure: check ownership %s", file);
9393 /* Revert ownership. */
9394 if (fchownat(fd_open_tree_level2, file, id, id, AT_SYMLINK_NOFOLLOW))
9395 die("failure: fchownat %s", file);
9400 if (wait_for_pid(pid))
9403 /* Verify that chown works correctly for callers in the third userns. */
9406 log_stderr("failure: fork");
9410 if (!switch_userns(attr_level3.userns_fd, 0, 0, false))
9411 die("failure: switch_userns");
9413 for (id = 0; id <= id_file_range; id++) {
9414 unsigned int id_new;
9417 snprintf(file, sizeof(file), FILE1 "_%u", id);
9420 if (id_new == 999 || id_new == 1000) {
9422 * We can't change ownership as we can't
9423 * chown from or to an unmapped id.
9425 if (!fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9426 die("failure: fchownat %s", file);
9428 if (fchownat(fd_open_tree_level3, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9429 die("failure: fchownat %s", file);
9432 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9433 die("failure: check ownership %s", file);
9435 /* There's no id 1000 anymore as we changed ownership for id 1000 to 1001 above. */
9436 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9437 die("failure: check ownership %s", file);
9439 if (id_new == 999) {
9441 * We did not change ownership as we can't
9442 * chown to an unmapped id.
9444 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id, id))
9445 die("failure: check ownership %s", file);
9446 } else if (id_new == 1000) {
9448 * We did not change ownership as we can't
9449 * chown from an unmapped id.
9451 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9452 die("failure: check ownership %s", file);
9454 if (!expected_uid_gid(fd_open_tree_level3, file, 0, id_new, id_new))
9455 die("failure: check ownership %s", file);
9458 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9459 die("failure: check ownership %s", file);
9461 /* Revert ownership. */
9462 if (id_new != 999 && id_new != 1000) {
9463 if (fchownat(fd_open_tree_level3, file, id, id, AT_SYMLINK_NOFOLLOW))
9464 die("failure: fchownat %s", file);
9470 if (wait_for_pid(pid))
9473 /* Verify that chown works correctly for callers in the fourth userns. */
9476 log_stderr("failure: fork");
9480 if (setns(attr_level4.userns_fd, CLONE_NEWUSER))
9481 die("failure: switch_userns");
9483 for (id = 0; id <= id_file_range; id++) {
9485 unsigned long id_new;
9487 snprintf(file, sizeof(file), FILE1 "_%u", id);
9490 if (!fchownat(fd_open_tree_level4, file, id_new, id_new, AT_SYMLINK_NOFOLLOW))
9491 die("failure: fchownat %s", file);
9493 if (!expected_uid_gid(fd_open_tree_level1, file, 0, t_overflowuid, t_overflowgid))
9494 die("failure: check ownership %s", file);
9496 if (!expected_uid_gid(fd_open_tree_level2, file, 0, t_overflowuid, t_overflowgid))
9497 die("failure: check ownership %s", file);
9499 if (!expected_uid_gid(fd_open_tree_level3, file, 0, t_overflowuid, t_overflowgid))
9500 die("failure: check ownership %s", file);
9502 if (!expected_uid_gid(fd_open_tree_level4, file, 0, t_overflowuid, t_overflowgid))
9503 die("failure: check ownership %s", file);
9509 if (wait_for_pid(pid))
9513 log_debug("Ran test");
9516 list_for_each_safe(it, &hierarchy[0].id_map, next) {
9522 list_for_each_safe(it, &hierarchy[1].id_map, next) {
9528 list_for_each_safe(it, &hierarchy[2].id_map, next) {
9534 safe_close(hierarchy[0].fd_userns);
9535 safe_close(hierarchy[1].fd_userns);
9536 safe_close(hierarchy[2].fd_userns);
9537 safe_close(fd_dir1);
9538 safe_close(fd_open_tree_level1);
9539 safe_close(fd_open_tree_level2);
9540 safe_close(fd_open_tree_level3);
9541 safe_close(fd_open_tree_level4);
9545 #ifndef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS
9547 #ifndef BTRFS_PATH_NAME_MAX
9548 #define BTRFS_PATH_NAME_MAX 4087
9551 struct btrfs_ioctl_vol_args {
9553 char name[BTRFS_PATH_NAME_MAX + 1];
9557 #ifndef HAVE_STRUCT_BTRFS_QGROUP_LIMIT
9558 struct btrfs_qgroup_limit {
9567 #ifndef HAVE_STRUCT_BTRFS_QGROUP_INHERIT
9568 struct btrfs_qgroup_inherit {
9571 __u64 num_ref_copies;
9572 __u64 num_excl_copies;
9573 struct btrfs_qgroup_limit lim;
9578 #if !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2) || !defined(HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2_SUBVOLID)
9580 #ifndef BTRFS_SUBVOL_NAME_MAX
9581 #define BTRFS_SUBVOL_NAME_MAX 4039
9584 struct btrfs_ioctl_vol_args_v2 {
9591 struct btrfs_qgroup_inherit *qgroup_inherit;
9596 char name[BTRFS_SUBVOL_NAME_MAX + 1];
9603 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_ARGS
9605 #ifndef BTRFS_INO_LOOKUP_PATH_MAX
9606 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
9608 struct btrfs_ioctl_ino_lookup_args {
9611 char name[BTRFS_INO_LOOKUP_PATH_MAX];
9615 #ifndef HAVE_STRUCT_BTRFS_IOCTL_INO_LOOKUP_USER_ARGS
9617 #ifndef BTRFS_VOL_NAME_MAX
9618 #define BTRFS_VOL_NAME_MAX 255
9621 #ifndef BTRFS_INO_LOOKUP_USER_PATH_MAX
9622 #define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1)
9625 struct btrfs_ioctl_ino_lookup_user_args {
9628 char name[BTRFS_VOL_NAME_MAX + 1];
9629 char path[BTRFS_INO_LOOKUP_USER_PATH_MAX];
9633 #ifndef HAVE_STRUCT_BTRFS_IOCTL_GET_SUBVOL_ROOTREF_ARGS
9635 #ifndef BTRFS_MAX_ROOTREF_BUFFER_NUM
9636 #define BTRFS_MAX_ROOTREF_BUFFER_NUM 255
9639 struct btrfs_ioctl_get_subvol_rootref_args {
9644 } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
9650 #ifndef BTRFS_IOCTL_MAGIC
9651 #define BTRFS_IOCTL_MAGIC 0x94
9654 #ifndef BTRFS_IOC_SNAP_DESTROY
9655 #define BTRFS_IOC_SNAP_DESTROY \
9656 _IOW(BTRFS_IOCTL_MAGIC, 15, struct btrfs_ioctl_vol_args)
9659 #ifndef BTRFS_IOC_SNAP_DESTROY_V2
9660 #define BTRFS_IOC_SNAP_DESTROY_V2 \
9661 _IOW(BTRFS_IOCTL_MAGIC, 63, struct btrfs_ioctl_vol_args_v2)
9664 #ifndef BTRFS_IOC_SNAP_CREATE_V2
9665 #define BTRFS_IOC_SNAP_CREATE_V2 \
9666 _IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
9669 #ifndef BTRFS_IOC_SUBVOL_CREATE_V2
9670 #define BTRFS_IOC_SUBVOL_CREATE_V2 \
9671 _IOW(BTRFS_IOCTL_MAGIC, 24, struct btrfs_ioctl_vol_args_v2)
9674 #ifndef BTRFS_IOC_SUBVOL_GETFLAGS
9675 #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
9678 #ifndef BTRFS_IOC_SUBVOL_SETFLAGS
9679 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
9682 #ifndef BTRFS_IOC_INO_LOOKUP
9683 #define BTRFS_IOC_INO_LOOKUP \
9684 _IOWR(BTRFS_IOCTL_MAGIC, 18, struct btrfs_ioctl_ino_lookup_args)
9687 #ifndef BTRFS_IOC_INO_LOOKUP_USER
9688 #define BTRFS_IOC_INO_LOOKUP_USER \
9689 _IOWR(BTRFS_IOCTL_MAGIC, 62, struct btrfs_ioctl_ino_lookup_user_args)
9692 #ifndef BTRFS_IOC_GET_SUBVOL_ROOTREF
9693 #define BTRFS_IOC_GET_SUBVOL_ROOTREF \
9694 _IOWR(BTRFS_IOCTL_MAGIC, 61, struct btrfs_ioctl_get_subvol_rootref_args)
9697 #ifndef BTRFS_SUBVOL_RDONLY
9698 #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
9701 #ifndef BTRFS_SUBVOL_SPEC_BY_ID
9702 #define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4)
9705 #ifndef BTRFS_FIRST_FREE_OBJECTID
9706 #define BTRFS_FIRST_FREE_OBJECTID 256ULL
9709 static int btrfs_delete_subvolume(int parent_fd, const char *name)
9711 struct btrfs_ioctl_vol_args args = {};
9716 if (len >= sizeof(args.name))
9717 return -ENAMETOOLONG;
9719 memcpy(args.name, name, len);
9720 args.name[len] = '\0';
9722 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY, &args);
9729 static int btrfs_delete_subvolume_id(int parent_fd, uint64_t subvolid)
9731 struct btrfs_ioctl_vol_args_v2 args = {};
9734 args.flags = BTRFS_SUBVOL_SPEC_BY_ID;
9735 args.subvolid = subvolid;
9737 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_DESTROY_V2, &args);
9744 static int btrfs_create_subvolume(int parent_fd, const char *name)
9746 struct btrfs_ioctl_vol_args_v2 args = {};
9751 if (len >= sizeof(args.name))
9752 return -ENAMETOOLONG;
9754 memcpy(args.name, name, len);
9755 args.name[len] = '\0';
9757 ret = ioctl(parent_fd, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
9764 static int btrfs_create_snapshot(int fd, int parent_fd, const char *name,
9767 struct btrfs_ioctl_vol_args_v2 args = {
9773 if (flags & ~BTRFS_SUBVOL_RDONLY)
9777 if (len >= sizeof(args.name))
9778 return -ENAMETOOLONG;
9779 memcpy(args.name, name, len);
9780 args.name[len] = '\0';
9782 if (flags & BTRFS_SUBVOL_RDONLY)
9783 args.flags |= BTRFS_SUBVOL_RDONLY;
9784 ret = ioctl(parent_fd, BTRFS_IOC_SNAP_CREATE_V2, &args);
9791 static int btrfs_get_subvolume_ro(int fd, bool *read_only_ret)
9796 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9800 *read_only_ret = flags & BTRFS_SUBVOL_RDONLY;
9804 static int btrfs_set_subvolume_ro(int fd, bool read_only)
9809 ret = ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
9814 flags |= BTRFS_SUBVOL_RDONLY;
9816 flags &= ~BTRFS_SUBVOL_RDONLY;
9818 ret = ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
9825 static int btrfs_get_subvolume_id(int fd, uint64_t *id_ret)
9827 struct btrfs_ioctl_ino_lookup_args args = {
9829 .objectid = BTRFS_FIRST_FREE_OBJECTID,
9833 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
9837 *id_ret = args.treeid;
9843 * The following helpers are adapted from the btrfsutils library. We can't use
9844 * the library directly since we need full control over how the subvolume
9845 * iteration happens. We need to be able to check whether unprivileged
9846 * subvolume iteration is possible, i.e. whether BTRFS_IOC_INO_LOOKUP_USER is
9847 * available and also ensure that it is actually used when looking up paths.
9849 struct btrfs_stack {
9851 struct btrfs_ioctl_get_subvol_rootref_args rootref_args;
9860 struct btrfs_stack *search_stack;
9862 size_t stack_capacity;
9865 size_t cur_path_capacity;
9868 static struct btrfs_stack *top_stack_entry(struct btrfs_iter *iter)
9870 return &iter->search_stack[iter->stack_len - 1];
9873 static int pop_stack(struct btrfs_iter *iter)
9875 struct btrfs_stack *top, *parent;
9879 if (iter->stack_len == 1) {
9884 top = top_stack_entry(iter);
9886 parent = top_stack_entry(iter);
9889 for (i = parent->path_len; i < top->path_len; i++) {
9890 if (i == 0 || iter->cur_path[i] == '/') {
9891 parent_fd = openat(fd, "..", O_RDONLY);
9892 if (fd != iter->cur_fd)
9894 if (parent_fd == -1)
9899 if (iter->cur_fd != iter->fd)
9900 close(iter->cur_fd);
9906 static int append_stack(struct btrfs_iter *iter, uint64_t tree_id, size_t path_len)
9908 struct btrfs_stack *entry;
9910 if (iter->stack_len >= iter->stack_capacity) {
9911 size_t new_capacity = iter->stack_capacity * 2;
9912 struct btrfs_stack *new_search_stack;
9913 #ifdef HAVE_REALLOCARRAY
9914 new_search_stack = reallocarray(iter->search_stack, new_capacity,
9915 sizeof(*iter->search_stack));
9917 new_search_stack = realloc(iter->search_stack, new_capacity * sizeof(*iter->search_stack));
9919 if (!new_search_stack)
9922 iter->stack_capacity = new_capacity;
9923 iter->search_stack = new_search_stack;
9926 entry = &iter->search_stack[iter->stack_len];
9928 memset(entry, 0, sizeof(*entry));
9929 entry->path_len = path_len;
9930 entry->tree_id = tree_id;
9932 if (iter->stack_len) {
9933 struct btrfs_stack *top;
9937 top = top_stack_entry(iter);
9938 path = &iter->cur_path[top->path_len];
9941 fd = openat(iter->cur_fd, path, O_RDONLY);
9945 close(iter->cur_fd);
9954 static int btrfs_iterator_start(int fd, uint64_t top, struct btrfs_iter **ret)
9956 struct btrfs_iter *iter;
9959 iter = malloc(sizeof(*iter));
9966 iter->stack_len = 0;
9967 iter->stack_capacity = 4;
9968 iter->search_stack = malloc(sizeof(*iter->search_stack) *
9969 iter->stack_capacity);
9970 if (!iter->search_stack) {
9975 iter->cur_path_capacity = 256;
9976 iter->cur_path = malloc(iter->cur_path_capacity);
9977 if (!iter->cur_path) {
9979 goto out_search_stack;
9982 err = append_stack(iter, top, 0);
9991 free(iter->cur_path);
9993 free(iter->search_stack);
9999 static void btrfs_iterator_end(struct btrfs_iter *iter)
10002 free(iter->cur_path);
10003 free(iter->search_stack);
10004 if (iter->cur_fd != iter->fd)
10005 close(iter->cur_fd);
10011 static int __append_path(struct btrfs_iter *iter, const char *name,
10012 size_t name_len, const char *dir, size_t dir_len,
10013 size_t *path_len_ret)
10015 struct btrfs_stack *top = top_stack_entry(iter);
10019 path_len = top->path_len;
10021 * We need a joining slash if we have a current path and a subdirectory.
10023 if (top->path_len && dir_len)
10025 path_len += dir_len;
10027 * We need another joining slash if we have a current path and a name,
10028 * but not if we have a subdirectory, because the lookup ioctl includes
10029 * a trailing slash.
10031 if (top->path_len && !dir_len && name_len)
10033 path_len += name_len;
10035 /* We need one extra character for the NUL terminator. */
10036 if (path_len + 1 > iter->cur_path_capacity) {
10037 char *tmp = realloc(iter->cur_path, path_len + 1);
10041 iter->cur_path = tmp;
10042 iter->cur_path_capacity = path_len + 1;
10045 p = iter->cur_path + top->path_len;
10046 if (top->path_len && dir_len)
10048 memcpy(p, dir, dir_len);
10050 if (top->path_len && !dir_len && name_len)
10052 memcpy(p, name, name_len);
10056 *path_len_ret = path_len;
10061 static int get_subvolume_path(struct btrfs_iter *iter, uint64_t treeid,
10062 uint64_t dirid, size_t *path_len_ret)
10064 struct btrfs_ioctl_ino_lookup_user_args args = {
10070 ret = ioctl(iter->cur_fd, BTRFS_IOC_INO_LOOKUP_USER, &args);
10074 return __append_path(iter, args.name, strlen(args.name), args.path,
10075 strlen(args.path), path_len_ret);
10078 static int btrfs_iterator_next(struct btrfs_iter *iter, char **path_ret,
10081 struct btrfs_stack *top;
10082 uint64_t treeid, dirid;
10088 if (iter->stack_len == 0)
10091 top = top_stack_entry(iter);
10092 if (top->items_pos < top->rootref_args.num_items) {
10095 ret = ioctl(iter->cur_fd,
10096 BTRFS_IOC_GET_SUBVOL_ROOTREF,
10097 &top->rootref_args);
10098 if (ret == -1 && errno != EOVERFLOW)
10100 top->items_pos = 0;
10102 if (top->rootref_args.num_items == 0) {
10103 err = pop_stack(iter);
10110 treeid = top->rootref_args.rootref[top->items_pos].treeid;
10111 dirid = top->rootref_args.rootref[top->items_pos].dirid;
10113 err = get_subvolume_path(iter, treeid, dirid, &path_len);
10115 /* Skip the subvolume if we can't access it. */
10116 if (errno == EACCES)
10121 err = append_stack(iter, treeid, path_len);
10124 * Skip the subvolume if it does not exist (which can
10125 * happen if there is another filesystem mounted over a
10126 * parent directory) or we don't have permission to
10129 if (errno == ENOENT || errno == EACCES)
10134 top = top_stack_entry(iter);
10140 *path_ret = malloc(top->path_len + 1);
10143 memcpy(*path_ret, iter->cur_path, top->path_len);
10144 (*path_ret)[top->path_len] = '\0';
10147 *id_ret = top->tree_id;
10151 #define BTRFS_SUBVOLUME1 "subvol1"
10152 #define BTRFS_SUBVOLUME1_SNAPSHOT1 "subvol1_snapshot1"
10153 #define BTRFS_SUBVOLUME1_SNAPSHOT1_RO "subvol1_snapshot1_ro"
10154 #define BTRFS_SUBVOLUME1_RENAME "subvol1_rename"
10155 #define BTRFS_SUBVOLUME2 "subvol2"
10157 static int btrfs_subvolumes_fsids_mapped(void)
10160 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10161 struct mount_attr attr = {
10162 .attr_set = MOUNT_ATTR_IDMAP,
10166 if (!caps_supported())
10169 /* Changing mount properties on a detached mount. */
10170 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10171 if (attr.userns_fd < 0) {
10172 log_stderr("failure: get_userns_fd");
10176 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10179 AT_SYMLINK_NOFOLLOW |
10180 OPEN_TREE_CLOEXEC |
10182 if (open_tree_fd < 0) {
10183 log_stderr("failure: sys_open_tree");
10187 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10188 log_stderr("failure: sys_mount_setattr");
10193 * The open_tree() syscall returns an O_PATH file descriptor which we
10194 * can't use with ioctl(). So let's reopen it as a proper file
10197 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10199 log_stderr("failure: openat");
10205 log_stderr("failure: fork");
10209 if (!switch_fsids(10000, 10000))
10210 die("failure: switch fsids");
10213 die("failure: raise caps");
10216 * The caller's fsids now have mappings in the idmapped mount so
10217 * any file creation must succeed.
10220 /* create subvolume */
10221 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10222 die("failure: btrfs_create_subvolume");
10224 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10225 die("failure: check ownership");
10227 /* remove subvolume */
10228 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10229 die("failure: btrfs_delete_subvolume");
10231 /* create subvolume */
10232 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10233 die("failure: btrfs_create_subvolume");
10235 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10236 die("failure: check ownership");
10239 die("failure: lower caps");
10242 * The filesystem is not mounted with user_subvol_rm_allowed so
10243 * subvolume deletion must fail.
10245 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10246 die("failure: btrfs_delete_subvolume");
10247 if (errno != EPERM)
10248 die("failure: errno");
10250 exit(EXIT_SUCCESS);
10252 if (wait_for_pid(pid))
10255 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10256 die("failure: check ownership");
10258 /* remove subvolume */
10259 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10260 log_stderr("failure: btrfs_delete_subvolume");
10265 log_debug("Ran test");
10267 safe_close(attr.userns_fd);
10268 safe_close(open_tree_fd);
10269 safe_close(tree_fd);
10274 static int btrfs_subvolumes_fsids_mapped_userns(void)
10277 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10278 struct mount_attr attr = {
10279 .attr_set = MOUNT_ATTR_IDMAP,
10283 if (!caps_supported())
10286 /* Changing mount properties on a detached mount. */
10287 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10288 if (attr.userns_fd < 0) {
10289 log_stderr("failure: get_userns_fd");
10293 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10296 AT_SYMLINK_NOFOLLOW |
10297 OPEN_TREE_CLOEXEC |
10299 if (open_tree_fd < 0) {
10300 log_stderr("failure: sys_open_tree");
10304 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10305 log_stderr("failure: sys_mount_setattr");
10310 * The open_tree() syscall returns an O_PATH file descriptor which we
10311 * can't use with ioctl(). So let's reopen it as a proper file
10314 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10316 log_stderr("failure: openat");
10322 log_stderr("failure: fork");
10326 if (!switch_userns(attr.userns_fd, 0, 0, false))
10327 die("failure: switch_userns");
10329 /* The caller's fsids now have mappings in the idmapped mount so
10330 * any file creation must fail.
10333 /* create subvolume */
10334 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10335 die("failure: btrfs_create_subvolume");
10337 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10338 die("failure: check ownership");
10340 /* remove subvolume */
10341 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10342 die("failure: btrfs_delete_subvolume");
10344 exit(EXIT_SUCCESS);
10346 if (wait_for_pid(pid))
10349 /* remove subvolume */
10350 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10351 log_stderr("failure: btrfs_delete_subvolume");
10356 log_debug("Ran test");
10358 safe_close(attr.userns_fd);
10359 safe_close(open_tree_fd);
10360 safe_close(tree_fd);
10365 static int btrfs_subvolumes_fsids_unmapped(void)
10368 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10369 struct mount_attr attr = {
10370 .attr_set = MOUNT_ATTR_IDMAP,
10373 /* create directory for rename test */
10374 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10375 log_stderr("failure: btrfs_create_subvolume");
10379 /* change ownership of all files to uid 0 */
10380 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10381 log_stderr("failure: fchownat");
10385 /* Changing mount properties on a detached mount. */
10386 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10387 if (attr.userns_fd < 0) {
10388 log_stderr("failure: get_userns_fd");
10392 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10395 AT_SYMLINK_NOFOLLOW |
10396 OPEN_TREE_CLOEXEC |
10398 if (open_tree_fd < 0) {
10399 log_stderr("failure: sys_open_tree");
10403 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10404 log_stderr("failure: sys_mount_setattr");
10408 if (!switch_fsids(0, 0)) {
10409 log_stderr("failure: switch_fsids");
10414 * The caller's fsids don't have a mappings in the idmapped mount so
10415 * any file creation must fail.
10419 * The open_tree() syscall returns an O_PATH file descriptor which we
10420 * can't use with ioctl(). So let's reopen it as a proper file
10423 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10425 log_stderr("failure: openat");
10429 /* create subvolume */
10430 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2)) {
10431 log_stderr("failure: btrfs_create_subvolume");
10434 if (errno != EOVERFLOW) {
10435 log_stderr("failure: errno");
10439 /* try to rename a subvolume */
10440 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10441 BTRFS_SUBVOLUME1_RENAME)) {
10442 log_stderr("failure: renameat");
10445 if (errno != EOVERFLOW) {
10446 log_stderr("failure: errno");
10450 /* The caller is privileged over the inode so file deletion must work. */
10452 /* remove subvolume */
10453 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10454 log_stderr("failure: btrfs_delete_subvolume");
10459 log_debug("Ran test");
10461 safe_close(attr.userns_fd);
10462 safe_close(open_tree_fd);
10463 safe_close(tree_fd);
10468 static int btrfs_subvolumes_fsids_unmapped_userns(void)
10471 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
10472 struct mount_attr attr = {
10473 .attr_set = MOUNT_ATTR_IDMAP,
10477 /* create directory for rename test */
10478 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10479 log_stderr("failure: btrfs_create_subvolume");
10483 /* change ownership of all files to uid 0 */
10484 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10485 log_stderr("failure: fchownat");
10489 /* Changing mount properties on a detached mount. */
10490 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10491 if (attr.userns_fd < 0) {
10492 log_stderr("failure: get_userns_fd");
10496 /* Changing mount properties on a detached mount. */
10497 userns_fd = get_userns_fd(0, 30000, 10000);
10498 if (userns_fd < 0) {
10499 log_stderr("failure: get_userns_fd");
10503 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10506 AT_SYMLINK_NOFOLLOW |
10507 OPEN_TREE_CLOEXEC |
10509 if (open_tree_fd < 0) {
10510 log_stderr("failure: sys_open_tree");
10514 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10515 log_stderr("failure: sys_mount_setattr");
10520 * The open_tree() syscall returns an O_PATH file descriptor which we
10521 * can't use with ioctl(). So let's reopen it as a proper file
10524 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10526 log_stderr("failure: openat");
10532 log_stderr("failure: fork");
10536 if (!switch_userns(userns_fd, 0, 0, false))
10537 die("failure: switch_userns");
10539 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
10540 t_overflowuid, t_overflowgid))
10541 die("failure: expected_uid_gid");
10543 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
10544 t_overflowuid, t_overflowgid))
10545 die("failure: expected_uid_gid");
10548 * The caller's fsids don't have a mappings in the idmapped mount so
10549 * any file creation must fail.
10552 /* create subvolume */
10553 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
10554 die("failure: btrfs_create_subvolume");
10555 if (errno != EOVERFLOW)
10556 die("failure: errno");
10558 /* try to rename a subvolume */
10559 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
10560 BTRFS_SUBVOLUME1_RENAME))
10561 die("failure: renameat");
10562 if (errno != EOVERFLOW)
10563 die("failure: errno");
10566 * The caller is not privileged over the inode so subvolume
10567 * deletion must fail.
10570 /* remove subvolume */
10571 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10572 die("failure: btrfs_delete_subvolume");
10574 exit(EXIT_SUCCESS);
10576 if (wait_for_pid(pid))
10579 /* remove subvolume */
10580 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10581 log_stderr("failure: btrfs_delete_subvolume");
10586 log_debug("Ran test");
10588 safe_close(attr.userns_fd);
10589 safe_close(open_tree_fd);
10590 safe_close(tree_fd);
10591 safe_close(userns_fd);
10596 static int btrfs_snapshots_fsids_mapped(void)
10599 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10600 struct mount_attr attr = {
10601 .attr_set = MOUNT_ATTR_IDMAP,
10605 if (!caps_supported())
10608 /* Changing mount properties on a detached mount. */
10609 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10610 if (attr.userns_fd < 0) {
10611 log_stderr("failure: get_userns_fd");
10615 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10618 AT_SYMLINK_NOFOLLOW |
10619 OPEN_TREE_CLOEXEC |
10621 if (open_tree_fd < 0) {
10622 log_stderr("failure: sys_open_tree");
10626 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10627 log_stderr("failure: sys_mount_setattr");
10632 * The open_tree() syscall returns an O_PATH file descriptor which we
10633 * can't use with ioctl(). So let's reopen it as a proper file
10636 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10638 log_stderr("failure: openat");
10644 log_stderr("failure: fork");
10648 int subvolume_fd = -EBADF;
10650 if (!switch_fsids(10000, 10000))
10651 die("failure: switch fsids");
10654 die("failure: raise caps");
10656 /* The caller's fsids now have mappings in the idmapped mount so
10657 * any file creation must fail.
10660 /* create subvolume */
10661 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10662 die("failure: btrfs_create_subvolume");
10664 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10665 die("failure: expected_uid_gid");
10667 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10668 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10669 if (subvolume_fd < 0)
10670 die("failure: openat");
10672 /* create read-write snapshot */
10673 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10674 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10675 die("failure: btrfs_create_snapshot");
10677 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10678 die("failure: expected_uid_gid");
10680 /* create read-only snapshot */
10681 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10682 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10683 BTRFS_SUBVOL_RDONLY))
10684 die("failure: btrfs_create_snapshot");
10686 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10687 die("failure: expected_uid_gid");
10689 safe_close(subvolume_fd);
10691 /* remove subvolume */
10692 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10693 die("failure: btrfs_delete_subvolume");
10695 /* remove read-write snapshot */
10696 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
10697 die("failure: btrfs_delete_subvolume");
10699 /* remove read-only snapshot */
10700 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
10701 die("failure: btrfs_delete_subvolume");
10703 /* create directory */
10704 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10705 die("failure: btrfs_create_subvolume");
10707 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10708 die("failure: expected_uid_gid");
10710 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10711 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10712 if (subvolume_fd < 0)
10713 die("failure: openat");
10715 /* create read-write snapshot */
10716 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10717 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10718 die("failure: btrfs_create_snapshot");
10720 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10721 die("failure: expected_uid_gid");
10723 /* create read-only snapshot */
10724 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10725 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10726 BTRFS_SUBVOL_RDONLY))
10727 die("failure: btrfs_create_snapshot");
10729 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10730 die("failure: expected_uid_gid");
10732 safe_close(subvolume_fd);
10734 exit(EXIT_SUCCESS);
10736 if (wait_for_pid(pid))
10739 /* remove directory */
10740 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10741 log_stderr("failure: btrfs_delete_subvolume");
10745 /* remove read-write snapshot */
10746 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10747 log_stderr("failure: btrfs_delete_subvolume");
10751 /* remove read-only snapshot */
10752 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10753 log_stderr("failure: btrfs_delete_subvolume");
10758 log_debug("Ran test");
10760 safe_close(attr.userns_fd);
10761 safe_close(open_tree_fd);
10762 safe_close(tree_fd);
10767 static int btrfs_snapshots_fsids_mapped_userns(void)
10770 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10771 struct mount_attr attr = {
10772 .attr_set = MOUNT_ATTR_IDMAP,
10776 if (!caps_supported())
10779 /* Changing mount properties on a detached mount. */
10780 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10781 if (attr.userns_fd < 0) {
10782 log_stderr("failure: get_userns_fd");
10786 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10789 AT_SYMLINK_NOFOLLOW |
10790 OPEN_TREE_CLOEXEC |
10792 if (open_tree_fd < 0) {
10793 log_stderr("failure: sys_open_tree");
10797 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
10798 log_stderr("failure: sys_mount_setattr");
10803 * The open_tree() syscall returns an O_PATH file descriptor which we
10804 * can't use with ioctl(). So let's reopen it as a proper file
10807 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10809 log_stderr("failure: openat");
10815 log_stderr("failure: fork");
10819 int subvolume_fd = -EBADF;
10821 if (!switch_userns(attr.userns_fd, 0, 0, false))
10822 die("failure: switch_userns");
10824 /* create subvolume */
10825 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
10826 die("failure: btrfs_create_subvolume");
10828 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
10829 die("failure: expected_uid_gid");
10831 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10832 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10833 if (subvolume_fd < 0)
10834 die("failure: openat");
10836 /* create read-write snapshot */
10837 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10838 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10839 die("failure: btrfs_create_snapshot");
10841 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
10842 die("failure: expected_uid_gid");
10844 /* create read-only snapshot */
10845 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
10846 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10847 BTRFS_SUBVOL_RDONLY))
10848 die("failure: btrfs_create_snapshot");
10850 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
10851 die("failure: expected_uid_gid");
10853 safe_close(subvolume_fd);
10855 exit(EXIT_SUCCESS);
10857 if (wait_for_pid(pid))
10860 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
10861 die("failure: expected_uid_gid");
10863 /* remove directory */
10864 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
10865 log_stderr("failure: btrfs_delete_subvolume");
10869 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
10870 die("failure: expected_uid_gid");
10872 /* remove read-write snapshot */
10873 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
10874 log_stderr("failure: btrfs_delete_subvolume");
10878 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
10879 die("failure: expected_uid_gid");
10881 /* remove read-only snapshot */
10882 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO)) {
10883 log_stderr("failure: btrfs_delete_subvolume");
10888 log_debug("Ran test");
10890 safe_close(attr.userns_fd);
10891 safe_close(open_tree_fd);
10892 safe_close(tree_fd);
10897 static int btrfs_snapshots_fsids_unmapped(void)
10900 int open_tree_fd = -EBADF, tree_fd = -EBADF;
10901 struct mount_attr attr = {
10902 .attr_set = MOUNT_ATTR_IDMAP,
10906 if (!caps_supported())
10909 /* create directory for rename test */
10910 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
10911 log_stderr("failure: btrfs_create_subvolume");
10915 /* change ownership of all files to uid 0 */
10916 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
10917 log_stderr("failure: fchownat");
10921 /* Changing mount properties on a detached mount. */
10922 attr.userns_fd = get_userns_fd(0, 10000, 10000);
10923 if (attr.userns_fd < 0) {
10924 log_stderr("failure: get_userns_fd");
10928 open_tree_fd = sys_open_tree(t_dir1_fd, "",
10931 AT_SYMLINK_NOFOLLOW |
10932 OPEN_TREE_CLOEXEC |
10934 if (open_tree_fd < 0) {
10935 log_stderr("failure: sys_open_tree");
10939 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
10941 log_stderr("failure: sys_mount_setattr");
10947 log_stderr("failure: fork");
10951 int subvolume_fd = -EBADF;
10953 if (!switch_fsids(0, 0)) {
10954 log_stderr("failure: switch_fsids");
10959 * The caller's fsids don't have a mappings in the idmapped
10960 * mount so any file creation must fail.
10964 * The open_tree() syscall returns an O_PATH file descriptor
10965 * which we can't use with ioctl(). So let's reopen it as a
10966 * proper file descriptor.
10968 tree_fd = openat(open_tree_fd, ".",
10969 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10971 die("failure: openat");
10973 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
10974 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
10975 if (subvolume_fd < 0)
10976 die("failure: openat");
10978 /* create directory */
10979 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
10980 die("failure: btrfs_create_subvolume");
10981 if (errno != EOVERFLOW)
10982 die("failure: errno");
10984 /* create read-write snapshot */
10985 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
10986 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
10987 die("failure: btrfs_create_snapshot");
10988 if (errno != EOVERFLOW)
10989 die("failure: errno");
10991 /* create read-only snapshot */
10992 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
10993 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
10994 BTRFS_SUBVOL_RDONLY))
10995 die("failure: btrfs_create_snapshot");
10996 if (errno != EOVERFLOW)
10997 die("failure: errno");
10999 /* try to rename a directory */
11000 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11001 BTRFS_SUBVOLUME1_RENAME))
11002 die("failure: renameat");
11003 if (errno != EOVERFLOW)
11004 die("failure: errno");
11007 die("failure: caps_down");
11009 /* create read-write snapshot */
11010 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11011 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11012 die("failure: btrfs_create_snapshot");
11013 if (errno != EPERM)
11014 die("failure: errno");
11016 /* create read-only snapshot */
11017 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11018 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11019 BTRFS_SUBVOL_RDONLY))
11020 die("failure: btrfs_create_snapshot");
11021 if (errno != EPERM)
11022 die("failure: errno");
11025 * The caller is not privileged over the inode so subvolume
11026 * deletion must fail.
11029 /* remove directory */
11030 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11031 die("failure: btrfs_delete_subvolume");
11032 if (errno != EPERM)
11033 die("failure: errno");
11036 die("failure: caps_down");
11039 * The caller is privileged over the inode so subvolume
11040 * deletion must work.
11043 /* remove directory */
11044 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11045 die("failure: btrfs_delete_subvolume");
11047 exit(EXIT_SUCCESS);
11049 if (wait_for_pid(pid))
11053 log_debug("Ran test");
11055 safe_close(attr.userns_fd);
11056 safe_close(open_tree_fd);
11057 safe_close(tree_fd);
11062 static int btrfs_snapshots_fsids_unmapped_userns(void)
11065 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
11066 userns_fd = -EBADF;
11067 struct mount_attr attr = {
11068 .attr_set = MOUNT_ATTR_IDMAP,
11072 if (!caps_supported())
11075 /* create directory for rename test */
11076 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
11077 log_stderr("failure: btrfs_create_subvolume");
11081 /* change ownership of all files to uid 0 */
11082 if (fchownat(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
11083 log_stderr("failure: fchownat");
11087 /* Changing mount properties on a detached mount. */
11088 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11089 if (attr.userns_fd < 0) {
11090 log_stderr("failure: get_userns_fd");
11094 /* Changing mount properties on a detached mount. */
11095 userns_fd = get_userns_fd(0, 30000, 10000);
11096 if (userns_fd < 0) {
11097 log_stderr("failure: get_userns_fd");
11101 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11104 AT_SYMLINK_NOFOLLOW |
11105 OPEN_TREE_CLOEXEC |
11107 if (open_tree_fd < 0) {
11108 log_stderr("failure: sys_open_tree");
11112 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr,
11114 log_stderr("failure: sys_mount_setattr");
11119 * The open_tree() syscall returns an O_PATH file descriptor
11120 * which we can't use with ioctl(). So let's reopen it as a
11121 * proper file descriptor.
11123 tree_fd = openat(open_tree_fd, ".",
11124 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11126 log_stderr("failure: openat");
11130 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11131 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11132 if (subvolume_fd < 0) {
11133 log_stderr("failure: openat");
11139 log_stderr("failure: fork");
11143 if (!switch_userns(userns_fd, 0, 0, false))
11144 die("failure: switch_userns");
11146 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
11147 t_overflowuid, t_overflowgid))
11148 die("failure: expected_uid_gid");
11150 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
11151 t_overflowuid, t_overflowgid))
11152 die("failure: expected_uid_gid");
11155 * The caller's fsids don't have a mappings in the idmapped
11156 * mount so any file creation must fail.
11159 /* create directory */
11160 if (!btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME2))
11161 die("failure: btrfs_create_subvolume");
11162 if (errno != EOVERFLOW)
11163 die("failure: errno");
11165 /* create read-write snapshot */
11166 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11167 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11168 die("failure: btrfs_create_snapshot");
11169 if (errno != EPERM)
11170 die("failure: errno");
11172 /* create read-only snapshot */
11173 if (!btrfs_create_snapshot(subvolume_fd, tree_fd,
11174 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11175 BTRFS_SUBVOL_RDONLY))
11176 die("failure: btrfs_create_snapshot");
11177 if (errno != EPERM)
11178 die("failure: errno");
11180 /* try to rename a directory */
11181 if (!renameat(open_tree_fd, BTRFS_SUBVOLUME1, open_tree_fd,
11182 BTRFS_SUBVOLUME1_RENAME))
11183 die("failure: renameat");
11184 if (errno != EOVERFLOW)
11185 die("failure: errno");
11188 * The caller is not privileged over the inode so subvolume
11189 * deletion must fail.
11192 /* remove directory */
11193 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11194 die("failure: btrfs_delete_subvolume");
11195 if (errno != EPERM)
11196 die("failure: errno");
11198 exit(EXIT_SUCCESS);
11200 if (wait_for_pid(pid))
11203 /* remove directory */
11204 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11205 die("failure: btrfs_delete_subvolume");
11208 log_debug("Ran test");
11210 safe_close(attr.userns_fd);
11211 safe_close(open_tree_fd);
11212 safe_close(subvolume_fd);
11213 safe_close(tree_fd);
11218 static int btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed(void)
11221 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11222 struct mount_attr attr = {
11223 .attr_set = MOUNT_ATTR_IDMAP,
11227 if (!caps_supported())
11230 /* Changing mount properties on a detached mount. */
11231 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11232 if (attr.userns_fd < 0) {
11233 log_stderr("failure: get_userns_fd");
11237 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11240 AT_SYMLINK_NOFOLLOW |
11241 OPEN_TREE_CLOEXEC |
11243 if (open_tree_fd < 0) {
11244 log_stderr("failure: sys_open_tree");
11248 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11249 log_stderr("failure: sys_mount_setattr");
11254 * The open_tree() syscall returns an O_PATH file descriptor which we
11255 * can't use with ioctl(). So let's reopen it as a proper file
11258 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11260 log_stderr("failure: openat");
11266 log_stderr("failure: fork");
11270 if (!switch_fsids(10000, 10000))
11271 die("failure: switch fsids");
11274 die("failure: raise caps");
11277 * The caller's fsids now have mappings in the idmapped mount so
11278 * any file creation must succedd.
11281 /* create subvolume */
11282 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11283 die("failure: btrfs_create_subvolume");
11285 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11286 die("failure: check ownership");
11289 * The scratch device is mounted with user_subvol_rm_allowed so
11290 * subvolume deletion must succeed.
11292 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11293 die("failure: btrfs_delete_subvolume");
11295 exit(EXIT_SUCCESS);
11297 if (wait_for_pid(pid))
11301 log_debug("Ran test");
11303 safe_close(attr.userns_fd);
11304 safe_close(open_tree_fd);
11305 safe_close(tree_fd);
11310 static int btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed(void)
11313 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11314 struct mount_attr attr = {
11315 .attr_set = MOUNT_ATTR_IDMAP,
11319 if (!caps_supported())
11322 /* Changing mount properties on a detached mount. */
11323 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11324 if (attr.userns_fd < 0) {
11325 log_stderr("failure: get_userns_fd");
11329 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11332 AT_SYMLINK_NOFOLLOW |
11333 OPEN_TREE_CLOEXEC |
11335 if (open_tree_fd < 0) {
11336 log_stderr("failure: sys_open_tree");
11340 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11341 log_stderr("failure: sys_mount_setattr");
11346 * The open_tree() syscall returns an O_PATH file descriptor which we
11347 * can't use with ioctl(). So let's reopen it as a proper file
11350 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11352 log_stderr("failure: openat");
11358 log_stderr("failure: fork");
11362 if (!switch_userns(attr.userns_fd, 0, 0, false))
11363 die("failure: switch_userns");
11365 /* The caller's fsids now have mappings in the idmapped mount so
11366 * any file creation must fail.
11369 /* create subvolume */
11370 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11371 die("failure: btrfs_create_subvolume");
11373 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11374 die("failure: check ownership");
11377 * The scratch device is mounted with user_subvol_rm_allowed so
11378 * subvolume deletion must succeed.
11380 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11381 die("failure: btrfs_delete_subvolume");
11383 exit(EXIT_SUCCESS);
11385 if (wait_for_pid(pid))
11389 log_debug("Ran test");
11391 safe_close(attr.userns_fd);
11392 safe_close(open_tree_fd);
11393 safe_close(tree_fd);
11398 static int btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed(void)
11401 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11402 struct mount_attr attr = {
11403 .attr_set = MOUNT_ATTR_IDMAP,
11407 if (!caps_supported())
11410 /* Changing mount properties on a detached mount. */
11411 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11412 if (attr.userns_fd < 0) {
11413 log_stderr("failure: get_userns_fd");
11417 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11420 AT_SYMLINK_NOFOLLOW |
11421 OPEN_TREE_CLOEXEC |
11423 if (open_tree_fd < 0) {
11424 log_stderr("failure: sys_open_tree");
11428 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11429 log_stderr("failure: sys_mount_setattr");
11434 * The open_tree() syscall returns an O_PATH file descriptor which we
11435 * can't use with ioctl(). So let's reopen it as a proper file
11438 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11440 log_stderr("failure: openat");
11446 log_stderr("failure: fork");
11450 int subvolume_fd = -EBADF;
11452 if (!switch_fsids(10000, 10000))
11453 die("failure: switch fsids");
11456 die("failure: raise caps");
11459 * The caller's fsids now have mappings in the idmapped mount so
11460 * any file creation must succeed.
11463 /* create subvolume */
11464 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11465 die("failure: btrfs_create_subvolume");
11467 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11468 die("failure: expected_uid_gid");
11470 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11471 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11472 if (subvolume_fd < 0)
11473 die("failure: openat");
11475 /* create read-write snapshot */
11476 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11477 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11478 die("failure: btrfs_create_snapshot");
11480 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
11481 die("failure: expected_uid_gid");
11483 /* create read-only snapshot */
11484 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11485 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11486 BTRFS_SUBVOL_RDONLY))
11487 die("failure: btrfs_create_snapshot");
11489 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 10000, 10000))
11490 die("failure: expected_uid_gid");
11492 safe_close(subvolume_fd);
11494 /* remove subvolume */
11495 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11496 die("failure: btrfs_delete_subvolume");
11498 /* remove read-write snapshot */
11499 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11500 die("failure: btrfs_delete_subvolume");
11502 /* remove read-only snapshot */
11503 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11504 die("failure: btrfs_delete_subvolume");
11506 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11507 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11508 if (subvolume_fd < 0)
11509 die("failure: openat");
11511 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11512 die("failure: btrfs_set_subvolume_ro");
11514 safe_close(subvolume_fd);
11516 /* remove read-only snapshot */
11517 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11518 die("failure: btrfs_delete_subvolume");
11520 exit(EXIT_SUCCESS);
11522 if (wait_for_pid(pid))
11526 log_debug("Ran test");
11528 safe_close(attr.userns_fd);
11529 safe_close(open_tree_fd);
11530 safe_close(tree_fd);
11535 static int btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed(void)
11538 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11539 struct mount_attr attr = {
11540 .attr_set = MOUNT_ATTR_IDMAP,
11544 if (!caps_supported())
11547 /* Changing mount properties on a detached mount. */
11548 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11549 if (attr.userns_fd < 0) {
11550 log_stderr("failure: get_userns_fd");
11554 open_tree_fd = sys_open_tree(t_mnt_scratch_fd, "",
11557 AT_SYMLINK_NOFOLLOW |
11558 OPEN_TREE_CLOEXEC |
11560 if (open_tree_fd < 0) {
11561 log_stderr("failure: sys_open_tree");
11565 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11566 log_stderr("failure: sys_mount_setattr");
11571 * The open_tree() syscall returns an O_PATH file descriptor which we
11572 * can't use with ioctl(). So let's reopen it as a proper file
11575 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11577 log_stderr("failure: openat");
11583 log_stderr("failure: fork");
11587 int subvolume_fd = -EBADF;
11589 if (!switch_userns(attr.userns_fd, 0, 0, false))
11590 die("failure: switch_userns");
11592 /* create subvolume */
11593 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11594 die("failure: btrfs_create_subvolume");
11596 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11597 die("failure: expected_uid_gid");
11599 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11600 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11601 if (subvolume_fd < 0)
11602 die("failure: openat");
11604 /* create read-write snapshot */
11605 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11606 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
11607 die("failure: btrfs_create_snapshot");
11609 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11610 die("failure: expected_uid_gid");
11612 /* create read-only snapshot */
11613 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
11614 BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11615 BTRFS_SUBVOL_RDONLY))
11616 die("failure: btrfs_create_snapshot");
11618 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11619 die("failure: expected_uid_gid");
11621 /* remove directory */
11622 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11623 die("failure: btrfs_delete_subvolume");
11625 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
11626 die("failure: expected_uid_gid");
11628 /* remove read-write snapshot */
11629 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1))
11630 die("failure: btrfs_delete_subvolume");
11632 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO, 0, 0, 0))
11633 die("failure: expected_uid_gid");
11635 /* remove read-only snapshot */
11636 if (!btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11637 die("failure: btrfs_delete_subvolume");
11639 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO,
11640 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11641 if (subvolume_fd < 0)
11642 die("failure: openat");
11644 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11645 die("failure: btrfs_set_subvolume_ro");
11647 safe_close(subvolume_fd);
11649 /* remove read-only snapshot */
11650 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1_RO))
11651 die("failure: btrfs_delete_subvolume");
11653 exit(EXIT_SUCCESS);
11655 if (wait_for_pid(pid))
11659 log_debug("Ran test");
11661 safe_close(attr.userns_fd);
11662 safe_close(open_tree_fd);
11663 safe_close(tree_fd);
11668 static int btrfs_delete_by_spec_id(void)
11671 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
11672 uint64_t subvolume_id1 = -EINVAL, subvolume_id2 = -EINVAL;
11673 struct mount_attr attr = {
11674 .attr_set = MOUNT_ATTR_IDMAP,
11678 /* Changing mount properties on a detached mount. */
11679 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11680 if (attr.userns_fd < 0) {
11681 log_stderr("failure: get_userns_fd");
11685 /* create subvolume */
11686 if (btrfs_create_subvolume(t_mnt_scratch_fd, "A")) {
11687 log_stderr("failure: btrfs_create_subvolume");
11691 /* create subvolume */
11692 if (btrfs_create_subvolume(t_mnt_scratch_fd, "B")) {
11693 log_stderr("failure: btrfs_create_subvolume");
11697 subvolume_fd = openat(t_mnt_scratch_fd, "B", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11698 if (subvolume_fd < 0) {
11699 log_stderr("failure: openat");
11703 /* create subvolume */
11704 if (btrfs_create_subvolume(subvolume_fd, "C")) {
11705 log_stderr("failure: btrfs_create_subvolume");
11709 safe_close(subvolume_fd);
11711 subvolume_fd = openat(t_mnt_scratch_fd, "A", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11712 if (subvolume_fd < 0) {
11713 log_stderr("failure: openat");
11717 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id1)) {
11718 log_stderr("failure: btrfs_get_subvolume_id");
11722 subvolume_fd = openat(t_mnt_scratch_fd, "B/C", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11723 if (subvolume_fd < 0) {
11724 log_stderr("failure: openat");
11728 if (btrfs_get_subvolume_id(subvolume_fd, &subvolume_id2)) {
11729 log_stderr("failure: btrfs_get_subvolume_id");
11733 if (sys_mount(t_device_scratch, t_mountpoint, "btrfs", 0, "subvol=B/C")) {
11734 log_stderr("failure: mount");
11738 open_tree_fd = sys_open_tree(-EBADF, t_mountpoint,
11740 AT_SYMLINK_NOFOLLOW |
11741 OPEN_TREE_CLOEXEC |
11743 if (open_tree_fd < 0) {
11744 log_stderr("failure: sys_open_tree");
11748 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11749 log_stderr("failure: sys_mount_setattr");
11754 * The open_tree() syscall returns an O_PATH file descriptor which we
11755 * can't use with ioctl(). So let's reopen it as a proper file
11758 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11760 log_stderr("failure: openat");
11766 log_stderr("failure: fork");
11771 * The subvolume isn't exposed in the idmapped mount so
11772 * delation via spec id must fail.
11774 if (!btrfs_delete_subvolume_id(tree_fd, subvolume_id1))
11775 die("failure: btrfs_delete_subvolume_id");
11776 if (errno != EOPNOTSUPP)
11777 die("failure: errno");
11779 if (btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id1))
11780 die("failure: btrfs_delete_subvolume_id");
11782 exit(EXIT_SUCCESS);
11784 if (wait_for_pid(pid))
11788 log_debug("Ran test");
11790 safe_close(attr.userns_fd);
11791 safe_close(open_tree_fd);
11792 safe_close(tree_fd);
11793 sys_umount2(t_mountpoint, MNT_DETACH);
11794 btrfs_delete_subvolume_id(t_mnt_scratch_fd, subvolume_id2);
11795 btrfs_delete_subvolume(t_mnt_scratch_fd, "B");
11800 static int btrfs_subvolumes_setflags_fsids_mapped(void)
11803 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11804 struct mount_attr attr = {
11805 .attr_set = MOUNT_ATTR_IDMAP,
11809 if (!caps_supported())
11812 /* Changing mount properties on a detached mount. */
11813 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11814 if (attr.userns_fd < 0) {
11815 log_stderr("failure: get_userns_fd");
11819 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11822 AT_SYMLINK_NOFOLLOW |
11823 OPEN_TREE_CLOEXEC |
11825 if (open_tree_fd < 0) {
11826 log_stderr("failure: sys_open_tree");
11830 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11831 log_stderr("failure: sys_mount_setattr");
11836 * The open_tree() syscall returns an O_PATH file descriptor which we
11837 * can't use with ioctl(). So let's reopen it as a proper file
11840 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11842 log_stderr("failure: openat");
11848 log_stderr("failure: fork");
11852 int subvolume_fd = -EBADF;
11853 bool read_only = false;
11855 if (!switch_fsids(10000, 10000))
11856 die("failure: switch fsids");
11859 die("failure: raise caps");
11861 /* The caller's fsids now have mappings in the idmapped mount so
11862 * any file creation must fail.
11865 /* create subvolume */
11866 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11867 die("failure: btrfs_create_subvolume");
11869 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
11870 die("failure: expected_uid_gid");
11872 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11873 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11874 if (subvolume_fd < 0)
11875 die("failure: openat");
11877 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11878 die("failure: btrfs_get_subvolume_ro");
11881 die("failure: read_only");
11883 if (btrfs_set_subvolume_ro(subvolume_fd, true))
11884 die("failure: btrfs_set_subvolume_ro");
11886 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11887 die("failure: btrfs_get_subvolume_ro");
11890 die("failure: not read_only");
11892 if (btrfs_set_subvolume_ro(subvolume_fd, false))
11893 die("failure: btrfs_set_subvolume_ro");
11895 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11896 die("failure: btrfs_get_subvolume_ro");
11899 die("failure: read_only");
11901 safe_close(subvolume_fd);
11903 exit(EXIT_SUCCESS);
11905 if (wait_for_pid(pid))
11908 /* remove directory */
11909 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
11910 log_stderr("failure: btrfs_delete_subvolume");
11915 log_debug("Ran test");
11917 safe_close(attr.userns_fd);
11918 safe_close(open_tree_fd);
11919 safe_close(tree_fd);
11924 static int btrfs_subvolumes_setflags_fsids_mapped_userns(void)
11927 int open_tree_fd = -EBADF, tree_fd = -EBADF;
11928 struct mount_attr attr = {
11929 .attr_set = MOUNT_ATTR_IDMAP,
11933 if (!caps_supported())
11936 /* Changing mount properties on a detached mount. */
11937 attr.userns_fd = get_userns_fd(0, 10000, 10000);
11938 if (attr.userns_fd < 0) {
11939 log_stderr("failure: get_userns_fd");
11943 open_tree_fd = sys_open_tree(t_dir1_fd, "",
11946 AT_SYMLINK_NOFOLLOW |
11947 OPEN_TREE_CLOEXEC |
11949 if (open_tree_fd < 0) {
11950 log_stderr("failure: sys_open_tree");
11954 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
11955 log_stderr("failure: sys_mount_setattr");
11960 * The open_tree() syscall returns an O_PATH file descriptor which we
11961 * can't use with ioctl(). So let's reopen it as a proper file
11964 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11966 log_stderr("failure: openat");
11972 log_stderr("failure: fork");
11976 int subvolume_fd = -EBADF;
11977 bool read_only = false;
11979 if (!switch_userns(attr.userns_fd, 0, 0, false))
11980 die("failure: switch_userns");
11982 /* The caller's fsids now have mappings in the idmapped mount so
11983 * any file creation must fail.
11986 /* create subvolume */
11987 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
11988 die("failure: btrfs_create_subvolume");
11990 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
11991 die("failure: expected_uid_gid");
11993 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
11994 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
11995 if (subvolume_fd < 0)
11996 die("failure: openat");
11998 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
11999 die("failure: btrfs_get_subvolume_ro");
12002 die("failure: read_only");
12004 if (btrfs_set_subvolume_ro(subvolume_fd, true))
12005 die("failure: btrfs_set_subvolume_ro");
12007 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12008 die("failure: btrfs_get_subvolume_ro");
12011 die("failure: not read_only");
12013 if (btrfs_set_subvolume_ro(subvolume_fd, false))
12014 die("failure: btrfs_set_subvolume_ro");
12016 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12017 die("failure: btrfs_get_subvolume_ro");
12020 die("failure: read_only");
12022 safe_close(subvolume_fd);
12024 exit(EXIT_SUCCESS);
12026 if (wait_for_pid(pid))
12029 /* remove directory */
12030 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12031 log_stderr("failure: btrfs_delete_subvolume");
12036 log_debug("Ran test");
12038 safe_close(attr.userns_fd);
12039 safe_close(open_tree_fd);
12040 safe_close(tree_fd);
12045 static int btrfs_subvolumes_setflags_fsids_unmapped(void)
12048 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12049 struct mount_attr attr = {
12050 .attr_set = MOUNT_ATTR_IDMAP,
12054 if (!caps_supported())
12057 /* Changing mount properties on a detached mount. */
12058 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12059 if (attr.userns_fd < 0) {
12060 log_stderr("failure: get_userns_fd");
12064 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12067 AT_SYMLINK_NOFOLLOW |
12068 OPEN_TREE_CLOEXEC |
12070 if (open_tree_fd < 0) {
12071 log_stderr("failure: sys_open_tree");
12075 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12076 log_stderr("failure: sys_mount_setattr");
12081 * The open_tree() syscall returns an O_PATH file descriptor which we
12082 * can't use with ioctl(). So let's reopen it as a proper file
12085 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12087 log_stderr("failure: openat");
12091 /* create subvolume */
12092 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12093 log_stderr("failure: btrfs_create_subvolume");
12097 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12098 log_stderr("failure: expected_uid_gid");
12102 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12103 log_stderr("failure: expected_uid_gid");
12109 log_stderr("failure: fork");
12113 int subvolume_fd = -EBADF;
12114 bool read_only = false;
12116 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12117 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12118 if (subvolume_fd < 0)
12119 die("failure: openat");
12121 if (!switch_fsids(0, 0))
12122 die("failure: switch fsids");
12125 die("failure: raise caps");
12128 * The caller's fsids don't have mappings in the idmapped mount
12129 * so any file creation must fail.
12132 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12133 die("failure: btrfs_get_subvolume_ro");
12136 die("failure: read_only");
12138 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12139 die("failure: btrfs_set_subvolume_ro");
12140 if (errno != EPERM)
12141 die("failure: errno");
12143 safe_close(subvolume_fd);
12145 exit(EXIT_SUCCESS);
12147 if (wait_for_pid(pid))
12150 /* remove directory */
12151 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12152 log_stderr("failure: btrfs_delete_subvolume");
12157 log_debug("Ran test");
12159 safe_close(attr.userns_fd);
12160 safe_close(open_tree_fd);
12161 safe_close(tree_fd);
12166 static int btrfs_subvolumes_setflags_fsids_unmapped_userns(void)
12169 int open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
12170 struct mount_attr attr = {
12171 .attr_set = MOUNT_ATTR_IDMAP,
12175 if (!caps_supported())
12178 /* Changing mount properties on a detached mount. */
12179 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12180 if (attr.userns_fd < 0) {
12181 log_stderr("failure: get_userns_fd");
12185 /* Changing mount properties on a detached mount. */
12186 userns_fd = get_userns_fd(0, 30000, 10000);
12187 if (userns_fd < 0) {
12188 log_stderr("failure: get_userns_fd");
12192 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12195 AT_SYMLINK_NOFOLLOW |
12196 OPEN_TREE_CLOEXEC |
12198 if (open_tree_fd < 0) {
12199 log_stderr("failure: sys_open_tree");
12203 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12204 log_stderr("failure: sys_mount_setattr");
12209 * The open_tree() syscall returns an O_PATH file descriptor which we
12210 * can't use with ioctl(). So let's reopen it as a proper file
12213 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12215 log_stderr("failure: openat");
12219 /* create subvolume */
12220 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12221 log_stderr("failure: btrfs_create_subvolume");
12225 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12226 log_stderr("failure: expected_uid_gid");
12230 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12231 log_stderr("failure: expected_uid_gid");
12237 log_stderr("failure: fork");
12241 int subvolume_fd = -EBADF;
12242 bool read_only = false;
12245 * The caller's fsids don't have mappings in the idmapped mount
12246 * so any file creation must fail.
12249 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12250 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12251 if (subvolume_fd < 0)
12252 die("failure: openat");
12254 if (!switch_userns(userns_fd, 0, 0, false))
12255 die("failure: switch_userns");
12257 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12258 t_overflowuid, t_overflowgid))
12259 die("failure: expected_uid_gid");
12261 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12262 t_overflowuid, t_overflowgid))
12263 die("failure: expected_uid_gid");
12265 if (btrfs_get_subvolume_ro(subvolume_fd, &read_only))
12266 die("failure: btrfs_get_subvolume_ro");
12269 die("failure: read_only");
12271 if (!btrfs_set_subvolume_ro(subvolume_fd, true))
12272 die("failure: btrfs_set_subvolume_ro");
12273 if (errno != EPERM)
12274 die("failure: errno");
12276 safe_close(subvolume_fd);
12278 exit(EXIT_SUCCESS);
12280 if (wait_for_pid(pid))
12283 /* remove directory */
12284 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12285 log_stderr("failure: btrfs_delete_subvolume");
12290 log_debug("Ran test");
12292 safe_close(attr.userns_fd);
12293 safe_close(open_tree_fd);
12294 safe_close(tree_fd);
12295 safe_close(userns_fd);
12300 static int btrfs_snapshots_setflags_fsids_mapped(void)
12303 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12304 struct mount_attr attr = {
12305 .attr_set = MOUNT_ATTR_IDMAP,
12309 if (!caps_supported())
12312 /* Changing mount properties on a detached mount. */
12313 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12314 if (attr.userns_fd < 0) {
12315 log_stderr("failure: get_userns_fd");
12319 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12322 AT_SYMLINK_NOFOLLOW |
12323 OPEN_TREE_CLOEXEC |
12325 if (open_tree_fd < 0) {
12326 log_stderr("failure: sys_open_tree");
12330 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12331 log_stderr("failure: sys_mount_setattr");
12336 * The open_tree() syscall returns an O_PATH file descriptor which we
12337 * can't use with ioctl(). So let's reopen it as a proper file
12340 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12342 log_stderr("failure: openat");
12348 log_stderr("failure: fork");
12352 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12353 bool read_only = false;
12355 if (!switch_fsids(10000, 10000))
12356 die("failure: switch fsids");
12359 die("failure: raise caps");
12362 * The caller's fsids now have mappings in the idmapped mount
12363 * so any file creation must succeed.
12366 /* create subvolume */
12367 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12368 die("failure: btrfs_create_subvolume");
12370 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000))
12371 die("failure: expected_uid_gid");
12373 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12374 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12375 if (subvolume_fd < 0)
12376 die("failure: openat");
12378 /* create read-write snapshot */
12379 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12380 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12381 die("failure: btrfs_create_snapshot");
12383 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000))
12384 die("failure: expected_uid_gid");
12386 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12387 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12388 if (snapshot_fd < 0)
12389 die("failure: openat");
12391 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12392 die("failure: btrfs_get_subvolume_ro");
12395 die("failure: read_only");
12397 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12398 die("failure: btrfs_set_subvolume_ro");
12400 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12401 die("failure: btrfs_get_subvolume_ro");
12404 die("failure: not read_only");
12406 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12407 die("failure: btrfs_set_subvolume_ro");
12409 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12410 die("failure: btrfs_get_subvolume_ro");
12413 die("failure: read_only");
12415 safe_close(snapshot_fd);
12416 safe_close(subvolume_fd);
12418 exit(EXIT_SUCCESS);
12420 if (wait_for_pid(pid))
12423 /* remove directory */
12424 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12425 log_stderr("failure: btrfs_delete_subvolume");
12429 /* remove directory */
12430 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12431 log_stderr("failure: btrfs_delete_subvolume");
12436 log_debug("Ran test");
12438 safe_close(attr.userns_fd);
12439 safe_close(open_tree_fd);
12440 safe_close(tree_fd);
12445 static int btrfs_snapshots_setflags_fsids_mapped_userns(void)
12448 int open_tree_fd = -EBADF, tree_fd = -EBADF;
12449 struct mount_attr attr = {
12450 .attr_set = MOUNT_ATTR_IDMAP,
12454 if (!caps_supported())
12457 /* Changing mount properties on a detached mount. */
12458 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12459 if (attr.userns_fd < 0) {
12460 log_stderr("failure: get_userns_fd");
12464 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12467 AT_SYMLINK_NOFOLLOW |
12468 OPEN_TREE_CLOEXEC |
12470 if (open_tree_fd < 0) {
12471 log_stderr("failure: sys_open_tree");
12475 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12476 log_stderr("failure: sys_mount_setattr");
12481 * The open_tree() syscall returns an O_PATH file descriptor which we
12482 * can't use with ioctl(). So let's reopen it as a proper file
12485 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12487 log_stderr("failure: openat");
12493 log_stderr("failure: fork");
12497 int snapshot_fd = -EBADF, subvolume_fd = -EBADF;
12498 bool read_only = false;
12500 if (!switch_userns(attr.userns_fd, 0, 0, false))
12501 die("failure: switch_userns");
12504 * The caller's fsids now have mappings in the idmapped mount so
12505 * any file creation must succeed.
12508 /* create subvolume */
12509 if (btrfs_create_subvolume(tree_fd, BTRFS_SUBVOLUME1))
12510 die("failure: btrfs_create_subvolume");
12512 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 0, 0))
12513 die("failure: expected_uid_gid");
12515 subvolume_fd = openat(tree_fd, BTRFS_SUBVOLUME1,
12516 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12517 if (subvolume_fd < 0)
12518 die("failure: openat");
12520 /* create read-write snapshot */
12521 if (btrfs_create_snapshot(subvolume_fd, tree_fd,
12522 BTRFS_SUBVOLUME1_SNAPSHOT1, 0))
12523 die("failure: btrfs_create_snapshot");
12525 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0))
12526 die("failure: expected_uid_gid");
12528 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12529 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12530 if (snapshot_fd < 0)
12531 die("failure: openat");
12533 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12534 die("failure: btrfs_get_subvolume_ro");
12537 die("failure: read_only");
12539 if (btrfs_set_subvolume_ro(snapshot_fd, true))
12540 die("failure: btrfs_set_subvolume_ro");
12542 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12543 die("failure: btrfs_get_subvolume_ro");
12546 die("failure: not read_only");
12548 if (btrfs_set_subvolume_ro(snapshot_fd, false))
12549 die("failure: btrfs_set_subvolume_ro");
12551 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12552 die("failure: btrfs_get_subvolume_ro");
12555 die("failure: read_only");
12557 safe_close(snapshot_fd);
12558 safe_close(subvolume_fd);
12560 exit(EXIT_SUCCESS);
12562 if (wait_for_pid(pid))
12565 /* remove directory */
12566 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12567 log_stderr("failure: btrfs_delete_subvolume");
12571 /* remove directory */
12572 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12573 log_stderr("failure: btrfs_delete_subvolume");
12578 log_debug("Ran test");
12580 safe_close(attr.userns_fd);
12581 safe_close(open_tree_fd);
12582 safe_close(tree_fd);
12587 static int btrfs_snapshots_setflags_fsids_unmapped(void)
12590 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF;
12591 struct mount_attr attr = {
12592 .attr_set = MOUNT_ATTR_IDMAP,
12596 if (!caps_supported())
12599 /* Changing mount properties on a detached mount. */
12600 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12601 if (attr.userns_fd < 0) {
12602 log_stderr("failure: get_userns_fd");
12606 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12609 AT_SYMLINK_NOFOLLOW |
12610 OPEN_TREE_CLOEXEC |
12612 if (open_tree_fd < 0) {
12613 log_stderr("failure: sys_open_tree");
12617 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12618 log_stderr("failure: sys_mount_setattr");
12623 * The open_tree() syscall returns an O_PATH file descriptor which we
12624 * can't use with ioctl(). So let's reopen it as a proper file
12627 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12629 log_stderr("failure: openat");
12633 /* create subvolume */
12634 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12635 log_stderr("failure: btrfs_create_subvolume");
12639 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12640 log_stderr("failure: expected_uid_gid");
12644 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12645 log_stderr("failure: expected_uid_gid");
12649 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12650 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12651 if (subvolume_fd < 0) {
12652 log_stderr("failure: openat");
12656 /* create read-write snapshot */
12657 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12658 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12659 log_stderr("failure: btrfs_create_snapshot");
12663 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12664 log_stderr("failure: expected_uid_gid");
12668 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12669 log_stderr("failure: expected_uid_gid");
12675 log_stderr("failure: fork");
12679 int snapshot_fd = -EBADF;
12680 bool read_only = false;
12682 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12683 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12684 if (snapshot_fd < 0)
12685 die("failure: openat");
12687 if (!switch_fsids(0, 0))
12688 die("failure: switch fsids");
12691 die("failure: raise caps");
12694 * The caller's fsids don't have mappings in the idmapped mount
12695 * so any file creation must fail.
12698 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12699 die("failure: btrfs_get_subvolume_ro");
12702 die("failure: read_only");
12704 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12705 die("failure: btrfs_set_subvolume_ro");
12706 if (errno != EPERM)
12707 die("failure: errno");
12709 safe_close(snapshot_fd);
12711 exit(EXIT_SUCCESS);
12713 if (wait_for_pid(pid))
12716 /* remove directory */
12717 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12718 log_stderr("failure: btrfs_delete_subvolume");
12722 /* remove directory */
12723 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12724 log_stderr("failure: btrfs_delete_subvolume");
12729 log_debug("Ran test");
12731 safe_close(attr.userns_fd);
12732 safe_close(open_tree_fd);
12733 safe_close(subvolume_fd);
12734 safe_close(tree_fd);
12739 static int btrfs_snapshots_setflags_fsids_unmapped_userns(void)
12742 int open_tree_fd = -EBADF, subvolume_fd = -EBADF, tree_fd = -EBADF,
12743 userns_fd = -EBADF;
12744 struct mount_attr attr = {
12745 .attr_set = MOUNT_ATTR_IDMAP,
12749 if (!caps_supported())
12752 /* Changing mount properties on a detached mount. */
12753 attr.userns_fd = get_userns_fd(0, 10000, 10000);
12754 if (attr.userns_fd < 0) {
12755 log_stderr("failure: get_userns_fd");
12759 /* Changing mount properties on a detached mount. */
12760 userns_fd = get_userns_fd(0, 30000, 10000);
12761 if (userns_fd < 0) {
12762 log_stderr("failure: get_userns_fd");
12766 open_tree_fd = sys_open_tree(t_dir1_fd, "",
12769 AT_SYMLINK_NOFOLLOW |
12770 OPEN_TREE_CLOEXEC |
12772 if (open_tree_fd < 0) {
12773 log_stderr("failure: sys_open_tree");
12777 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
12778 log_stderr("failure: sys_mount_setattr");
12783 * The open_tree() syscall returns an O_PATH file descriptor which we
12784 * can't use with ioctl(). So let's reopen it as a proper file
12787 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12789 log_stderr("failure: openat");
12793 /* create subvolume */
12794 if (btrfs_create_subvolume(t_dir1_fd, BTRFS_SUBVOLUME1)) {
12795 log_stderr("failure: btrfs_create_subvolume");
12799 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0, 0, 0)) {
12800 log_stderr("failure: expected_uid_gid");
12804 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1, 0, 10000, 10000)) {
12805 log_stderr("failure: expected_uid_gid");
12809 subvolume_fd = openat(t_dir1_fd, BTRFS_SUBVOLUME1,
12810 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12811 if (subvolume_fd < 0) {
12812 log_stderr("failure: openat");
12816 /* create read-write snapshot */
12817 if (btrfs_create_snapshot(subvolume_fd, t_dir1_fd,
12818 BTRFS_SUBVOLUME1_SNAPSHOT1, 0)) {
12819 log_stderr("failure: btrfs_create_snapshot");
12823 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 0, 0)) {
12824 log_stderr("failure: expected_uid_gid");
12828 if (!expected_uid_gid(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1, 0, 10000, 10000)) {
12829 log_stderr("failure: expected_uid_gid");
12835 log_stderr("failure: fork");
12839 int snapshot_fd = -EBADF;
12840 bool read_only = false;
12843 * The caller's fsids don't have mappings in the idmapped mount
12844 * so any file creation must fail.
12847 snapshot_fd = openat(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1,
12848 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
12849 if (snapshot_fd < 0)
12850 die("failure: openat");
12853 if (!switch_userns(userns_fd, 0, 0, false))
12854 die("failure: switch_userns");
12856 if (!expected_uid_gid(t_dir1_fd, BTRFS_SUBVOLUME1, 0,
12857 t_overflowuid, t_overflowgid))
12858 die("failure: expected_uid_gid");
12860 if (!expected_uid_gid(open_tree_fd, BTRFS_SUBVOLUME1, 0,
12861 t_overflowuid, t_overflowgid))
12862 die("failure: expected_uid_gid");
12865 * The caller's fsids don't have mappings in the idmapped mount
12866 * so any file creation must fail.
12869 if (btrfs_get_subvolume_ro(snapshot_fd, &read_only))
12870 die("failure: btrfs_get_subvolume_ro");
12873 die("failure: read_only");
12875 if (!btrfs_set_subvolume_ro(snapshot_fd, true))
12876 die("failure: btrfs_set_subvolume_ro");
12877 if (errno != EPERM)
12878 die("failure: errno");
12880 safe_close(snapshot_fd);
12882 exit(EXIT_SUCCESS);
12884 if (wait_for_pid(pid))
12887 /* remove directory */
12888 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1)) {
12889 log_stderr("failure: btrfs_delete_subvolume");
12893 /* remove directory */
12894 if (btrfs_delete_subvolume(tree_fd, BTRFS_SUBVOLUME1_SNAPSHOT1)) {
12895 log_stderr("failure: btrfs_delete_subvolume");
12900 log_debug("Ran test");
12902 safe_close(attr.userns_fd);
12903 safe_close(open_tree_fd);
12904 safe_close(subvolume_fd);
12905 safe_close(tree_fd);
12906 safe_close(userns_fd);
12911 #define BTRFS_SUBVOLUME_SUBVOL1 "subvol1"
12912 #define BTRFS_SUBVOLUME_SUBVOL2 "subvol2"
12913 #define BTRFS_SUBVOLUME_SUBVOL3 "subvol3"
12914 #define BTRFS_SUBVOLUME_SUBVOL4 "subvol4"
12916 #define BTRFS_SUBVOLUME_SUBVOL1_ID 0
12917 #define BTRFS_SUBVOLUME_SUBVOL2_ID 1
12918 #define BTRFS_SUBVOLUME_SUBVOL3_ID 2
12919 #define BTRFS_SUBVOLUME_SUBVOL4_ID 3
12921 #define BTRFS_SUBVOLUME_DIR1 "dir1"
12922 #define BTRFS_SUBVOLUME_DIR2 "dir2"
12924 #define BTRFS_SUBVOLUME_MNT "mnt_subvolume1"
12926 #define BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3 "subvol1/subvol3"
12927 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2 "subvol1/dir1/dir2"
12928 #define BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4 "subvol1/dir1/dir2/subvol4"
12931 * We create the following mount layout to test lookup:
12933 * |-/mnt/test /dev/loop0 btrfs rw,relatime,space_cache,subvolid=5,subvol=/
12934 * | |-/mnt/test/mnt1 /dev/loop1[/subvol1] btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=268,subvol=/subvol1
12935 * '-/mnt/scratch /dev/loop1 btrfs rw,relatime,space_cache,user_subvol_rm_allowed,subvolid=5,subvol=/
12937 static int btrfs_subvolume_lookup_user(void)
12940 int dir1_fd = -EBADF, dir2_fd = -EBADF, mnt_fd = -EBADF,
12941 open_tree_fd = -EBADF, tree_fd = -EBADF, userns_fd = -EBADF;
12942 int subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
12943 uint64_t subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID + 1];
12944 uint64_t subvolid = -EINVAL;
12945 struct mount_attr attr = {
12946 .attr_set = MOUNT_ATTR_IDMAP,
12949 struct btrfs_iter *iter;
12951 if (!caps_supported())
12954 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
12955 subvolume_fds[i] = -EBADF;
12957 for (i = 0; i < ARRAY_SIZE(subvolume_ids); i++)
12958 subvolume_ids[i] = -EINVAL;
12960 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL1)) {
12961 log_stderr("failure: btrfs_create_subvolume");
12965 if (btrfs_create_subvolume(t_mnt_scratch_fd, BTRFS_SUBVOLUME_SUBVOL2)) {
12966 log_stderr("failure: btrfs_create_subvolume");
12970 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] = openat(t_mnt_scratch_fd,
12971 BTRFS_SUBVOLUME_SUBVOL1,
12972 O_CLOEXEC | O_DIRECTORY);
12973 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID] < 0) {
12974 log_stderr("failure: openat");
12978 /* create subvolume */
12979 if (btrfs_create_subvolume(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_SUBVOL3)) {
12980 log_stderr("failure: btrfs_create_subvolume");
12984 if (mkdirat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1, 0777)) {
12985 log_stderr("failure: mkdirat");
12989 dir1_fd = openat(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID], BTRFS_SUBVOLUME_DIR1,
12990 O_CLOEXEC | O_DIRECTORY);
12992 log_stderr("failure: openat");
12996 if (mkdirat(dir1_fd, BTRFS_SUBVOLUME_DIR2, 0777)) {
12997 log_stderr("failure: mkdirat");
13001 dir2_fd = openat(dir1_fd, BTRFS_SUBVOLUME_DIR2, O_CLOEXEC | O_DIRECTORY);
13003 log_stderr("failure: openat");
13007 if (btrfs_create_subvolume(dir2_fd, BTRFS_SUBVOLUME_SUBVOL4)) {
13008 log_stderr("failure: btrfs_create_subvolume");
13012 if (mkdirat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, 0777)) {
13013 log_stderr("failure: mkdirat");
13017 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13018 if (sys_mount(t_device_scratch, t_buf, "btrfs", 0,
13019 "subvol=" BTRFS_SUBVOLUME_SUBVOL1)) {
13020 log_stderr("failure: mount");
13024 mnt_fd = openat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, O_CLOEXEC | O_DIRECTORY);
13026 log_stderr("failure: openat");
13030 if (chown_r(t_mnt_scratch_fd, ".", 1000, 1000)) {
13031 log_stderr("failure: chown_r");
13035 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] = openat(t_mnt_scratch_fd,
13036 BTRFS_SUBVOLUME_SUBVOL2,
13037 O_CLOEXEC | O_DIRECTORY);
13038 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID] < 0) {
13039 log_stderr("failure: openat");
13043 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL1_ID],
13044 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL1_ID])) {
13045 log_stderr("failure: btrfs_get_subvolume_id");
13049 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL2_ID],
13050 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL2_ID])) {
13051 log_stderr("failure: btrfs_get_subvolume_id");
13055 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] = openat(t_mnt_scratch_fd,
13056 BTRFS_SUBVOLUME_SUBVOL1xSUBVOL3,
13057 O_CLOEXEC | O_DIRECTORY);
13058 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID] < 0) {
13059 log_stderr("failure: openat");
13063 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID],
13064 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])) {
13065 log_stderr("failure: btrfs_get_subvolume_id");
13069 subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] = openat(t_mnt_scratch_fd,
13070 BTRFS_SUBVOLUME_SUBVOL1xDIR1xDIR2xSUBVOL4,
13071 O_CLOEXEC | O_DIRECTORY);
13072 if (subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID] < 0) {
13073 log_stderr("failure: openat");
13077 if (btrfs_get_subvolume_id(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID],
13078 &subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])) {
13079 log_stderr("failure: btrfs_get_subvolume_id");
13084 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL3_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13085 log_stderr("failure: fchmod");
13089 if (fchmod(subvolume_fds[BTRFS_SUBVOLUME_SUBVOL4_ID], S_IRUSR | S_IWUSR | S_IXUSR), 0) {
13090 log_stderr("failure: fchmod");
13094 attr.userns_fd = get_userns_fd(0, 10000, 10000);
13095 if (attr.userns_fd < 0) {
13096 log_stderr("failure: get_userns_fd");
13100 open_tree_fd = sys_open_tree(mnt_fd, "",
13103 AT_SYMLINK_NOFOLLOW |
13104 OPEN_TREE_CLOEXEC |
13106 if (open_tree_fd < 0) {
13107 log_stderr("failure: sys_open_tree");
13111 if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
13112 log_stderr("failure: sys_mount_setattr");
13117 * The open_tree() syscall returns an O_PATH file descriptor which we
13118 * can't use with ioctl(). So let's reopen it as a proper file
13121 tree_fd = openat(open_tree_fd, ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
13123 log_stderr("failure: openat");
13129 log_stderr("failure: fork");
13133 bool subvolume3_found = false, subvolume4_found = false;
13135 if (!switch_fsids(11000, 11000))
13136 die("failure: switch fsids");
13139 die("failure: lower caps");
13141 if (btrfs_iterator_start(tree_fd, 0, &iter))
13142 die("failure: btrfs_iterator_start");
13145 char *subvol_path = NULL;
13148 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13152 die("failure: btrfs_iterator_next");
13154 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13155 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13156 die("failure: subvolume id %llu->%s",
13157 (long long unsigned)subvolid, subvol_path);
13159 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13160 subvolume3_found = true;
13162 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13163 subvolume4_found = true;
13167 btrfs_iterator_end(iter);
13169 if (!subvolume3_found || !subvolume4_found)
13170 die("failure: subvolume id");
13172 exit(EXIT_SUCCESS);
13174 if (wait_for_pid(pid))
13179 log_stderr("failure: fork");
13183 bool subvolume3_found = false, subvolume4_found = false;
13185 if (!switch_userns(attr.userns_fd, 0, 0, false))
13186 die("failure: switch_userns");
13188 if (btrfs_iterator_start(tree_fd, 0, &iter))
13189 die("failure: btrfs_iterator_start");
13192 char *subvol_path = NULL;
13195 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13199 die("failure: btrfs_iterator_next");
13201 if (subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID] &&
13202 subvolid != subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13203 die("failure: subvolume id %llu->%s",
13204 (long long unsigned)subvolid, subvol_path);
13206 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL3_ID])
13207 subvolume3_found = true;
13209 if (subvolid == subvolume_ids[BTRFS_SUBVOLUME_SUBVOL4_ID])
13210 subvolume4_found = true;
13214 btrfs_iterator_end(iter);
13216 if (!subvolume3_found || !subvolume4_found)
13217 die("failure: subvolume id");
13219 exit(EXIT_SUCCESS);
13221 if (wait_for_pid(pid))
13226 log_stderr("failure: fork");
13230 bool subvolume_found = false;
13232 if (!switch_fsids(0, 0))
13233 die("failure: switch fsids");
13236 die("failure: lower caps");
13238 if (btrfs_iterator_start(tree_fd, 0, &iter))
13239 die("failure: btrfs_iterator_start");
13242 char *subvol_path = NULL;
13245 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13249 die("failure: btrfs_iterator_next");
13253 subvolume_found = true;
13256 btrfs_iterator_end(iter);
13258 if (subvolume_found)
13259 die("failure: subvolume id");
13261 exit(EXIT_SUCCESS);
13263 if (wait_for_pid(pid))
13266 userns_fd = get_userns_fd(0, 30000, 10000);
13267 if (userns_fd < 0) {
13268 log_stderr("failure: get_userns_fd");
13274 log_stderr("failure: fork");
13278 bool subvolume_found = false;
13280 if (!switch_userns(userns_fd, 0, 0, true))
13281 die("failure: switch_userns");
13283 if (btrfs_iterator_start(tree_fd, 0, &iter))
13284 die("failure: btrfs_iterator_start");
13287 char *subvol_path = NULL;
13290 ret = btrfs_iterator_next(iter, &subvol_path, &subvolid);
13294 die("failure: btrfs_iterator_next");
13298 subvolume_found = true;
13301 btrfs_iterator_end(iter);
13303 if (subvolume_found)
13304 die("failure: subvolume id");
13306 exit(EXIT_SUCCESS);
13308 if (wait_for_pid(pid))
13312 log_debug("Ran test");
13314 safe_close(dir1_fd);
13315 safe_close(dir2_fd);
13316 safe_close(open_tree_fd);
13317 safe_close(tree_fd);
13318 safe_close(userns_fd);
13319 for (i = 0; i < ARRAY_SIZE(subvolume_fds); i++)
13320 safe_close(subvolume_fds[i]);
13321 snprintf(t_buf, sizeof(t_buf), "%s/%s", t_mountpoint, BTRFS_SUBVOLUME_MNT);
13322 sys_umount2(t_buf, MNT_DETACH);
13323 unlinkat(t_mnt_fd, BTRFS_SUBVOLUME_MNT, AT_REMOVEDIR);
13328 static void usage(void)
13330 fprintf(stderr, "Description:\n");
13331 fprintf(stderr, " Run idmapped mount tests\n\n");
13333 fprintf(stderr, "Arguments:\n");
13334 fprintf(stderr, "--device Device used in the tests\n");
13335 fprintf(stderr, "--fstype Filesystem type used in the tests\n");
13336 fprintf(stderr, "--help Print help\n");
13337 fprintf(stderr, "--mountpoint Mountpoint of device\n");
13338 fprintf(stderr, "--supported Test whether idmapped mounts are supported on this filesystem\n");
13339 fprintf(stderr, "--scratch-mountpoint Mountpoint of scratch device used in the tests\n");
13340 fprintf(stderr, "--scratch-device Scratch device used in the tests\n");
13341 fprintf(stderr, "--test-core Run core idmapped mount testsuite\n");
13342 fprintf(stderr, "--test-fscaps-regression Run fscap regression tests\n");
13343 fprintf(stderr, "--test-nested-userns Run nested userns idmapped mount testsuite\n");
13344 fprintf(stderr, "--test-btrfs Run btrfs specific idmapped mount testsuite\n");
13346 _exit(EXIT_SUCCESS);
13349 static const struct option longopts[] = {
13350 {"device", required_argument, 0, 'd'},
13351 {"fstype", required_argument, 0, 'f'},
13352 {"mountpoint", required_argument, 0, 'm'},
13353 {"scratch-mountpoint", required_argument, 0, 'a'},
13354 {"scratch-device", required_argument, 0, 'e'},
13355 {"supported", no_argument, 0, 's'},
13356 {"help", no_argument, 0, 'h'},
13357 {"test-core", no_argument, 0, 'c'},
13358 {"test-fscaps-regression", no_argument, 0, 'g'},
13359 {"test-nested-userns", no_argument, 0, 'n'},
13360 {"test-btrfs", no_argument, 0, 'b'},
13364 struct t_idmapped_mounts {
13366 const char *description;
13367 } basic_suite[] = {
13368 { acls, "posix acls on regular mounts", },
13369 { create_in_userns, "create operations in user namespace", },
13370 { device_node_in_userns, "device node in user namespace", },
13371 { expected_uid_gid_idmapped_mounts, "expected ownership on idmapped mounts", },
13372 { fscaps, "fscaps on regular mounts", },
13373 { fscaps_idmapped_mounts, "fscaps on idmapped mounts", },
13374 { fscaps_idmapped_mounts_in_userns, "fscaps on idmapped mounts in user namespace", },
13375 { fscaps_idmapped_mounts_in_userns_separate_userns, "fscaps on idmapped mounts in user namespace with different id mappings", },
13376 { fsids_mapped, "mapped fsids", },
13377 { fsids_unmapped, "unmapped fsids", },
13378 { hardlink_crossing_mounts, "cross mount hardlink", },
13379 { hardlink_crossing_idmapped_mounts, "cross idmapped mount hardlink", },
13380 { hardlink_from_idmapped_mount, "hardlinks from idmapped mounts", },
13381 { hardlink_from_idmapped_mount_in_userns, "hardlinks from idmapped mounts in user namespace", },
13382 #ifdef HAVE_LIBURING_H
13383 { io_uring, "io_uring", },
13384 { io_uring_userns, "io_uring in user namespace", },
13385 { io_uring_idmapped, "io_uring from idmapped mounts", },
13386 { io_uring_idmapped_userns, "io_uring from idmapped mounts in user namespace", },
13387 { io_uring_idmapped_unmapped, "io_uring from idmapped mounts with unmapped ids", },
13388 { io_uring_idmapped_unmapped_userns, "io_uring from idmapped mounts with unmapped ids in user namespace", },
13390 { protected_symlinks, "following protected symlinks on regular mounts", },
13391 { protected_symlinks_idmapped_mounts, "following protected symlinks on idmapped mounts", },
13392 { protected_symlinks_idmapped_mounts_in_userns, "following protected symlinks on idmapped mounts in user namespace", },
13393 { rename_crossing_mounts, "cross mount rename", },
13394 { rename_crossing_idmapped_mounts, "cross idmapped mount rename", },
13395 { rename_from_idmapped_mount, "rename from idmapped mounts", },
13396 { rename_from_idmapped_mount_in_userns, "rename from idmapped mounts in user namespace", },
13397 { setattr_truncate, "setattr truncate", },
13398 { setattr_truncate_idmapped, "setattr truncate on idmapped mounts", },
13399 { setattr_truncate_idmapped_in_userns, "setattr truncate on idmapped mounts in user namespace", },
13400 { setgid_create, "create operations in directories with setgid bit set", },
13401 { setgid_create_idmapped, "create operations in directories with setgid bit set on idmapped mounts", },
13402 { setgid_create_idmapped_in_userns, "create operations in directories with setgid bit set on idmapped mounts in user namespace", },
13403 { setid_binaries, "setid binaries on regular mounts", },
13404 { setid_binaries_idmapped_mounts, "setid binaries on idmapped mounts", },
13405 { setid_binaries_idmapped_mounts_in_userns, "setid binaries on idmapped mounts in user namespace", },
13406 { setid_binaries_idmapped_mounts_in_userns_separate_userns, "setid binaries on idmapped mounts in user namespace with different id mappings", },
13407 { sticky_bit_unlink, "sticky bit unlink operations on regular mounts", },
13408 { sticky_bit_unlink_idmapped_mounts, "sticky bit unlink operations on idmapped mounts", },
13409 { sticky_bit_unlink_idmapped_mounts_in_userns, "sticky bit unlink operations on idmapped mounts in user namespace", },
13410 { sticky_bit_rename, "sticky bit rename operations on regular mounts", },
13411 { sticky_bit_rename_idmapped_mounts, "sticky bit rename operations on idmapped mounts", },
13412 { sticky_bit_rename_idmapped_mounts_in_userns, "sticky bit rename operations on idmapped mounts in user namespace", },
13413 { symlink_regular_mounts, "symlink from regular mounts", },
13414 { symlink_idmapped_mounts, "symlink from idmapped mounts", },
13415 { symlink_idmapped_mounts_in_userns, "symlink from idmapped mounts in user namespace", },
13416 { threaded_idmapped_mount_interactions, "threaded operations on idmapped mounts", },
13419 struct t_idmapped_mounts fscaps_in_ancestor_userns[] = {
13420 { fscaps_idmapped_mounts_in_userns_valid_in_ancestor_userns, "fscaps on idmapped mounts in user namespace writing fscap valid in ancestor userns", },
13423 struct t_idmapped_mounts t_nested_userns[] = {
13424 { nested_userns, "test that nested user namespaces behave correctly when attached to idmapped mounts", },
13427 struct t_idmapped_mounts t_btrfs[] = {
13428 { btrfs_subvolumes_fsids_mapped, "test subvolumes with mapped fsids", },
13429 { btrfs_subvolumes_fsids_mapped_userns, "test subvolumes with mapped fsids inside user namespace", },
13430 { btrfs_subvolumes_fsids_mapped_user_subvol_rm_allowed, "test subvolume deletion with user_subvol_rm_allowed mount option", },
13431 { btrfs_subvolumes_fsids_mapped_userns_user_subvol_rm_allowed, "test subvolume deletion with user_subvol_rm_allowed mount option inside user namespace", },
13432 { btrfs_subvolumes_fsids_unmapped, "test subvolumes with unmapped fsids", },
13433 { btrfs_subvolumes_fsids_unmapped_userns, "test subvolumes with unmapped fsids inside user namespace", },
13434 { btrfs_snapshots_fsids_mapped, "test snapshots with mapped fsids", },
13435 { btrfs_snapshots_fsids_mapped_userns, "test snapshots with mapped fsids inside user namespace", },
13436 { btrfs_snapshots_fsids_mapped_user_subvol_rm_allowed, "test snapshots deletion with user_subvol_rm_allowed mount option", },
13437 { btrfs_snapshots_fsids_mapped_userns_user_subvol_rm_allowed, "test snapshots deletion with user_subvol_rm_allowed mount option inside user namespace", },
13438 { btrfs_snapshots_fsids_unmapped, "test snapshots with unmapped fsids", },
13439 { btrfs_snapshots_fsids_unmapped_userns, "test snapshots with unmapped fsids inside user namespace", },
13440 { btrfs_delete_by_spec_id, "test subvolume deletion by spec id", },
13441 { btrfs_subvolumes_setflags_fsids_mapped, "test subvolume flags with mapped fsids", },
13442 { btrfs_subvolumes_setflags_fsids_mapped_userns, "test subvolume flags with mapped fsids inside user namespace", },
13443 { btrfs_subvolumes_setflags_fsids_unmapped, "test subvolume flags with unmapped fsids", },
13444 { btrfs_subvolumes_setflags_fsids_unmapped_userns, "test subvolume flags with unmapped fsids inside user namespace", },
13445 { btrfs_snapshots_setflags_fsids_mapped, "test snapshots flags with mapped fsids", },
13446 { btrfs_snapshots_setflags_fsids_mapped_userns, "test snapshots flags with mapped fsids inside user namespace", },
13447 { btrfs_snapshots_setflags_fsids_unmapped, "test snapshots flags with unmapped fsids", },
13448 { btrfs_snapshots_setflags_fsids_unmapped_userns, "test snapshots flags with unmapped fsids inside user namespace", },
13449 { btrfs_subvolume_lookup_user, "test unprivileged subvolume lookup", },
13452 static bool run_test(struct t_idmapped_mounts suite[], size_t suite_size)
13456 for (i = 0; i < suite_size; i++) {
13457 struct t_idmapped_mounts *t = &suite[i];
13470 die("failure: %s", t->description);
13472 exit(EXIT_SUCCESS);
13475 ret = wait_for_pid(pid);
13485 int main(int argc, char *argv[])
13489 bool supported = false, test_btrfs = false, test_core = false,
13490 test_fscaps_regression = false, test_nested_userns = false;
13492 while ((ret = getopt_long_only(argc, argv, "", longopts, &index)) != -1) {
13501 t_mountpoint = optarg;
13510 test_fscaps_regression = true;
13513 test_nested_userns = true;
13519 t_mountpoint_scratch = optarg;
13522 t_device_scratch = optarg;
13532 die_errno(EINVAL, "test device missing");
13535 die_errno(EINVAL, "test filesystem type missing");
13538 die_errno(EINVAL, "mountpoint of test device missing");
13540 /* create separate mount namespace */
13541 if (unshare(CLONE_NEWNS))
13542 die("failure: create new mount namespace");
13544 /* turn off mount propagation */
13545 if (sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0))
13546 die("failure: turn mount propagation off");
13548 t_mnt_fd = openat(-EBADF, t_mountpoint, O_CLOEXEC | O_DIRECTORY);
13550 die("failed to open %s", t_mountpoint);
13552 t_mnt_scratch_fd = openat(-EBADF, t_mountpoint_scratch, O_CLOEXEC | O_DIRECTORY);
13554 die("failed to open %s", t_mountpoint_scratch);
13557 * Caller just wants to know whether the filesystem we're on supports
13561 int open_tree_fd = -EBADF;
13562 struct mount_attr attr = {
13563 .attr_set = MOUNT_ATTR_IDMAP,
13564 .userns_fd = -EBADF,
13567 /* Changing mount properties on a detached mount. */
13568 attr.userns_fd = get_userns_fd(0, 1000, 1);
13569 if (attr.userns_fd < 0)
13570 exit(EXIT_FAILURE);
13572 open_tree_fd = sys_open_tree(t_mnt_fd, "",
13575 AT_SYMLINK_NOFOLLOW |
13576 OPEN_TREE_CLOEXEC |
13578 if (open_tree_fd < 0)
13581 ret = sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr));
13583 close(open_tree_fd);
13584 close(attr.userns_fd);
13587 exit(EXIT_FAILURE);
13589 exit(EXIT_SUCCESS);
13592 stash_overflowuid();
13593 stash_overflowgid();
13595 fret = EXIT_FAILURE;
13597 if (test_core && !run_test(basic_suite, ARRAY_SIZE(basic_suite)))
13600 if (test_fscaps_regression &&
13601 !run_test(fscaps_in_ancestor_userns,
13602 ARRAY_SIZE(fscaps_in_ancestor_userns)))
13605 if (test_nested_userns &&
13606 !run_test(t_nested_userns, ARRAY_SIZE(t_nested_userns)))
13609 if (test_btrfs && !run_test(t_btrfs, ARRAY_SIZE(t_btrfs)))
13612 fret = EXIT_SUCCESS;