From: Lennart Poettering Date: Mon, 13 Jan 2025 12:12:23 +0000 (+0100) Subject: chase: introduce flags that verify that chased inode is regular file or dir X-Git-Tag: v258-rc1~1548^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=90b9f7a07e6f57825f416f6ce2db0a9f2086754b;p=thirdparty%2Fsystemd.git chase: introduce flags that verify that chased inode is regular file or dir This also implies the new CHASE_MUST_BE_DIRECTORY flag in case the specified path ends in a slash. This makes the rules stricter, it means we'll be closer to how this is handled in kernel: if a path ends in a slash it can never refer to a non-directory. --- diff --git a/src/basic/chase.c b/src/basic/chase.c index a0edb7e11c8..2022e7a169c 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -89,6 +89,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int int r; assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT)); + assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR)); assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME)); assert(!FLAGS_SET(flags, CHASE_TRAIL_SLASH|CHASE_EXTRACT_FILENAME)); assert(dir_fd >= 0 || dir_fd == AT_FDCWD); @@ -243,8 +244,15 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int if (root_fd < 0) return -errno; - if (FLAGS_SET(flags, CHASE_TRAIL_SLASH)) - append_trail_slash = ENDSWITH_SET(buffer, "/", "/."); + if (ENDSWITH_SET(buffer, "/", "/.")) { + flags |= CHASE_MUST_BE_DIRECTORY; + if (FLAGS_SET(flags, CHASE_TRAIL_SLASH)) + append_trail_slash = true; + } else if (dot_or_dot_dot(buffer) || endswith(buffer, "/..")) + flags |= CHASE_MUST_BE_DIRECTORY; + + if (FLAGS_SET(flags, CHASE_PARENT)) + flags |= CHASE_MUST_BE_DIRECTORY; for (todo = buffer;;) { _cleanup_free_ char *first = NULL; @@ -476,12 +484,18 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int close_and_replace(fd, child); } - if (FLAGS_SET(flags, CHASE_PARENT)) { + if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY)) { r = stat_verify_directory(&st); if (r < 0) return r; } + if (FLAGS_SET(flags, CHASE_MUST_BE_REGULAR)) { + r = stat_verify_regular(&st); + if (r < 0) + return r; + } + if (ret_path) { if (FLAGS_SET(flags, CHASE_EXTRACT_FILENAME) && done) { _cleanup_free_ char *f = NULL; diff --git a/src/basic/chase.h b/src/basic/chase.h index cedd7097fb8..eda7cad0b76 100644 --- a/src/basic/chase.h +++ b/src/basic/chase.h @@ -29,6 +29,8 @@ typedef enum ChaseFlags { * file points to the last path component does not exist. */ CHASE_MKDIR_0755 = 1 << 11, /* Create any missing directories in the given path. */ CHASE_EXTRACT_FILENAME = 1 << 12, /* Only return the last component of the resolved path */ + CHASE_MUST_BE_DIRECTORY = 1 << 13, /* Fail if returned inode fd is not a dir */ + CHASE_MUST_BE_REGULAR = 1 << 14, /* Fail if returned inode fd is not a regular file */ } ChaseFlags; bool unsafe_transition(const struct stat *a, const struct stat *b); diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c index ee7e08b086a..bc4d890d354 100644 --- a/src/shared/machine-id-setup.c +++ b/src/shared/machine-id-setup.c @@ -74,7 +74,7 @@ static int acquire_machine_id(const char *root, bool machine_id_from_firmware, s } /* Then, try reading the D-Bus machine ID, unless it is a symlink */ - fd = chase_and_open("/var/lib/dbus/machine-id", root, CHASE_PREFIX_ROOT | CHASE_NOFOLLOW, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); + fd = chase_and_open("/var/lib/dbus/machine-id", root, CHASE_PREFIX_ROOT|CHASE_NOFOLLOW|CHASE_MUST_BE_REGULAR, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); if (fd >= 0 && id128_read_fd(fd, ID128_FORMAT_PLAIN | ID128_REFUSE_NULL, ret) >= 0) { log_info("Initializing machine ID from D-Bus machine ID."); return 0; @@ -140,12 +140,12 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag WITH_UMASK(0000) { _cleanup_close_ int inode_fd = -EBADF; - r = chase("/etc/machine-id", root, CHASE_PREFIX_ROOT, &etc_machine_id, &inode_fd); + r = chase("/etc/machine-id", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_REGULAR, &etc_machine_id, &inode_fd); if (r == -ENOENT) { _cleanup_close_ int etc_fd = -EBADF; _cleanup_free_ char *etc = NULL; - r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, &etc, &etc_fd); + r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY, &etc, &etc_fd); if (r < 0) return log_error_errno(r, "Failed to open '/etc/': %m"); @@ -250,7 +250,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag if (write_run_machine_id) { _cleanup_free_ char *run = NULL; - r = chase("/run/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, &run, &run_fd); + r = chase("/run/", root, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY, &run, &run_fd); if (r < 0) return log_error_errno(r, "Failed to open '/run/': %m"); @@ -266,7 +266,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlag unlink_run_machine_id = true; } else { - r = chase("/run/machine-id", root, CHASE_PREFIX_ROOT, &run_machine_id, /* ret_inode_fd= */ NULL); + r = chase("/run/machine-id", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_REGULAR, &run_machine_id, /* ret_inode_fd= */ NULL); if (r < 0) return log_error_errno(r, "Failed to open '/run/machine-id': %m"); } @@ -321,7 +321,7 @@ int machine_id_commit(const char *root) { _cleanup_close_ int etc_fd = -EBADF; _cleanup_free_ char *etc = NULL; - r = chase("/etc/", root, CHASE_PREFIX_ROOT, &etc, &etc_fd); + r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_DIRECTORY, &etc, &etc_fd); if (r < 0) return log_error_errno(r, "Failed to open /etc/: %m"); @@ -369,7 +369,7 @@ int machine_id_commit(const char *root) { /* Open /etc/ again after we transitioned into our own private mount namespace */ _cleanup_close_ int etc_fd_again = -EBADF; - r = chase("/etc/", root, CHASE_PREFIX_ROOT, /* ret_path= */ NULL, &etc_fd_again); + r = chase("/etc/", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, &etc_fd_again); if (r < 0) return log_error_errno(r, "Failed to open /etc/: %m");