]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Fix infinite loop in path-util.c
authorAki Tuomi <aki.tuomi@dovecot.fi>
Fri, 9 Jun 2017 10:15:35 +0000 (13:15 +0300)
committerGitLab <gitlab@git.dovecot.net>
Fri, 9 Jun 2017 13:26:27 +0000 (16:26 +0300)
Infinite loop was reached if the path was longer than
128 bytes, and the 128 boundary was in middle of path
name component.

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

index d678909e4cec413d6fcfca109521179a90c531e6..d23d12790b379d0ed8fde0d48d7446191aa582b9 100644 (file)
@@ -175,9 +175,12 @@ static int path_normalize(const char *path, bool resolve_links,
                                                return -1;
                                        }
 
-                                       /* try again with bigger buffer */
+                                       /* try again with bigger buffer,
+                                          we need to allocate more space as well if lsize == ret,
+                                          because the returned link may have gotten truncated */
                                        espace = ltlen + tlen + 2;
-                                       if ((npath_pos + espace + lsize) >= (npath + asize)) {
+                                       if ((npath_pos + espace + lsize) >= (npath + asize) ||
+                                            lsize == (size_t)ret) {
                                                ptrdiff_t npath_offset = npath_pos - npath;
                                                asize = nearest_power((npath_offset + espace + lsize) + 1);
                                                lsize = asize - (npath_offset + espace);
index 9c736224dba4c6afb9ba4cf08cf46872a758fa95..e0db0b6550dd69da82dc85149c595f08bab89cb9 100644 (file)
@@ -3,6 +3,7 @@
 #include "test-lib.h"
 #include "path-util.h"
 #include "unlink-directory.h"
+#include "str.h"
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -109,6 +110,49 @@ static void test_abspath_vs_normpath() {
        test_assert_strcmp(norm, "/bin");
 }
 
+static void test_link_alloc() {
+#define COMPONENT_COMPONENT "/component-component"
+       const char *o_tmpdir;
+
+       /* idea here is to make sure component-component
+          would optimally hit to the nearest_power value.
+
+          it has to be big enough to cause requirement for
+          allocation in t_realpath. */
+       string_t *basedir = t_str_new(256);
+       str_append(basedir, cwd);
+       str_append(basedir, "/"TEMP_DIRNAME);
+       size_t len = nearest_power(I_MAX(127, str_len(basedir))) -
+                       strlen(COMPONENT_COMPONENT);
+
+       while(str_len(basedir) < len) {
+               str_append(basedir, COMPONENT_COMPONENT);
+               (void)mkdir(str_c(basedir), 0700);
+       }
+       o_tmpdir = tmpdir;
+       tmpdir = str_c(basedir);
+
+        link1 = t_strconcat(tmpdir, "/link1", NULL);
+        if (symlink(tmpdir, link1) < 0) {
+                i_fatal("symlink(%s, %s) failed: %m", tmpdir, link1);
+        }
+
+        /* link2 and link3 point to each other to create a loop */
+        link2 = t_strconcat(tmpdir, "/link2", NULL);
+        link3 = t_strconcat(tmpdir, "/link3", NULL);
+        if (symlink(link3, link2) < 0) {
+                i_fatal("symlink(%s, %s) failed: %m", link3, link2);
+        }
+        if (symlink(link2, link3) < 0) {
+                i_fatal("symlink(%s, %s) failed: %m", link2, link3);
+        }
+
+       test_link1();
+       test_link_loop();
+
+       tmpdir = o_tmpdir;
+}
+
 static void test_cleanup(void)
 {
        const char *error;
@@ -145,6 +189,7 @@ static void test_init(void) {
 
 void test_path_util(void) {
        test_begin("test_path_util");
+       alarm(20);
        test_init();
        test_local_path();
        test_absolute_path_no_change();
@@ -155,6 +200,8 @@ void test_path_util(void) {
        test_link1();
        test_link_loop();
        test_abspath_vs_normpath();
+       test_link_alloc();
        test_cleanup();
+       alarm(0);
        test_end();
 }