]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: tighten path_is_valid() checks
authorLennart Poettering <lennart@poettering.net>
Mon, 25 Jan 2021 18:41:59 +0000 (19:41 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 3 Feb 2021 22:36:55 +0000 (23:36 +0100)
This tightens the path_is_valid() checking: it now tests whether each
component in the path is bound by FILENAME_MAX in its size.

src/basic/path-util.c
src/test/test-path-util.c

index 3dff09b15198f12460be3760339d4e1ab123f9f2..f7498d012568538681e51cb60435232270b1d608 100644 (file)
@@ -891,7 +891,7 @@ bool filename_is_valid(const char *p) {
         if (*e != 0)
                 return false;
 
-        if (e - p > FILENAME_MAX) /* FILENAME_MAX is counted *without* the trailing NUL byte */
+        if (e - p > NAME_MAX) /* NAME_MAX is counted *without* the trailing NUL byte */
                 return false;
 
         return true;
@@ -902,10 +902,25 @@ bool path_is_valid(const char *p) {
         if (isempty(p))
                 return false;
 
-        if (strlen(p) >= PATH_MAX) /* PATH_MAX is counted *with* the trailing NUL byte */
-                return false;
+        for (const char *e = p;;) {
+                size_t n;
 
-        return true;
+                /* Skip over slashes */
+                e += strspn(e, "/");
+                if (e - p >= PATH_MAX) /* Already reached the maximum length for a path? (PATH_MAX is counted
+                                        * *with* the trailing NUL byte) */
+                        return false;
+                if (*e == 0)           /* End of string? Yay! */
+                        return true;
+
+                /* Skip over one component */
+                n = strcspn(e, "/");
+                if (n > NAME_MAX)      /* One component larger than NAME_MAX? (NAME_MAX is counted *without* the
+                                        * trailing NUL byte) */
+                        return false;
+
+                e += n;
+        }
 }
 
 bool path_is_normalized(const char *p) {
index 206f5fd436db154cdebad9063343048ad42974f3..58b185494df3f456ef1389f97b93ea38a64e425a 100644 (file)
@@ -604,8 +604,7 @@ static void test_path_extract_filename(void) {
 }
 
 static void test_filename_is_valid(void) {
-        char foo[FILENAME_MAX+2];
-        int i;
+        char foo[NAME_MAX+2];
 
         log_info("/* %s */", __func__);
 
@@ -618,9 +617,8 @@ static void test_filename_is_valid(void) {
         assert_se(!filename_is_valid("bar/foo/"));
         assert_se(!filename_is_valid("bar//"));
 
-        for (i=0; i<FILENAME_MAX+1; i++)
-                foo[i] = 'a';
-        foo[FILENAME_MAX+1] = '\0';
+        memset(foo, 'a', sizeof(foo) - 1);
+        char_array_0(foo);
 
         assert_se(!filename_is_valid(foo));
 
@@ -628,6 +626,38 @@ static void test_filename_is_valid(void) {
         assert_se(filename_is_valid("o.o"));
 }
 
+static void test_path_is_valid(void) {
+        char foo[PATH_MAX+2];
+        const char *c;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(!path_is_valid(""));
+        assert_se(path_is_valid("/bar/foo"));
+        assert_se(path_is_valid("/bar/foo/"));
+        assert_se(path_is_valid("/bar/foo/"));
+        assert_se(path_is_valid("//bar//foo//"));
+        assert_se(path_is_valid("/"));
+        assert_se(path_is_valid("/////"));
+        assert_se(path_is_valid("/////.///.////...///..//."));
+        assert_se(path_is_valid("."));
+        assert_se(path_is_valid(".."));
+        assert_se(path_is_valid("bar/foo"));
+        assert_se(path_is_valid("bar/foo/"));
+        assert_se(path_is_valid("bar//"));
+
+        memset(foo, 'a', sizeof(foo) -1);
+        char_array_0(foo);
+
+        assert_se(!path_is_valid(foo));
+
+        c = strjoina("/xxx/", foo, "/yyy");
+        assert_se(!path_is_valid(c));
+
+        assert_se(path_is_valid("foo_bar-333"));
+        assert_se(path_is_valid("o.o"));
+}
+
 static void test_hidden_or_backup_file(void) {
         log_info("/* %s */", __func__);
 
@@ -761,6 +791,7 @@ int main(int argc, char **argv) {
         test_last_path_component();
         test_path_extract_filename();
         test_filename_is_valid();
+        test_path_is_valid();
         test_hidden_or_backup_file();
         test_skip_dev_prefix();
         test_empty_or_root();