summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2016-06-15 21:46:46 -0700
committerStanislav Malyshev <stas@php.net>2016-06-15 21:51:28 -0700
commit88746d60ab3ad51797612ee62603bb3e08d4aac4 (patch)
treefe63792170eff22c73b4542e15608f0b78f41465
parent489fd56fe37bf40a662931c2b4d5baa918f13e37 (diff)
downloadphp-git-88746d60ab3ad51797612ee62603bb3e08d4aac4.tar.gz
Fix bug #72400 and #72403 - prevent signed int overflows for string lengths
-rw-r--r--ext/standard/string.c25
-rw-r--r--ext/standard/url.c96
2 files changed, 72 insertions, 49 deletions
diff --git a/ext/standard/string.c b/ext/standard/string.c
index 63eede1c71..acb6a01087 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -137,6 +137,9 @@ static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *
register unsigned char *result = NULL;
size_t i, j;
+ if (UNEXPECTED(oldlen * 2 * sizeof(char) > INT_MAX)) {
+ zend_error(E_ERROR, "String size overflow");
+ }
result = (unsigned char *) safe_emalloc(oldlen, 2 * sizeof(char), 1);
for (i = j = 0; i < oldlen; i++) {
@@ -2613,6 +2616,7 @@ PHP_FUNCTION(quotemeta)
char *p, *q;
char c;
int old_len;
+ size_t new_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) {
return;
@@ -2647,8 +2651,13 @@ PHP_FUNCTION(quotemeta)
}
}
*q = 0;
+ new_len = q - str;
+ if (UNEXPECTED(new_len > INT_MAX)) {
+ efree(str);
+ zend_error(E_ERROR, "String size overflow");
+ }
- RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
+ RETURN_STRINGL(erealloc(str, new_len + 1), new_len, 0);
}
/* }}} */
@@ -3500,7 +3509,7 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
char *source, *target;
char *end;
char c;
- int newlen;
+ size_t newlen;
if (!wlength) {
wlength = strlen(what);
@@ -3531,11 +3540,15 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
}
*target = 0;
newlen = target - new_str;
+ if (UNEXPECTED(newlen > INT_MAX)) {
+ efree(new_str);
+ zend_error(E_ERROR, "String size overflow");
+ }
if (target - new_str < length * 4) {
new_str = erealloc(new_str, newlen + 1);
}
if (new_length) {
- *new_length = newlen;
+ *new_length = (int)newlen;
}
if (should_free) {
STR_FREE((char*)str);
@@ -3587,6 +3600,9 @@ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_f
*target = 0;
*new_length = target - new_str;
+ if (UNEXPECTED(*new_length < 0)) {
+ zend_error(E_ERROR, "String size overflow");
+ }
if (should_free) {
STR_FREE(str);
}
@@ -4290,6 +4306,9 @@ PHP_FUNCTION(nl2br)
size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
new_length = str_len + repl_cnt * repl_len;
+ if (UNEXPECTED(new_length > INT_MAX)) {
+ zend_error(E_ERROR, "String size overflow");
+ }
tmp = target = safe_emalloc(repl_cnt, repl_len, str_len + 1);
}
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);
}