]> granicus.if.org Git - php/commitdiff
More int->size_t and string overflow fixes
authorStanislav Malyshev <stas@php.net>
Sat, 5 Nov 2016 20:20:24 +0000 (13:20 -0700)
committerStanislav Malyshev <stas@php.net>
Sat, 5 Nov 2016 21:00:47 +0000 (14:00 -0700)
Zend/zend_multiply.h
Zend/zend_strtod.c
ext/bz2/bz2.c
ext/pgsql/pgsql.c
ext/spl/spl_directory.c
ext/standard/html.c
ext/standard/math.c
ext/standard/user_filters.c
ext/xmlrpc/libxmlrpc/simplestring.c
ext/xmlrpc/libxmlrpc/simplestring.h

index 8a93990466db12eeb548a1faf4c3785635748927..da0bc16933b678c5ac1ed5d04eaddbdc02f23f42 100644 (file)
@@ -278,6 +278,19 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t
        return ret;
 }
 
+/* A bit more generic version of the same */
+static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, size_t offset, const char *message)
+{
+       int overflow;
+       size_t ret = zend_safe_address(nmemb, size, offset, &overflow);
+
+       if (UNEXPECTED(overflow)) {
+               zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset);
+               return 0;
+       }
+       return ret;
+}
+
 #endif /* ZEND_MULTIPLY_H */
 
 /*
index 889a31685c3f57f8e8192ce39bb6fde81e20ef97..d15048b7e59ebdae4ee82b22bbad4beb1f75c715 100644 (file)
@@ -2677,6 +2677,14 @@ zend_strtod
                        }
                }
  dig_done:
+       if (nd < 0) {
+               /* overflow */
+               nd = DBL_DIG + 2;
+       }
+       if (nf < 0) {
+               /* overflow */
+               nf = DBL_DIG + 2;
+       }
        e = 0;
        if (c == 'e' || c == 'E') {
                if (!nd && !nz && !nz0) {
@@ -4543,7 +4551,7 @@ static void destroy_freelist(void)
                }
                freelist[i] = NULL;
        }
-       FREE_DTOA_LOCK(0) 
+       FREE_DTOA_LOCK(0)
 }
 
 #ifdef __cplusplus
index 573b6e2015f17a62f92cc35c44b176ce743cfcdd..d0daa8e4f094eaaad4c6e24baa36349d6640984b 100644 (file)
@@ -588,8 +588,8 @@ static PHP_FUNCTION(bzdecompress)
        bzs.avail_in = source_len;
 
        /* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
+       dest = zend_string_safe_alloc(source_len, 2, 1, 0);
        bzs.avail_out = source_len * 2;
-       dest = zend_string_alloc(bzs.avail_out + 1, 0);
        bzs.next_out = ZSTR_VAL(dest);
 
        while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) {
index 9ee81b1ac52c0f51a656bac896206885a6121a32..570e9ec735e145fc49584b4c36df3e85df1a552b 100644 (file)
@@ -1537,7 +1537,7 @@ PHP_FUNCTION(pg_connect_poll)
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
                return;
        }
-       
+
        if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
                RETURN_FALSE;
        }
@@ -4356,7 +4356,7 @@ PHP_FUNCTION(pg_escape_string)
                        break;
        }
 
-       to = zend_string_alloc(ZSTR_LEN(from) * 2, 0);
+       to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
 #ifdef HAVE_PQESCAPE_CONN
        if (link) {
                if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
@@ -4408,7 +4408,7 @@ PHP_FUNCTION(pg_escape_bytea)
                        RETURN_FALSE;
                }
                to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
-       } else 
+       } else
 #endif
                to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
 
index 17b9e8fa55725344c4f9d6974d5c27f0c23f47ce..aa747374dab9d70fca5e721bb7545b8917aa5f49 100644 (file)
@@ -199,7 +199,7 @@ static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *in
                        if (intern->file_name) {
                                efree(intern->file_name);
                        }
-                       intern->file_name_len = (int)spprintf(&intern->file_name, 0, "%s%c%s",
+                       intern->file_name_len = spprintf(&intern->file_name, 0, "%s%c%s",
                                                         spl_filesystem_object_get_path(intern, NULL),
                                                         slash, intern->u.dir.entry.d_name);
                        break;
@@ -232,7 +232,7 @@ static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path)
        int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
 
        intern->type = SPL_FS_DIR;
-       intern->_path_len = (int)strlen(path);
+       intern->_path_len = strlen(path);
        intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context));
 
        if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
@@ -383,7 +383,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
        }
 
        intern->file_name = use_copy ? estrndup(path, len) : path;
-       intern->file_name_len = (int)len;
+       intern->file_name_len = len;
 
        while (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
                intern->file_name[intern->file_name_len-1] = 0;
@@ -397,7 +397,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
        p2 = 0;
 #endif
        if (p1 || p2) {
-               intern->_path_len = (int)((p1 > p2 ? p1 : p2) - intern->file_name);
+               intern->_path_len = ((p1 > p2 ? p1 : p2) - intern->file_name);
        } else {
                intern->_path_len = 0;
        }
@@ -408,7 +408,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
        intern->_path = estrndup(path, intern->_path_len);
 } /* }}} */
 
-static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, int file_path_len, int use_copy, zend_class_entry *ce, zval *return_value) /* {{{ */
+static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, size_t file_path_len, int use_copy, zend_class_entry *ce, zval *return_value) /* {{{ */
 {
        spl_filesystem_object *intern;
        zval arg1;
@@ -916,7 +916,7 @@ SPL_METHOD(SplFileInfo, getExtension)
        const char *p;
        size_t flen;
        size_t path_len;
-       int idx;
+       size_t idx;
        zend_string *ret;
 
        if (zend_parse_parameters_none() == FAILURE) {
@@ -937,7 +937,7 @@ SPL_METHOD(SplFileInfo, getExtension)
 
        p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
        if (p) {
-               idx = (int)(p - ZSTR_VAL(ret));
+               idx = p - ZSTR_VAL(ret);
                RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
                zend_string_release(ret);
                return;
@@ -954,7 +954,7 @@ SPL_METHOD(DirectoryIterator, getExtension)
 {
        spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
        const char *p;
-       int idx;
+       size_t idx;
        zend_string *fname;
 
        if (zend_parse_parameters_none() == FAILURE) {
@@ -965,7 +965,7 @@ SPL_METHOD(DirectoryIterator, getExtension)
 
        p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname));
        if (p) {
-               idx = (int)(p - ZSTR_VAL(fname));
+               idx = p - ZSTR_VAL(fname);
                RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1);
                zend_string_release(fname);
        } else {
@@ -1383,7 +1383,7 @@ SPL_METHOD(SplFileInfo, getPathInfo)
                if (path) {
                        char *dpath = estrndup(path, path_len);
                        path_len = php_dirname(dpath, path_len);
-                       spl_filesystem_object_create_info(intern, dpath, (int)path_len, 1, ce, return_value);
+                       spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value);
                        efree(dpath);
                }
        }
@@ -1507,9 +1507,9 @@ SPL_METHOD(RecursiveDirectoryIterator, getChildren)
        subdir = Z_SPLFILESYSTEM_P(return_value);
        if (subdir) {
                if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
-                       subdir->u.dir.sub_path_len = (int)spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
+                       subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
                } else {
-                       subdir->u.dir.sub_path_len = (int)strlen(intern->u.dir.entry.d_name);
+                       subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
                        subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
                }
                subdir->info_class = intern->info_class;
@@ -2293,7 +2293,7 @@ SPL_METHOD(SplFileObject, __construct)
                p2 = 0;
 #endif
                if (p1 || p2) {
-                       intern->_path_len = (int)((p1 > p2 ? p1 : p2) - tmp_path);
+                       intern->_path_len = ((p1 > p2 ? p1 : p2) - tmp_path);
                } else {
                        intern->_path_len = 0;
                }
index 090b4de4f0dc8e9d6d1c17bb9bbed3f5b6565af8..e73afec4db6a0ece0b0342ff56f0829375525a6b 100644 (file)
@@ -1269,11 +1269,7 @@ PHPAPI zend_string *php_escape_html_entities_ex(unsigned char *old, size_t oldle
        if (oldlen < 64) {
                maxlen = 128;
        } else {
-               maxlen = 2 * oldlen;
-               if (maxlen < oldlen) {
-                       zend_error_noreturn(E_ERROR, "Input string is too long");
-                       return NULL;
-               }
+               maxlen = zend_safe_addmult(oldlen, 2, 0, "html_entities");
        }
 
        replaced = zend_string_alloc(maxlen, 0);
index e4b1160b75b4c729d3a45097dacd5370191ec1da..6cf3514082efdf8a581a544aed25a72ae7ef944f 100644 (file)
@@ -1151,19 +1151,15 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
 
        /* calculate the length of the return buffer */
        if (dp) {
-               integral = (int)(dp - ZSTR_VAL(tmpbuf));
+               integral = (dp - ZSTR_VAL(tmpbuf));
        } else {
                /* no decimal point was found */
-               integral = (int)ZSTR_LEN(tmpbuf);
+               integral = ZSTR_LEN(tmpbuf);
        }
 
        /* allow for thousand separators */
        if (thousand_sep) {
-               if (integral + thousand_sep_len * ((integral-1) / 3) < integral) {
-                       /* overflow */
-                       php_error_docref(NULL, E_ERROR, "String overflow");
-               }
-               integral += thousand_sep_len * ((integral-1) / 3);
+               integral = zend_safe_addmult((integral-1)/3, thousand_sep_len, integral, "number formatting");
        }
 
        reslen = integral;
@@ -1172,11 +1168,7 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
                reslen += dec;
 
                if (dec_point) {
-                       if (reslen + dec_point_len < dec_point_len) {
-                               /* overflow */
-                               php_error_docref(NULL, E_ERROR, "String overflow");
-                       }
-                       reslen += dec_point_len;
+                       reslen = zend_safe_addmult(reslen, 1, dec_point_len, "number formatting");
                }
        }
 
@@ -1194,8 +1186,8 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
         * Take care, as the sprintf implementation may return less places than
         * we requested due to internal buffer limitations */
        if (dec) {
-               int declen = (int)(dp ? s - dp : 0);
-               int topad = dec > declen ? dec - declen : 0;
+               size_t declen = (dp ? s - dp : 0);
+               size_t topad = dec > declen ? dec - declen : 0;
 
                /* pad with '0's */
                while (topad--) {
index e65148a2df9b983e2c8a0037f76ced3f94329724..2da03cd2766622a26cde3c710d77e0314bbc7599 100644 (file)
@@ -268,7 +268,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
        zval obj, zfilter;
        zval func_name;
        zval retval;
-       int len;
+       size_t len;
 
        /* some sanity checks */
        if (persistent) {
@@ -277,7 +277,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
                return NULL;
        }
 
-       len = (int)strlen(filtername);
+       len = strlen(filtername);
 
        /* determine the classname/class entry */
        if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), (char*)filtername, len))) {
@@ -289,7 +289,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
            TODO: Allow failed userfilter creations to continue
                  scanning through the list */
                if ((period = strrchr(filtername, '.'))) {
-                       char *wildcard = emalloc(len + 3);
+                       char *wildcard = safe_emalloc(len, 1, 3);
 
                        /* Search for wildcard matches instead */
                        memcpy(wildcard, filtername, len + 1); /* copy \0 */
@@ -452,7 +452,7 @@ static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
                if (!bucket->own_buf) {
                        bucket = php_stream_bucket_make_writeable(bucket);
                }
-               if ((int)bucket->buflen != Z_STRLEN_P(pzdata)) {
+               if (bucket->buflen != Z_STRLEN_P(pzdata)) {
                        bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
                        bucket->buflen = Z_STRLEN_P(pzdata);
                }
index 98b5c81e4236f6f2d4895ac0b46370693edd731e..585cac02aa32a868d78d9a684e55ab8165c14642 100644 (file)
@@ -201,7 +201,7 @@ void simplestring_addn(simplestring* target, const char* source, size_t add_len)
          simplestring_init_str(target);
       }
 
-      if((INT_MAX - add_len) < target->len || (INT_MAX - add_len - 1) < target->len) {
+      if((SIZE_MAX - add_len) < target->len || (SIZE_MAX - add_len - 1) < target->len) {
          /* check for overflows, if there's a potential overflow do nothing */
          return;
       }
index b46b0d779adf478405be674021a6dfe6723cf084..cb0c820e797a3dded4970230074ae8a7f6b19a88 100644 (file)
@@ -50,8 +50,8 @@ extern "C" {
  */
 typedef struct _simplestring {
    char* str;         /* string buf               */
-   int len;           /* length of string/buf     */
-   int size;          /* size of allocated buffer */
+   size_t len;           /* length of string/buf     */
+   size_t size;          /* size of allocated buffer */
 } simplestring;
 /******/