Skip to content

Commit

Permalink
Fix binary-safety of parse_url
Browse files Browse the repository at this point in the history
php_parse_url() is intended to support strings that are not zero
terminated. We can't use strcspn in the implementation.

As we have two uses of strcspn, add a helper.
  • Loading branch information
nikic committed Sep 2, 2020
1 parent 2e9e706 commit 54dbd3e
Show file tree
Hide file tree
Showing 12 changed files with 33 additions and 13 deletions.
5 changes: 5 additions & 0 deletions ext/standard/tests/url/parse_url_basic_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,11 @@ echo "Done";
string(19) "filter={"id":"123"}"
}

--> %:x: array(1) {
["path"]=>
string(3) "%:x"
}

--> http:///blah.com: bool(false)

--> http://:80: bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : string(0) ""
--> / : string(1) "/"
--> /rest/Users?filter={"id":"123"} : string(11) "/rest/Users"
--> %:x : string(3) "%:x"
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : string(19) "filter={"id":"123"}"
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/parse_url_basic_009.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ echo "Done";
--> : NULL
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
Expand Down
5 changes: 5 additions & 0 deletions ext/standard/tests/url/parse_url_unterminated.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,11 @@ echo "Done";
string(19) "filter={"id":"123"}"
}

--> %:x: array(1) {
["path"]=>
string(3) "%:x"
}

--> http:///blah.com: bool(false)

--> http://:80: bool(false)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/tests/url/urls.inc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ $urls = array(
'',
'/',
'/rest/Users?filter={"id":"123"}',
'%:x',

// Severely malformed URLs that do not parse:
'http:///blah.com',
Expand Down
27 changes: 14 additions & 13 deletions ext/standard/url.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ PHPAPI php_url *php_url_parse(char const *str)
return php_url_parse_ex(str, strlen(str));
}

static const char *binary_strcspn(const char *s, const char *e, const char *chars) {
while (*chars) {
const char *p = memchr(s, *chars, e - s);
if (p) {
e = p;
}
chars++;
}
return e;
}

/* {{{ php_url_parse
*/
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
Expand All @@ -109,7 +120,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
while (p < e) {
/* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
if (e + 1 < ue && e < s + strcspn(s, "?#")) {
if (e + 1 < ue && e < binary_strcspn(s, ue, "?#")) {
goto parse_port;
} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
s += 2;
Expand Down Expand Up @@ -209,18 +220,8 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
goto just_path;
}

parse_host:
/* Binary-safe strcspn(s, "/?#") */
e = ue;
if ((p = memchr(s, '/', e - s))) {
e = p;
}
if ((p = memchr(s, '?', e - s))) {
e = p;
}
if ((p = memchr(s, '#', e - s))) {
e = p;
}
parse_host:
e = binary_strcspn(s, ue, "/?#");

/* check for login and password */
if ((p = zend_memrchr(s, '@', (e-s)))) {
Expand Down

0 comments on commit 54dbd3e

Please sign in to comment.