]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: check root path in more detail
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 21 Jul 2023 04:28:39 +0000 (13:28 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 29 Jul 2023 13:09:28 +0000 (22:09 +0900)
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.

src/basic/chase.c
src/basic/fd-util.h
src/test/test-chase.c

index b612a2fef619eb877c873f6cf1b8f08cc6322edc..abb9b73384140c0c87bd27fe0fdff428a0b17812 100644 (file)
@@ -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;
 
index c870a1b8990d6ca21d870c260b0e51913b12958d..6aecb91fab3e98ec12d05de9f89d752af1f128ad 100644 (file)
@@ -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);
 }
index 75c508970e1b511f7673ccc5f8c2b4136773c779..d3399c11c6c1275032e4b2d89a371db4d5de49a6 100644 (file)
@@ -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);