Backported from 5.6.27 by Remi. From 29e2a204fb42af061e66a9f847ffbc8f1d13897a Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Wed, 28 Sep 2016 22:29:25 -0700 Subject: [PATCH] Fixed bug #73174 - heap overflow in php_pcre_replace_impl --- ext/pcre/php_pcre.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 7589a78..2a8ff19 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1040,8 +1040,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub char **subpat_names; /* Array for named subpatterns */ int num_subpats; /* Number of captured subpatterns */ int size_offsets; /* Size of the offsets array */ - int new_len; /* Length of needed storage */ - int alloc_len; /* Actual allocated length */ + size_t new_len; /* Length of needed storage */ + size_t alloc_len; /* Actual allocated length */ int eval_result_len=0; /* Length of the eval'ed or function-returned string */ int match_len; /* Length of the current match */ @@ -1106,8 +1106,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0); - alloc_len = 2 * subject_len + 1; - result = safe_emalloc(alloc_len, sizeof(char), 0); + result = safe_emalloc(subject_len, 2*sizeof(char), 1); + alloc_len = 2 * (size_t)subject_len + 1; /* Initialize */ match = NULL; @@ -1172,8 +1172,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub } if (new_len + 1 > alloc_len) { - alloc_len = 1 + alloc_len + 2 * new_len; - new_buf = emalloc(alloc_len); + new_buf = safe_emalloc(2, new_len + 1, alloc_len); + alloc_len = 1 + alloc_len + 2 * (size_t)new_len; memcpy(new_buf, result, *result_len); efree(result); result = new_buf; @@ -1236,8 +1236,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub } else { new_len = *result_len + subject_len - start_offset; if (new_len + 1 > alloc_len) { - alloc_len = new_len + 1; /* now we know exactly how long it is */ - new_buf = safe_emalloc(alloc_len, sizeof(char), 0); + new_buf = safe_emalloc(new_len, sizeof(char), 1); + alloc_len = (size_t)new_len + 1; /* now we know exactly how long it is */ memcpy(new_buf, result, *result_len); efree(result); result = new_buf; @@ -1268,6 +1268,12 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub efree(offsets); efree(subpat_names); + if(result && (size_t)(*result_len) > INT_MAX) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is too big, max is %d", INT_MAX); + efree(result); + result = NULL; + } + return result; } /* }}} */ -- 2.1.4