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.
This commit is contained in:
Lennart Poettering
2025-01-20 11:35:03 +01:00
parent 64d52739c5
commit 90b9f7a07e
3 changed files with 26 additions and 10 deletions
+17 -3
View File
@@ -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;
+2
View File
@@ -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);