From 1cabb6905b98ecc11bfb1fd8305c8f5c089e5c32 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 29 Jul 2025 03:25:17 +0900 Subject: [PATCH 1/2] chase: check the result is a directory or regular file only when the resolved path exists Otherwise, if it is called with CHASE_NONEXISTENT, when we call stat_verify_directory()/_regular() the struct stat is for one of the parent directory, rather than for the result path. With this change, we can safely specify CHASE_MUST_BE_DIRECTORY/REGULAR with CHASE_NONEXISTENT. More importantly, chaseat() internally sets CHASE_MUST_BE_DIRECTORY when the input path ends with "/", "/,", "/..". Hence, without this change, we cannot specify CHASE_NONEXISTENT safely. Follow-up for 90b9f7a07e6f57825f416f6ce2db0a9f2086754b. --- src/basic/chase.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/basic/chase.c b/src/basic/chase.c index 3a929498bf..68bb9816ce 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -509,16 +509,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_MUST_BE_DIRECTORY)) { - r = stat_verify_directory(&st); - if (r < 0) - return r; - } + if (exists) { + 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 (FLAGS_SET(flags, CHASE_MUST_BE_REGULAR)) { + r = stat_verify_regular(&st); + if (r < 0) + return r; + } } if (ret_path) { From 580643a47f18db6f3e6cd44b48c10e21ad439839 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 29 Jul 2025 03:36:36 +0900 Subject: [PATCH 2/2] conf-files: CHASE_MUST_BE_DIRECTORY can be set with CHASE_NONEXISTENT With the previous commit, now CHASE_MUST_BE_DIRECTORY can be set with CHASE_NONEXISTENT. Let's unconditionally set the flag to chase the directory part of the conf file. --- src/basic/conf-files.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index b1b0c74637..c00325f2e4 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -145,7 +145,9 @@ int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile return log_debug_errno(r, "Failed to extract directory from '%s': %m", path); if (r >= 0) { r = chaseat(rfd, dirpath, - CHASE_AT_RESOLVE_IN_ROOT | (FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : CHASE_MUST_BE_DIRECTORY), + CHASE_AT_RESOLVE_IN_ROOT | + CHASE_MUST_BE_DIRECTORY | + (FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : 0), &resolved_dirpath, /* ret_fd = */ NULL); if (r < 0) return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath));