diff options
author | Stanislav Malyshev <stas@php.net> | 2016-06-15 21:46:46 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2016-06-15 21:51:28 -0700 |
commit | 88746d60ab3ad51797612ee62603bb3e08d4aac4 (patch) | |
tree | fe63792170eff22c73b4542e15608f0b78f41465 /ext/standard/url.c | |
parent | 489fd56fe37bf40a662931c2b4d5baa918f13e37 (diff) | |
download | php-git-88746d60ab3ad51797612ee62603bb3e08d4aac4.tar.gz |
Fix bug #72400 and #72403 - prevent signed int overflows for string lengths
Diffstat (limited to 'ext/standard/url.c')
-rw-r--r-- | ext/standard/url.c | 96 |
1 files changed, 50 insertions, 46 deletions
diff --git a/ext/standard/url.c b/ext/standard/url.c index 27a216a5e0..fc3f080a41 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -65,27 +65,27 @@ PHPAPI char *php_replace_controlchars_ex(char *str, int len) { unsigned char *s = (unsigned char *)str; unsigned char *e = (unsigned char *)str + len; - + if (!str) { return (NULL); } - + while (s < e) { - + if (iscntrl(*s)) { *s='_'; - } + } s++; } - + return (str); -} +} /* }}} */ PHPAPI char *php_replace_controlchars(char *str) { return php_replace_controlchars_ex(str, strlen(str)); -} +} PHPAPI php_url *php_url_parse(char const *str) { @@ -99,7 +99,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) char port_buf[6]; php_url *ret = ecalloc(1, sizeof(php_url)); char const *s, *e, *p, *pp, *ue; - + s = str; ue = s + length; @@ -118,40 +118,40 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) } p++; } - + if (*(e + 1) == '\0') { /* only scheme is available */ ret->scheme = estrndup(s, (e - s)); php_replace_controlchars_ex(ret->scheme, (e - s)); goto end; } - /* + /* * certain schemas like mailto: and zlib: may not have any / after them * this check ensures we support those. */ if (*(e+1) != '/') { - /* check if the data we get is a port this allows us to + /* check if the data we get is a port this allows us to * correctly parse things like a.com:80 */ p = e + 1; while (isdigit(*p)) { p++; } - + if ((*p == '\0' || *p == '/') && (p - e) < 7) { goto parse_port; } - + ret->scheme = estrndup(s, (e-s)); php_replace_controlchars_ex(ret->scheme, (e - s)); - + length -= ++e - s; s = e; goto just_path; } else { ret->scheme = estrndup(s, (e-s)); php_replace_controlchars_ex(ret->scheme, (e - s)); - + if (*(e+2) == '/') { s = e + 3; if (!strncasecmp("file", ret->scheme, sizeof("file"))) { @@ -173,9 +173,9 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) length -= ++e - s; s = e; goto just_path; - } + } } - } + } } else if (e) { /* no scheme; starts with colon: look for port */ parse_port: p = e + 1; @@ -216,9 +216,9 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) ue = s + length; goto nohost; } - + e = ue; - + if (!(p = memchr(s, '/', (ue - s)))) { char *query, *fragment; @@ -238,14 +238,14 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) } } else { e = p; - } - + } + /* check for login and password */ if ((p = zend_memrchr(s, '@', (e-s)))) { if ((pp = memchr(s, ':', (p-s)))) { ret->user = estrndup(s, (pp-s)); php_replace_controlchars_ex(ret->user, (pp - s)); - + pp++; ret->pass = estrndup(pp, (p-pp)); php_replace_controlchars_ex(ret->pass, (p-pp)); @@ -253,14 +253,14 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) ret->user = estrndup(s, (p-s)); php_replace_controlchars_ex(ret->user, (p-s)); } - + s = p + 1; } /* check for port */ if (*s == '[' && *(e-1) == ']') { - /* Short circuit portscan, - we're dealing with an + /* Short circuit portscan, + we're dealing with an IPv6 embedded address */ p = s; } else { @@ -294,11 +294,11 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) } } p--; - } + } } else { p = e; } - + /* check if we have a valid host, if we don't reject the string as url */ if ((p-s) < 1) { STR_FREE(ret->scheme); @@ -310,15 +310,15 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) ret->host = estrndup(s, (p-s)); php_replace_controlchars_ex(ret->host, (p - s)); - + if (e == ue) { return ret; } - + s = e; - + nohost: - + if ((p = memchr(s, '?', (ue - s)))) { pp = strchr(s, '#'); @@ -330,14 +330,14 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) p = pp; goto label_parse; } - + if (p - s) { ret->path = estrndup(s, (p-s)); php_replace_controlchars_ex(ret->path, (p - s)); - } - + } + if (pp) { - if (pp - ++p) { + if (pp - ++p) { ret->query = estrndup(p, (pp-p)); php_replace_controlchars_ex(ret->query, (pp - p)); } @@ -351,15 +351,15 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length) if (p - s) { ret->path = estrndup(s, (p-s)); php_replace_controlchars_ex(ret->path, (p - s)); - } - + } + label_parse: p++; - + if (ue - p) { ret->fragment = estrndup(p, (ue-p)); php_replace_controlchars_ex(ret->fragment, (ue - p)); - } + } } else { ret->path = estrndup(s, (ue-s)); php_replace_controlchars_ex(ret->path, (ue - s)); @@ -441,7 +441,7 @@ PHP_FUNCTION(parse_url) add_assoc_string(return_value, "query", resource->query, 1); if (resource->fragment != NULL) add_assoc_string(return_value, "fragment", resource->fragment, 1); -done: +done: php_url_free(resource); } /* }}} */ @@ -489,7 +489,7 @@ PHPAPI char *php_url_encode(char const *s, int len, int *new_length) register unsigned char c; unsigned char *to, *start; unsigned char const *from, *end; - + from = (unsigned char *)s; end = (unsigned char *)s + len; start = to = (unsigned char *) safe_emalloc(3, len, 1); @@ -575,7 +575,7 @@ PHPAPI int php_url_decode(char *str, int len) if (*data == '+') { *dest = ' '; } - else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) + else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) { #ifndef CHARSET_EBCDIC *dest = (char) php_htoi(data + 1); @@ -625,6 +625,10 @@ PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length) if (new_length) { *new_length = y; } + if (UNEXPECTED(y > INT_MAX)) { + efree(str); + zend_error(E_ERROR, "String size overflow"); + } return ((char *) str); } /* }}} */ @@ -673,7 +677,7 @@ PHPAPI int php_raw_url_decode(char *str, int len) char *data = str; while (len--) { - if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) + if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) { #ifndef CHARSET_EBCDIC *dest = (char) php_htoi(data + 1); @@ -705,7 +709,7 @@ PHP_FUNCTION(get_headers) HashPosition pos; HashTable *hashT; long format = 0; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &url, &url_len, &format) == FAILURE) { return; } @@ -724,12 +728,12 @@ PHP_FUNCTION(get_headers) /* check for curl-wrappers that provide headers via a special "headers" element */ if (zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h) != FAILURE && Z_TYPE_PP(h) == IS_ARRAY) { - /* curl-wrappers don't load data until the 1st read */ + /* curl-wrappers don't load data until the 1st read */ if (!Z_ARRVAL_PP(h)->nNumOfElements) { php_stream_getc(stream); } zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h); - hashT = Z_ARRVAL_PP(h); + hashT = Z_ARRVAL_PP(h); } else { hashT = HASH_OF(stream->wrapperdata); } |