diff options
author | Stanislav Malyshev <stas@php.net> | 2016-10-12 23:07:47 -0700 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2016-10-13 10:17:01 +0200 |
commit | 50775b77dd82c4cf2fcc182533f711a1cdf7c0b6 (patch) | |
tree | 0fc3410117e5a44b82818f2ebd2624f39aba5af6 | |
parent | 48f61377519d8dc4b3ad8127af69df41b46469d9 (diff) | |
download | php-git-50775b77dd82c4cf2fcc182533f711a1cdf7c0b6.tar.gz |
Fix potential overflows in php_pcre_replace_impl
(cherry picked from commit 9c50ba42d6503a5fcfffad6c6823a9bee0e033c0)
-rw-r--r-- | Zend/zend_alloc.c | 17 | ||||
-rw-r--r-- | Zend/zend_multiply.h | 12 | ||||
-rw-r--r-- | ext/pcre/php_pcre.c | 34 |
3 files changed, 30 insertions, 33 deletions
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 8861d00874..77471e5eb8 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -1472,7 +1472,7 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, si #endif #ifdef ZEND_WIN32 /* On Windows we don't have ability to extend huge blocks in-place. - * We allocate them with 2MB size granularity, to avoid many + * We allocate them with 2MB size granularity, to avoid many * reallocations when they are extended by small pieces */ new_size = ZEND_MM_ALIGNED_SIZE_EX(size, MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE)); @@ -1740,7 +1740,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D { #ifdef ZEND_WIN32 /* On Windows we don't have ability to extend huge blocks in-place. - * We allocate them with 2MB size granularity, to avoid many + * We allocate them with 2MB size granularity, to avoid many * reallocations when they are extended by small pieces */ size_t new_size = ZEND_MM_ALIGNED_SIZE_EX(size, MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE)); @@ -2500,19 +2500,6 @@ ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC Z return zend_mm_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } -static zend_always_inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - int overflow; - size_t ret = zend_safe_address(nmemb, size, offset, &overflow); - - if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return ret; -} - - ZEND_API void* ZEND_FASTCALL _safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { return emalloc_rel(safe_address(nmemb, size, offset)); diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h index dfd21f7da3..0c23071a7f 100644 --- a/Zend/zend_multiply.h +++ b/Zend/zend_multiply.h @@ -266,6 +266,18 @@ static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, si } #endif +static zend_always_inline size_t safe_address(size_t nmemb, size_t size, size_t offset) +{ + int overflow; + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); + + if (UNEXPECTED(overflow)) { + zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); + return 0; + } + return ret; +} + #endif /* ZEND_MULTIPLY_H */ /* diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 5170cb2e7f..9b1fb20aaa 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -88,7 +88,7 @@ static void pcre_handle_exec_error(int pcre_code) /* {{{ */ case PCRE_ERROR_BADUTF8_OFFSET: preg_code = PHP_PCRE_BAD_UTF8_OFFSET_ERROR; break; - + #ifdef HAVE_PCRE_JIT_SUPPORT case PCRE_ERROR_JIT_STACKLIMIT: preg_code = PHP_PCRE_JIT_STACKLIMIT_ERROR; @@ -925,7 +925,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec to achieve this, unless we're already at the end of the string. */ if (g_notempty != 0 && start_offset < subject_len) { int unit_len = calculate_unit_length(pce, subject + start_offset); - + offsets[0] = (int)start_offset; offsets[1] = (int)(start_offset + unit_len); } else @@ -1125,7 +1125,6 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su int backref; /* Backreference number */ int start_offset; /* Where the new search starts */ int g_notempty=0; /* If the match should not be empty */ - int replace_len=0; /* Length of replacement string */ char *replace=NULL, /* Replacement string */ *walkbuf, /* Location of current replacement in the result */ *walk, /* Used to walk the replacement string */ @@ -1133,7 +1132,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su *piece, /* The current piece of subject */ *replace_end=NULL, /* End of replacement string */ walk_last; /* Last walked character */ - int result_len; /* Length of result */ + size_t result_len; /* Length of result */ unsigned char *mark = NULL; /* Target for MARK name */ zend_string *result; /* Result of replacement */ zend_string *eval_result=NULL; /* Result of custom function */ @@ -1155,8 +1154,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su if (!is_callable_replace) { replace = Z_STRVAL_P(replace_val); - replace_len = (int)Z_STRLEN_P(replace_val); - replace_end = replace + replace_len; + replace_end = replace + Z_STRLEN_P(replace_val); } /* Calculate the size of the offsets array, and allocate memory for it. */ @@ -1224,7 +1222,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su match = subject + offsets[0]; new_len = result_len + offsets[0] - start_offset; /* part before the match */ - + /* if (!is_callable_replace) */ if (EXPECTED(replace)) { /* do regular substitution */ @@ -1250,7 +1248,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su } if (new_len >= alloc_len) { - alloc_len = alloc_len + 2 * new_len; + alloc_len = safe_address(2, new_len, alloc_len); if (result == NULL) { result = zend_string_alloc(alloc_len, 0); } else { @@ -1260,7 +1258,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su /* copy the part of the string before the match */ memcpy(&ZSTR_VAL(result)[result_len], piece, match-piece); - result_len += (int)(match-piece); + result_len += (match-piece); /* copy replacement and backrefs */ walkbuf = ZSTR_VAL(result) + result_len; @@ -1288,14 +1286,14 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su } *walkbuf = '\0'; /* increment the result length by how much we've added to the string */ - result_len += (int)(walkbuf - (ZSTR_VAL(result) + result_len)); + result_len += (walkbuf - (ZSTR_VAL(result) + result_len)); } else { /* Use custom function to get replacement string and its length. */ eval_result = preg_do_repl_func(replace_val, subject, offsets, subpat_names, count, mark); ZEND_ASSERT(eval_result); - new_len += (int)ZSTR_LEN(eval_result); + new_len = safe_address(1, ZSTR_LEN(eval_result), new_len); if (new_len >= alloc_len) { - alloc_len = alloc_len + 2 * new_len; + alloc_len = safe_address(2, new_len, alloc_len); if (result == NULL) { result = zend_string_alloc(alloc_len, 0); } else { @@ -1517,7 +1515,7 @@ static int preg_replace_impl(zval *return_value, zval *regex, zval *replace, zva } } } ZEND_HASH_FOREACH_END(); - } else { + } else { /* if subject is not an array */ old_replace_count = replace_count; if ((result = php_replace_in_subject(regex, replace, subject, limit_val, is_callable_replace, &replace_count)) != NULL) { @@ -1528,7 +1526,7 @@ static int preg_replace_impl(zval *return_value, zval *regex, zval *replace, zva } } } - + return replace_count; } /* }}} */ @@ -1617,7 +1615,7 @@ static PHP_FUNCTION(preg_replace_callback_array) Z_PARAM_LONG(limit) Z_PARAM_ZVAL_EX(zcount, 0, 1) ZEND_PARSE_PARAMETERS_END(); - + ZVAL_UNDEF(&zv); ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pattern), str_idx, replace) { if (str_idx) { @@ -1626,7 +1624,7 @@ static PHP_FUNCTION(preg_replace_callback_array) php_error_docref(NULL, E_WARNING, "Delimiter must not be alphanumeric or backslash"); zval_ptr_dtor(return_value); RETURN_NULL(); - } + } if (!zend_is_callable(replace, 0, &callback_name)) { php_error_docref(NULL, E_WARNING, "'%s' is not a valid callback", ZSTR_VAL(callback_name)); @@ -1648,14 +1646,14 @@ static PHP_FUNCTION(preg_replace_callback_array) zval_ptr_dtor(®ex); if (Z_ISUNDEF(zv)) { - RETURN_NULL(); + RETURN_NULL(); } ZVAL_COPY_VALUE(return_value, &zv); if (UNEXPECTED(EG(exception))) { zval_ptr_dtor(return_value); - RETURN_NULL(); + RETURN_NULL(); } } ZEND_HASH_FOREACH_END(); |