diff options
author | Daniel Stenberg <daniel@haxx.se> | 2020-12-04 17:27:57 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2020-12-07 00:50:49 +0100 |
commit | abd846c374c5269809ce11740754bc6f00a0b193 (patch) | |
tree | 29d4b2139f86ca3989bcb5431c4feb0f1d92b7b6 | |
parent | 2260e0ebe6d45529495231b3e37a0c58fb92a6a2 (diff) | |
download | curl-abd846c374c5269809ce11740754bc6f00a0b193.tar.gz |
urlapi: don't accept blank port number field without scheme
... as it makes the URL parser accept "very-long-hostname://" as a valid
host name and we don't want that. The parser now only accepts a blank
(no digits) after the colon if the URL starts with a scheme.
Reported-by: d4d on hackerone
Closes #6283
-rw-r--r-- | lib/urlapi-int.h | 2 | ||||
-rw-r--r-- | lib/urlapi.c | 13 | ||||
-rw-r--r-- | tests/data/test1653 | 2 | ||||
-rw-r--r-- | tests/unit/unit1653.c | 40 |
4 files changed, 39 insertions, 18 deletions
diff --git a/lib/urlapi-int.h b/lib/urlapi-int.h index 0ac5d9e0c..425723309 100644 --- a/lib/urlapi-int.h +++ b/lib/urlapi-int.h @@ -28,7 +28,7 @@ bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); #ifdef DEBUGBUILD -CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname); +CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, bool); #endif #endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/lib/urlapi.c b/lib/urlapi.c index 4bce3d4eb..ae7596359 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -497,7 +497,8 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, return result; } -UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname) +UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, + bool has_scheme) { char *portptr = NULL; char endbracket; @@ -542,10 +543,14 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname) /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just - use the default port. Firefox, Chrome and Safari all do that. */ + use the default port. Firefox, Chrome and Safari all do that. + + Don't do it if the URL has no scheme, to make something that looks like + a scheme not work! + */ if(!portptr[1]) { *portptr = '\0'; - return CURLUE_OK; + return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER; } if(!ISDIGIT(portptr[1])) @@ -904,7 +909,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(result) return result; - result = Curl_parse_port(u, hostname); + result = Curl_parse_port(u, hostname, url_has_scheme); if(result) return result; diff --git a/tests/data/test1653 b/tests/data/test1653 index 59ec3f396..fff7f6e56 100644 --- a/tests/data/test1653 +++ b/tests/data/test1653 @@ -14,7 +14,7 @@ none unittest </features> <name> -urlapi +urlapi port number parsing </name> </client> </testcase> diff --git a/tests/unit/unit1653.c b/tests/unit/unit1653.c index d245ea6ec..7d02ae6de 100644 --- a/tests/unit/unit1653.c +++ b/tests/unit/unit1653.c @@ -55,7 +55,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15]"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); ret = curl_url_get(u, CURLUPART_PORT, &portnum, CURLU_NO_DEFAULT_PORT); fail_unless(ret != CURLUE_OK, "curl_url_get portnum returned something"); @@ -69,7 +69,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15|"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -80,7 +80,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff;fea7:da15]:80"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -92,7 +92,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15%25eth3]:80"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0); fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error"); @@ -108,7 +108,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15%25eth3]"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -120,7 +120,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15]:81"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0); fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error"); @@ -136,7 +136,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15];81"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -147,19 +147,20 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15]80"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret != CURLUE_OK, "Curl_parse_port true on error"); free_and_clear(ipv6port); curl_url_cleanup(u); - /* Valid IPv6 with no port after the colon, should use default */ + /* Valid IPv6 with no port after the colon, should use default if a scheme + was used in the URL */ u = curl_url(); if(!u) goto fail; ipv6port = strdup("[fe80::250:56ff:fea7:da15]:"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, TRUE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -171,7 +172,7 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15!25eth3]:80"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret != CURLUE_OK, "Curl_parse_port returned non-error"); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -183,10 +184,25 @@ UNITTEST_START ipv6port = strdup("[fe80::250:56ff:fea7:da15%eth3]:80"); if(!ipv6port) goto fail; - ret = Curl_parse_port(u, ipv6port); + ret = Curl_parse_port(u, ipv6port, FALSE); fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error"); + free_and_clear(ipv6port); + curl_url_cleanup(u); + + /* No scheme and no digits following the colon - not accepted. Because that + makes (a*50):// that looks like a scheme be an acceptable input. */ + u = curl_url(); + if(!u) + goto fail; + ipv6port = strdup("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaa:"); + if(!ipv6port) + goto fail; + ret = Curl_parse_port(u, ipv6port, FALSE); + fail_unless(ret == CURLUE_BAD_PORT_NUMBER, "Curl_parse_port did wrong"); fail: free(ipv6port); curl_url_cleanup(u); + } UNITTEST_STOP |