From: Lennart Poettering Date: Thu, 6 Feb 2025 22:03:46 +0000 (+0100) Subject: mount-util: refactor make_mount_point_inode_from_xyz() X-Git-Tag: v258-rc1~1299^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3075ea0bc98286412381941469244227e34dccf0;p=thirdparty%2Fsystemd.git mount-util: refactor make_mount_point_inode_from_xyz() This replaces make_mount_point_inode_from_stat() by make_mount_point_inode_from_mode() and makes it take a single mode_t rather than a "struct stat". Moreover, at an "atfd" style directory parameter. Then port all users over to new feature, and in particular make use of the directory fd: use chase() to create and pin parent directories first where needed. --- diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index d4718251623..3ff15a22141 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -958,10 +958,7 @@ static int mount_in_namespace_legacy( /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */ mount_tmp = strjoina(mount_slave, "/mount"); - if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) - r = mkdir_p(mount_tmp, 0700); - else - r = make_mount_point_inode_from_stat(chased_src_st, mount_tmp, 0700); + r = make_mount_point_inode_from_mode(AT_FDCWD, mount_tmp, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700); if (r < 0) { log_debug_errno(r, "Failed to create temporary mount point %s: %m", mount_tmp); goto finish; @@ -1057,12 +1054,15 @@ static int mount_in_namespace_legacy( errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) { - if (!(flags & MOUNT_IN_NAMESPACE_IS_IMAGE)) { - (void) mkdir_parents(dest, 0755); - (void) make_mount_point_inode_from_stat(chased_src_st, dest, 0700); - } else - (void) mkdir_p(dest, 0755); + _cleanup_close_ int dest_fd = -EBADF; + _cleanup_free_ char *dest_fn = NULL; + r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd); + if (r < 0) + log_debug_errno(r, "Failed to pin parent directory of mount '%s', ignoring: %m", dest); + else if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) { + r = make_mount_point_inode_from_mode(dest_fd, dest_fn, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700); + if (r < 0) + log_debug_errno(r, "Failed to make mount point inode of mount '%s', ignoring: %m", dest); } /* Fifth, move the mount to the right place inside */ @@ -1076,7 +1076,7 @@ static int mount_in_namespace_legacy( if (!mount_inside) report_errno_and_exit(errno_pipe_fd[1], log_oom_debug()); - r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest, NULL, MS_MOVE, NULL); + r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest_fd >= 0 ? FORMAT_PROC_FD_PATH(dest_fd) : dest, /* fstype= */ NULL, MS_MOVE, /* options= */ NULL); if (r < 0) report_errno_and_exit(errno_pipe_fd[1], r); @@ -1247,8 +1247,14 @@ static int mount_in_namespace( if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); + _cleanup_close_ int dest_fd = -EBADF; + _cleanup_free_ char *dest_fn = NULL; + r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd); + if (r < 0) + report_errno_and_exit(errno_pipe_fd[1], r); + if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) - (void) mkdir_parents(dest, 0755); + (void) make_mount_point_inode_from_mode(dest_fd, dest_fn, img ? S_IFDIR : st.st_mode, 0700); if (img) { DissectImageFlags f = @@ -1268,12 +1274,8 @@ static int mount_in_namespace( /* uid_range= */ UID_INVALID, /* userns_fd= */ -EBADF, f); - } else { - if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) - (void) make_mount_point_inode_from_stat(&st, dest, 0700); - + } else r = mount_exchange_graceful(new_mount_fd, dest, /* mount_beneath= */ true); - } report_errno_and_exit(errno_pipe_fd[1], r); } @@ -1698,17 +1700,17 @@ int bind_mount_submounts( return ret; } -int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) { - assert(st); +int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode) { + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dest); - if (S_ISDIR(st->st_mode)) - return mkdir_label(dest, mode); + if (S_ISDIR(source_mode)) + return mkdirat_label(dir_fd, dest, target_mode & 07777); else - return RET_NERRNO(mknod(dest, S_IFREG|(mode & ~0111), 0)); + return RET_NERRNO(mknodat(dir_fd, dest, S_IFREG|(target_mode & 07666), 0)); /* Mask off X bit */ } -int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) { +int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t access_mode) { struct stat st; assert(source); @@ -1717,7 +1719,7 @@ int make_mount_point_inode_from_path(const char *source, const char *dest, mode_ if (stat(source, &st) < 0) return -errno; - return make_mount_point_inode_from_stat(&st, dest, mode); + return make_mount_point_inode_from_mode(AT_FDCWD, dest, st.st_mode, access_mode); } int trigger_automount_at(int dir_fd, const char *path) { diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 895fe2b2cde..fa55c9d32ca 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -178,8 +178,8 @@ int bind_mount_submounts( const char *source, const char *target); -/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */ -int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode); +/* 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); int trigger_automount_at(int dir_fd, const char *path); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 9b1839d43a9..92c60c49ae2 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -297,22 +297,28 @@ static int move_submounts(const char *src, const char *dst) { assert_se(suffix = path_startswith(m->path, src)); + if (fstat(m->mount_fd, &st) < 0) + return log_error_errno(errno, "Failed to stat %s: %m", m->path); + t = path_join(dst, suffix); if (!t) return log_oom(); - if (fstat(m->mount_fd, &st) < 0) - return log_error_errno(errno, "Failed to stat %s: %m", m->path); - - r = mkdir_parents(t, 0755); + _cleanup_free_ char *fn = NULL; + _cleanup_close_ int fd = -EBADF; + r = chase(t, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn, &fd); if (r < 0) - return log_error_errno(r, "Failed to create parent directories of %s: %m", t); + return log_error_errno(r, "Failed to create and pin parent directory of %s: %m", t); - r = make_mount_point_inode_from_stat(&st, t, 0755); + r = make_mount_point_inode_from_mode(fd, fn, st.st_mode, 0755); if (r < 0 && r != -EEXIST) return log_error_errno(r, "Failed to create mountpoint %s: %m", t); - r = mount_follow_verbose(LOG_ERR, m->path, t, NULL, MS_BIND|MS_REC, NULL); + _cleanup_close_ int child_fd = openat(fd, fn, O_PATH|O_CLOEXEC); + if (child_fd < 0) + return log_error_errno(errno, "Failed to pin mountpoint %s: %m", t); + + r = mount_follow_verbose(LOG_ERR, m->path, FORMAT_PROC_FD_PATH(child_fd), /* fstype= */ NULL, MS_BIND|MS_REC, /* options= */ NULL); if (r < 0) return r; diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c index 5fb4d23f3e8..33220abe714 100644 --- a/src/test/test-mount-util.c +++ b/src/test/test-mount-util.c @@ -266,9 +266,9 @@ TEST(make_mount_point_inode) { assert_se(rmdir(dst_dir) == 0); assert_se(stat(src_file, &st) == 0); - assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0); + assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_file, st.st_mode, 0755) >= 0); assert_se(stat(src_dir, &st) == 0); - assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0); + assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_dir, st.st_mode, 0755) >= 0); assert_se(stat(dst_dir, &st) == 0); assert_se(S_ISDIR(st.st_mode));