← Commit list

3f06e27502

Daniel Stenberg
Daniel Stenberg
2026-03-18
SUCCESS Duration: 259s

Subject

urlapi: make dedotdotify handle leading dots correctly

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/urlapi.c+9 -5
@@ -718,8 +718,12 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
struct dynbuf out;
CURLcode result = CURLE_OK;
+ /* variables for leading dot checks */
+ const char *dinput = input;
+ size_t dlen = clen;
+
*outp = NULL;
- /* the path always starts with a slash, and a slash has not dot */
+ /* a single byte path cannot be cleaned up */
if(clen < 2)
return 0;
@@ -727,9 +731,9 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
/* A. If the input buffer begins with a prefix of "../" or "./", then
remove that prefix from the input buffer; otherwise, */
- if(is_dot(&input, &clen)) {
- const char *p = input;
- size_t blen = clen;
+ if(is_dot(&dinput, &dlen)) {
+ const char *p = dinput;
+ size_t blen = dlen;
if(!clen)
/* . [end] */
@@ -737,7 +741,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
else if(ISSLASH(*p)) {
/* one dot followed by a slash */
input = p + 1;
- clen--;
+ clen = dlen - 1;
}
/* D. if the input buffer consists only of "." or "..", then remove
tests/unit/unit1395.c+35 -0
@@ -37,6 +37,21 @@ static CURLcode test_unit1395(const char *arg)
};
const struct dotdot pairs[] = {
+ { "/%2f%2e%2e%2f/../a", "/a" },
+ { "/%2f%2e%2e%2f/../", "/" },
+ { "/%2f%2e%2e%2f/.", "/%2f%2e%2e%2f/" },
+ { "/%2f%2e%2e%2f/", "/%2f%2e%2e%2f/" },
+ { "/%2f%2e%2e%2f", "/%2f%2e%2e%2f" },
+ { "/%2f%2e%2e%2", "/%2f%2e%2e%2" },
+ { "/%2f%2e%2e%", "/%2f%2e%2e%" },
+ { "/%2f%2e%2e", "/%2f%2e%2e" },
+ { "/%2f%2e%2", "/%2f%2e%2" },
+ { "/%2f%2e%", "/%2f%2e%" },
+ { "/%2f%2e", "/%2f%2e" },
+ { "/%2f%2", "/%2f%2" },
+ { "/%2f%", "/%2f%" },
+ { "/%2f", "/%2f" },
+ { "/%2", "/%2" },
{ "%2f%2e%2e%2f/../a", "%2f%2e%2e%2f/a" },
{ "%2f%2e%2e%2f/../", "%2f%2e%2e%2f/" },
{ "%2f%2e%2e%2f/.", "%2f%2e%2e%2f/" },
@@ -108,6 +123,26 @@ static CURLcode test_unit1395(const char *arg)
{ "/moo/..", "/" },
{ "/..", "/" },
{ "/.", "/" },
+ { "////../a", "///a" },
+ { "/../../../../../../", "/" },
+ { "/..//..//", "//" },
+ { "/.config/../ssh", "/ssh" },
+ { "/..config/..", "/" },
+ { "/.../a", "/.../a" },
+ { "/a/%2E%2e/b", "/b" },
+ { "/a/%2e./b", "/b" },
+ { "/a/.%2e/b", "/b" },
+ { "/%2f..%2f", "/%2f..%2f" },
+ { "/a/b/.", "/a/b/" },
+ { "/a/b/..", "/a/" },
+ { "well-known", "well-known" },
+ { ".well-known", ".well-known" },
+ { "..well-known", "..well-known" },
+ { "...well-known", "...well-known" },
+ { "....well-known", "....well-known" },
+ { "%2ewell-known", "%2ewell-known" },
+ { "%2Ewell-known", "%2Ewell-known" },
+ { "../.well-known", ".well-known" },
};
for(i = 0; i < CURL_ARRAYSIZE(pairs); i++) {