From 4027bd72d9f0add0135e08cc7e1860cc1385f21f Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Tue, 7 Jan 2020 19:44:51 -0500 Subject: [PATCH] tool_dirhie: Allow directory traversal during creation - 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 | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tool_dirhie.c b/src/tool_dirhie.c index 06b3c03e88..a555039951 100644 --- a/src/tool_dirhie.c +++ b/src/tool_dirhie.c @@ -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 */