]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_dirhie: Allow directory traversal during creation
authorJay Satiro <raysatiro@yahoo.com>
Wed, 8 Jan 2020 00:44:51 +0000 (19:44 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Thu, 9 Jan 2020 19:24:53 +0000 (14:24 -0500)
- When creating a directory hierarchy do not error when mkdir fails due
  to error EACCESS (13) "access denied".

Some file systems allow for directory traversal; in this case that it
should be possible to create child directories when permission to the
parent directory is restricted.

This is a regression caused by me in f16bed0 (precedes curl-7_61_1).
Basically I had assumed that if a directory already existed it would
fail only with error EEXIST, and not error EACCES. The latter may
happen if the directory exists but has certain restricted permissions.

Reported-by: mbeifuss@users.noreply.github.com
Fixes https://github.com/curl/curl/issues/4796
Closes https://github.com/curl/curl/pull/4797

src/tool_dirhie.c

index 06b3c03e88f08b49723c1abd4e825ac8fba80db7..a555039951444f67d98cf8326ff9ac8c2a3b6aac 100644 (file)
@@ -125,6 +125,7 @@ CURLcode create_dir_hierarchy(const char *outfile, FILE *errors)
   tempdir = strtok(outdup, PATH_DELIMITERS);
 
   while(tempdir != NULL) {
+    bool skip = false;
     tempdir2 = strtok(NULL, PATH_DELIMITERS);
     /* since strtok returns a token for the last word even
        if not ending with DIR_CHAR, we need to prune it */
@@ -133,13 +134,27 @@ CURLcode create_dir_hierarchy(const char *outfile, FILE *errors)
       if(dlen)
         msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir);
       else {
-        if(outdup == tempdir)
+        if(outdup == tempdir) {
+#if defined(MSDOS) || defined(WIN32)
+          /* Skip creating a drive's current directory.
+             It may seem as though that would harmlessly fail but it could be
+             a corner case if X: did not exist, since we would be creating it
+             erroneously.
+             eg if outfile is X:\foo\bar\filename then don't mkdir X:
+             This logic takes into account unsupported drives !:, 1:, etc. */
+          char *p = strchr(tempdir, ':');
+          if(p && !p[1])
+            skip = true;
+#endif
           /* the output string doesn't start with a separator */
           strcpy(dirbuildup, tempdir);
+        }
         else
           msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir);
       }
-      if((-1 == mkdir(dirbuildup, (mode_t)0000750)) && (errno != EEXIST)) {
+      /* Create directory. Ignore access denied error to allow traversal. */
+      if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) &&
+         (errno != EACCES) && (errno != EEXIST)) {
         show_dir_errno(errors, dirbuildup);
         result = CURLE_WRITE_ERROR;
         break; /* get out of loop */