From 550e3e882e9c9e57bdbdb77c7e88480656bf760f Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 29 Nov 2021 15:48:41 +0100 Subject: [PATCH] Fix #74604: Out of bounds in php_pcre_replace_impl Trying to allocate a `zend_string` with a length only slighty smaller than `SIZE_MAX` causes an integer overflow; we make sure that this doesn't happen by catering to the maximal overhead of a `zend_string`. --- Zend/zend_string.h | 3 ++- ext/pcre/php_pcre.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index d90d2e06d38ff..ff6ada34ccabf 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -75,7 +75,8 @@ END_EXTERN_C() #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) -#define ZSTR_MAX_LEN (SIZE_MAX - ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) +#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1)) +#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD) #define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \ (str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \ diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 9d01b328228d0..a93b35c4f33ad 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1725,7 +1725,7 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su } if (new_len >= alloc_len) { - alloc_len = zend_safe_address_guarded(2, new_len, 0); + alloc_len = zend_safe_address_guarded(2, new_len, ZSTR_MAX_OVERHEAD) - ZSTR_MAX_OVERHEAD; if (result == NULL) { result = zend_string_alloc(alloc_len, 0); } else { @@ -1961,9 +1961,9 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin pcre2_get_mark(match_data), flags); ZEND_ASSERT(eval_result); - new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result), new_len); + new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result) + ZSTR_MAX_OVERHEAD, new_len) -ZSTR_MAX_OVERHEAD; if (new_len >= alloc_len) { - alloc_len = zend_safe_address_guarded(2, new_len, 0); + alloc_len = zend_safe_address_guarded(2, new_len, ZSTR_MAX_OVERHEAD) - ZSTR_MAX_OVERHEAD; if (result == NULL) { result = zend_string_alloc(alloc_len, 0); } else {