]> granicus.if.org Git - php/commitdiff
Fix bug #72400 and #72403 - prevent signed int overflows for string lengths
authorStanislav Malyshev <stas@php.net>
Thu, 16 Jun 2016 04:46:46 +0000 (21:46 -0700)
committerStanislav Malyshev <stas@php.net>
Thu, 16 Jun 2016 04:51:28 +0000 (21:51 -0700)
ext/standard/string.c
ext/standard/url.c

index 63eede1c71eb56a005612b56936e2b6c211ca803..acb6a01087de7758065f036cd91eb79f906a1340 100644 (file)
@@ -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);
        }
 
index 27a216a5e0f850eefcbc30c238b56d1e60ae1da9..fc3f080a41b6f581e88c43595f72a063cfda0ec5 100644 (file)
@@ -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);
        }