]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: handle root path more carefully in chase_and_open() 27918/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Jun 2023 05:47:42 +0000 (14:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Jun 2023 06:50:46 +0000 (15:50 +0900)
chase_and_open() may be called with relative root path.

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

index 983901f71416d70c9a4f4e86b41350a7d425dd77..2a1bada4363c1d0db13c0089af190438c425399a 100644 (file)
@@ -618,11 +618,51 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
         return 0;
 }
 
+int chase_extract_filename(const char *path, const char *root, char **ret) {
+        int r;
+
+        /* This is similar to path_extract_filename(), but takes root directory.
+         * The result should be consistent with chase() with CHASE_EXTRACT_FILENAME. */
+
+        assert(path);
+        assert(ret);
+
+        if (isempty(path))
+                return -EINVAL;
+
+        if (!path_is_absolute(path))
+                return -EINVAL;
+
+        if (!empty_or_root(root)) {
+                _cleanup_free_ char *root_abs = NULL;
+
+                r = path_make_absolute_cwd(root, &root_abs);
+                if (r < 0)
+                        return r;
+
+                path = path_startswith(path, root_abs);
+                if (!path)
+                        return -EINVAL;
+        }
+
+        if (!isempty(path)) {
+                r = path_extract_filename(path, ret);
+                if (r != -EADDRNOTAVAIL)
+                        return r;
+        }
+
+        char *fname = strdup(".");
+        if (!fname)
+                return -ENOMEM;
+
+        *ret = fname;
+        return 0;
+}
+
 int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
         _cleanup_close_ int path_fd = -EBADF;
         _cleanup_free_ char *p = NULL, *fname = NULL;
         mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
-        const char *q;
         int r;
 
         assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
@@ -640,13 +680,10 @@ int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, i
                 return r;
         assert(path_fd >= 0);
 
-        assert_se(q = path_startswith(p, empty_to_root(root)));
-        if (isempty(q))
-                q = ".";
-
-        if (!FLAGS_SET(chase_flags, CHASE_PARENT)) {
-                r = path_extract_filename(q, &fname);
-                if (r < 0 && r != -EADDRNOTAVAIL)
+        if (!FLAGS_SET(chase_flags, CHASE_PARENT) &&
+            !FLAGS_SET(chase_flags, CHASE_EXTRACT_FILENAME)) {
+                r = chase_extract_filename(p, root, &fname);
+                if (r < 0)
                         return r;
         }
 
index f37e8368227c75b7abd4df86373f1282b8d7f572..cfc714b9f774cc570cf0c5d8323c6eb811ba13e9 100644 (file)
@@ -43,6 +43,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b);
 int chase(const char *path_with_prefix, const char *root, ChaseFlags chase_flags, char **ret_path, int *ret_fd);
 
 int chaseat_prefix_root(const char *path, const char *root, char **ret);
+int chase_extract_filename(const char *path, const char *root, char **ret);
 
 int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path);
 int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);
index 3858600b0eb39bb73de6bdbc0c4bffec00e1042c..bee33bc8b284b50b68925ea1ee39f14aaae0e33d 100644 (file)
 
 static const char *arg_test_dir = NULL;
 
+static void test_chase_extract_filename_one(const char *path, const char *root, const char *expected) {
+        _cleanup_free_ char *ret1 = NULL, *ret2 = NULL, *fname = NULL;
+
+        log_debug("/* %s(path=%s, root=%s) */", __func__, path, strnull(root));
+
+        assert_se(chase(path, root, CHASE_EXTRACT_FILENAME, &ret1, NULL) > 0);
+        assert_se(streq(ret1, expected));
+
+        assert_se(chase(path, root, 0, &ret2, NULL) > 0);
+        assert_se(chase_extract_filename(ret2, root, &fname) >= 0);
+        assert_se(streq(fname, expected));
+}
+
 TEST(chase) {
         _cleanup_free_ char *result = NULL, *pwd = NULL;
         _cleanup_close_ int pfd = -EBADF;
@@ -111,6 +124,19 @@ TEST(chase) {
         assert_se(path_equal(result, temp));
         result = mfree(result);
 
+        /* Tests for CHASE_EXTRACT_FILENAME and chase_extract_filename() */
+
+        p = strjoina(temp, "/start");
+        pslash = strjoina(p, "/");
+        test_chase_extract_filename_one(p, NULL, "usr");
+        test_chase_extract_filename_one(pslash, NULL, "usr");
+        test_chase_extract_filename_one(p, temp, "usr");
+        test_chase_extract_filename_one(pslash, temp, "usr");
+
+        p = strjoina(temp, "/slash");
+        test_chase_extract_filename_one(p, NULL, ".");
+        test_chase_extract_filename_one(p, temp, ".");
+
         /* Paths that would "escape" outside of the "root" */
 
         p = strjoina(temp, "/6dots");