From: Yu Watanabe Date: Fri, 21 Jul 2023 04:28:39 +0000 (+0900) Subject: chase: check root path in more detail X-Git-Tag: v255-rc1~875^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=83c57d8cde7ac43e5d00e2ed247c831f4e241ba8;p=thirdparty%2Fsystemd.git chase: check root path in more detail In chaseat() we call dir_fd_is_root() several places, and the final result depends on it. If the root path specified to `chase()` is not normalized but points to "/", e.g. "/../", assertions in `chaseat()` or `chase()` may be triggered. --- diff --git a/src/basic/chase.c b/src/basic/chase.c index b612a2fef61..abb9b733841 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -518,6 +518,27 @@ chased_one: return 0; } +static int empty_or_root_to_null(const char **path) { + int r; + + assert(path); + + /* This nullifies the input path when the path is empty or points to "/". */ + + if (empty_or_root(*path)) { + *path = NULL; + return 0; + } + + r = path_is_root(*path); + if (r < 0) + return r; + if (r > 0) + *path = NULL; + + return 0; +} + int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, int *ret_fd) { _cleanup_free_ char *root_abs = NULL, *absolute = NULL, *p = NULL; _cleanup_close_ int fd = -EBADF, pfd = -EBADF; @@ -528,6 +549,10 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, if (isempty(path)) return -EINVAL; + r = empty_or_root_to_null(&root); + if (r < 0) + return r; + /* A root directory of "/" or "" is identical to "/". */ if (empty_or_root(root)) { root = "/"; @@ -624,8 +649,13 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) { if (!path_is_absolute(path)) { _cleanup_free_ char *root_abs = NULL; + r = empty_or_root_to_null(&root); + if (r < 0 && r != -ENOENT) + return r; + /* If the dir_fd points to the root directory, chaseat() always returns an absolute path. */ - assert(!empty_or_root(root)); + if (empty_or_root(root)) + return -EINVAL; r = path_make_absolute_cwd(root, &root_abs); if (r < 0) @@ -658,6 +688,10 @@ int chase_extract_filename(const char *path, const char *root, char **ret) { if (!path_is_absolute(path)) return -EINVAL; + r = empty_or_root_to_null(&root); + if (r < 0 && r != -ENOENT) + return r; + if (!empty_or_root(root)) { _cleanup_free_ char *root_abs = NULL; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index c870a1b8990..6aecb91fab3 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -102,6 +102,9 @@ int read_nr_open(void); int fd_get_diskseq(int fd, uint64_t *ret); int path_is_root_at(int dir_fd, const char *path); +static inline int path_is_root(const char *path) { + return path_is_root_at(AT_FDCWD, path); +} static inline int dir_fd_is_root(int dir_fd) { return path_is_root_at(dir_fd, NULL); } diff --git a/src/test/test-chase.c b/src/test/test-chase.c index 75c508970e1..d3399c11c6c 100644 --- a/src/test/test-chase.c +++ b/src/test/test-chase.c @@ -73,6 +73,11 @@ TEST(chase) { assert_se(path_equal(result, "/usr")); result = mfree(result); + r = chase(p, "/.//../../../", 0, &result, NULL); + assert_se(r > 0); + assert_se(path_equal(result, "/usr")); + result = mfree(result); + pslash = strjoina(p, "/"); r = chase(pslash, NULL, 0, &result, NULL); assert_se(r > 0);