From 8d4b2689ca3d300a0d56e0ad3edead8b14aa3eec Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 9 Jul 2025 09:35:40 +0200 Subject: [PATCH 1/4] recurse-dir: use -EBADF as placeholder for invalid fd As per our coding style. --- src/basic/recurse-dir.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 5080762078..05a2cfa2e0 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -175,7 +175,7 @@ int recurse_dir( r = func(RECURSE_DIR_ENTER, path, - -1, /* we have no parent fd */ + -EBADF, /* we have no parent fd */ dir_fd, NULL, /* we have no dirent */ statx_mask != 0 ? &root_sx : NULL, @@ -229,9 +229,9 @@ int recurse_dir( r = func(RECURSE_DIR_SKIP_OPEN_DIR_ERROR_BASE + errno, p, dir_fd, - -1, + /* inode_fd = */ -EBADF, de->entries[i], - NULL, + /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) break; @@ -273,9 +273,9 @@ int recurse_dir( r = func(RECURSE_DIR_SKIP_OPEN_INODE_ERROR_BASE + errno, p, dir_fd, - -1, + /* inode_fd = */ -EBADF, de->entries[i], - NULL, + /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) break; @@ -321,9 +321,9 @@ int recurse_dir( r = func(RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE + errno, p, dir_fd, - -1, + /* inode_fd = */ -EBADF, de->entries[i], - NULL, + /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) break; @@ -351,9 +351,9 @@ int recurse_dir( r = func(RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE + EISDIR, p, dir_fd, - -1, + /* inode_fd = */ -EBADF, de->entries[i], - NULL, + /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) break; @@ -476,9 +476,9 @@ int recurse_dir( r = func(RECURSE_DIR_LEAVE, path, - -1, + -EBADF, /* we have no parent fd */ dir_fd, - NULL, + NULL, /* we have no dirent */ statx_mask != 0 ? &root_sx : NULL, userdata); if (!IN_SET(r, RECURSE_DIR_LEAVE_DIRECTORY, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE)) From ba010e14f269af7386682fa4e703d453c0253ff5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 9 Jul 2025 09:55:15 +0200 Subject: [PATCH 2/4] recurse-dir: switch to FOREACH_ARRAY --- src/basic/recurse-dir.c | 45 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 05a2cfa2e0..2f63aa48f9 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -191,7 +191,8 @@ int recurse_dir( if (r < 0) return r; - for (size_t i = 0; i < de->n_entries; i++) { + FOREACH_ARRAY(entry, de->entries, de->n_entries) { + struct dirent *i = *entry; _cleanup_close_ int inode_fd = -EBADF, subdir_fd = -EBADF; _cleanup_free_ char *joined = NULL; struct statx sx; @@ -206,16 +207,16 @@ int recurse_dir( */ if (path) { - joined = path_join(path, de->entries[i]->d_name); + joined = path_join(path, i->d_name); if (!joined) return -ENOMEM; p = joined; } else - p = de->entries[i]->d_name; + p = i->d_name; - if (IN_SET(de->entries[i]->d_type, DT_UNKNOWN, DT_DIR)) { - subdir_fd = openat(dir_fd, de->entries[i]->d_name, O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); + if (IN_SET(i->d_type, DT_UNKNOWN, DT_DIR)) { + subdir_fd = openat(dir_fd, i->d_name, O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); if (subdir_fd < 0) { if (errno == ENOENT) /* Vanished by now, go for next file immediately */ continue; @@ -230,7 +231,7 @@ int recurse_dir( p, dir_fd, /* inode_fd = */ -EBADF, - de->entries[i], + i, /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -245,7 +246,7 @@ int recurse_dir( } else { /* If we managed to get a DIR* off the inode, it's definitely a directory. */ - de->entries[i]->d_type = DT_DIR; + i->d_type = DT_DIR; if (statx_mask != 0 || (flags & RECURSE_DIR_SAME_MOUNT)) { if (statx(subdir_fd, "", AT_EMPTY_PATH, statx_mask, &sx) < 0) @@ -261,7 +262,7 @@ int recurse_dir( if (flags & RECURSE_DIR_INODE_FD) { - inode_fd = openat(dir_fd, de->entries[i]->d_name, O_PATH|O_NOFOLLOW|O_CLOEXEC); + inode_fd = openat(dir_fd, i->d_name, O_PATH|O_NOFOLLOW|O_CLOEXEC); if (inode_fd < 0) { if (errno == ENOENT) /* Vanished by now, go for next file immediately */ continue; @@ -274,7 +275,7 @@ int recurse_dir( p, dir_fd, /* inode_fd = */ -EBADF, - de->entries[i], + i, /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -308,9 +309,9 @@ int recurse_dir( inode_fd = safe_close(inode_fd); } - } else if (statx_mask != 0 || (de->entries[i]->d_type == DT_UNKNOWN && (flags & RECURSE_DIR_ENSURE_TYPE))) { + } else if (statx_mask != 0 || (i->d_type == DT_UNKNOWN && (flags & RECURSE_DIR_ENSURE_TYPE))) { - if (statx(dir_fd, de->entries[i]->d_name, AT_SYMLINK_NOFOLLOW, statx_mask | STATX_TYPE, &sx) < 0) { + if (statx(dir_fd, i->d_name, AT_SYMLINK_NOFOLLOW, statx_mask | STATX_TYPE, &sx) < 0) { if (errno == ENOENT) /* Vanished by now? Go for next file immediately */ continue; @@ -322,7 +323,7 @@ int recurse_dir( p, dir_fd, /* inode_fd = */ -EBADF, - de->entries[i], + i, /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -352,7 +353,7 @@ int recurse_dir( p, dir_fd, /* inode_fd = */ -EBADF, - de->entries[i], + i, /* sx = */ NULL, userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -369,11 +370,11 @@ int recurse_dir( /* Copy over the data we acquired through statx() if we acquired any */ if (sx.stx_mask & STATX_TYPE) { assert((subdir_fd < 0) == !S_ISDIR(sx.stx_mode)); - de->entries[i]->d_type = IFTODT(sx.stx_mode); + i->d_type = IFTODT(sx.stx_mode); } if (sx.stx_mask & STATX_INO) - de->entries[i]->d_ino = sx.stx_ino; + i->d_ino = sx.stx_ino; } if (subdir_fd >= 0) { @@ -383,7 +384,7 @@ int recurse_dir( if (sx_valid && FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) is_mount = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); else { - r = is_mount_point_at(dir_fd, de->entries[i]->d_name, 0); + r = is_mount_point_at(dir_fd, i->d_name, /* flags = */ 0); if (r < 0) log_debug_errno(r, "Failed to determine whether %s is a submount, assuming not: %m", p); @@ -395,7 +396,7 @@ int recurse_dir( p, dir_fd, subdir_fd, - de->entries[i], + i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -414,7 +415,7 @@ int recurse_dir( p, dir_fd, subdir_fd, - de->entries[i], + i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -429,7 +430,7 @@ int recurse_dir( p, dir_fd, subdir_fd, - de->entries[i], + i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); if (r == RECURSE_DIR_LEAVE_DIRECTORY) @@ -443,7 +444,7 @@ int recurse_dir( p, statx_mask, n_depth_max - 1, - flags &~ RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */ + flags & ~RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */ func, userdata); if (r != 0) @@ -453,7 +454,7 @@ int recurse_dir( p, dir_fd, subdir_fd, - de->entries[i], + i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); } else @@ -462,7 +463,7 @@ int recurse_dir( p, dir_fd, inode_fd, - de->entries[i], + i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); From 2b4999acb406ea38c633c4698163726737296b12 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 9 Jul 2025 09:19:50 +0200 Subject: [PATCH 3/4] mount-util: regroup functions --- src/shared/mount-util.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 2f10bc896b..3c1fe9dc1e 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -13,11 +13,13 @@ typedef struct SubMount { void sub_mount_array_free(SubMount *s, size_t n); int get_sub_mounts(const char *prefix, SubMount **ret_mounts, size_t *ret_n_mounts); +int bind_mount_submounts( + const char *source, + const char *target); int repeat_unmount(const char *path, int flags); int umount_recursive_full(const char *target, int flags, char **keep); - static inline int umount_recursive(const char *target, int flags) { return umount_recursive_full(target, flags, NULL); } @@ -154,10 +156,6 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_o int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set); int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping); -int bind_mount_submounts( - const char *source, - const char *target); - /* Creates a mount point (without any parents) based on the source path or mode - i.e., a file or a directory */ int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode); int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode); From 56c6d90f8cdb392b1f2a1f180249d7b8fcb9c449 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 9 Jul 2025 10:07:07 +0200 Subject: [PATCH 4/4] mount-util: teach open_tree_attr_fallback() our usual AT_EMPTY_PATH trick While at it, rename it to _with_fallback following the naming scheme we use elsewhere. --- src/nspawn/nspawn-mount.c | 2 +- src/shared/mount-util.c | 16 ++++++++++++---- src/shared/mount-util.h | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index be1c01caf9..af794b0017 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -824,7 +824,7 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u * caller's userns *without* any mount idmapping in place. To get that uid, we clone the * mount source tree and clear any existing idmapping and temporarily mount that tree over * the mount source before we stat the mount source to figure out the source uid. */ - _cleanup_close_ int fd_clone = open_tree_attr_fallback( + _cleanup_close_ int fd_clone = open_tree_attr_with_fallback( AT_FDCWD, m->source, OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC, diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index a0db226c25..3d10a05091 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -1441,10 +1441,18 @@ int make_userns(uid_t uid_shift, return TAKE_FD(userns_fd); } -int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr) { +int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr) { + _cleanup_close_ int fd = -EBADF; + + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(attr); - _cleanup_close_ int fd = open_tree_attr(dir_fd, path, flags, attr, sizeof(struct mount_attr)); + if (isempty(path)) { + path = ""; + flags |= AT_EMPTY_PATH; + } + + fd = open_tree_attr(dir_fd, path, flags, attr, sizeof(struct mount_attr)); if (fd >= 0) return TAKE_FD(fd); if (!ERRNO_IS_NOT_SUPPORTED(errno)) @@ -1492,8 +1500,8 @@ int remount_idmap_fd( for (size_t i = 0; i < n; i++) { /* Clone the mount point and et the user namespace mapping attribute on the cloned mount point. */ - mount_fds[n_mounts_fds] = open_tree_attr_fallback( - /* dir_fd= */ -EBADF, + mount_fds[n_mounts_fds] = open_tree_attr_with_fallback( + AT_FDCWD, paths[i], OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC, &(struct mount_attr) { diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 3c1fe9dc1e..3140762498 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -150,7 +150,7 @@ typedef enum RemountIdmapping { _REMOUNT_IDMAPPING_INVALID = -EINVAL, } RemountIdmapping; -int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr); +int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr); int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping); int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set);