Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions Zend/zend_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,10 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt
#if ZEND_DEBUG
real_size = size;
size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info));
if (UNEXPECTED(size < real_size)) {
zend_mm_delayed_error_or_panic(heap->fallible, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
return NULL;
}
#endif
if (size > ZEND_MM_MAX_LARGE_SIZE) {
#if ZEND_DEBUG
Expand All @@ -1835,10 +1839,15 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt
* 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));
size_t alignment = MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE);
#else
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, REAL_PAGE_SIZE);
size_t alignment = REAL_PAGE_SIZE;
#endif
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, alignment);
if (UNEXPECTED(new_size < size)) {
zend_mm_delayed_error_or_panic(heap->fallible, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment);
return NULL;
}
if (new_size == old_size) {
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
Expand Down Expand Up @@ -1920,6 +1929,10 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
size_t real_size = size;

size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info));
if (UNEXPECTED(size < real_size)) {
zend_mm_delayed_error_or_panic(heap->fallible, "Possible integer overflow in memory allocation (%zu + %zu)", ZEND_MM_ALIGNED_SIZE(real_size), ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
return NULL;
}
#endif

ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted");
Expand Down
18 changes: 16 additions & 2 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)

/* Offset for safe_*alloc(n, m, offset) to size the string like zend_string_alloc(n * m + l). */
static zend_always_inline size_t zend_string_safe_offset(size_t n, size_t m, size_t l)
{
if (UNEXPECTED(l > ZSTR_MAX_LEN)) {
return SIZE_MAX; /* Rejected by the allocator. */
}
/* Works even if n * m wraps, allocator detects that overflow. */
return ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(n * m + l)) - n * m;
}

#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)); \
GC_SET_REFCOUNT(str, 1); \
Expand Down Expand Up @@ -209,10 +219,12 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
/* Fallible variant of zend_string_safe_alloc */
static zend_always_inline zend_string *zend_string_safe_falloc(size_t n, size_t m, size_t l, bool persistent, bool fallible)
{
zend_string *ret = (zend_string *)safe_fpemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
zend_string *ret = (zend_string *)safe_fpemalloc(n, m, zend_string_safe_offset(n, m, l), persistent, fallible);
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(ret == NULL)) {
return ret;
}
/* GCC can't see that allocation fails if l is too large, so make it explicit. */
ZEND_ASSERT(l <= ZSTR_MAX_LEN);

GC_SET_REFCOUNT(ret, 1);
GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
Expand Down Expand Up @@ -394,10 +406,12 @@ static zend_always_inline zend_string *zend_string_safe_frealloc(zend_string *s,

if (!ZSTR_IS_INTERNED(s)) {
if (GC_REFCOUNT(s) == 1) {
ret = (zend_string *)safe_fperealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
ret = (zend_string *)safe_fperealloc(s, n, m, zend_string_safe_offset(n, m, l), persistent, fallible);
if (ZEND_CONST_COND(fallible, true) && !ret) {
return NULL;
}
/* GCC can't see that allocation fails if l is too large, so make it explicit. */
ZEND_ASSERT(l <= ZSTR_MAX_LEN);
ZSTR_LEN(ret) = (n * m) + l;
zend_string_forget_hash_val(ret);
return ret;
Expand Down
10 changes: 6 additions & 4 deletions ext/mbstring/libmbfl/mbfl/mbfl_encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ typedef zend_string* (*mb_cut_fn)(unsigned char *str, size_t from, size_t len, u
static inline void mb_convert_buf_init(mb_convert_buf *buf, size_t initsize, uint32_t repl_char, unsigned int err_mode)
{
buf->state = buf->errors = 0;
buf->str = emalloc(_ZSTR_STRUCT_SIZE(initsize));
buf->str = emalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(initsize)));
buf->out = (unsigned char*)ZSTR_VAL(buf->str);
buf->limit = buf->out + initsize;
buf->replacement_char = repl_char;
Expand All @@ -167,16 +167,18 @@ static inline zend_result mb_convert_buf_ensure(mb_convert_buf *buf, unsigned ch
ZEND_ASSERT(*out <= *limit);
if ((size_t)(*limit - *out) < needed) {
size_t oldsize = *limit - (unsigned char*)ZSTR_VAL((buf)->str);
size_t newsize = oldsize + MAX(oldsize >> 1, needed);
zend_string *newstr = safe_ferealloc((buf)->str, 1, newsize, _ZSTR_STRUCT_SIZE(0), /* fallible */ true);
size_t growth = MAX(oldsize >> 1, needed);
zend_string *newstr = safe_ferealloc((buf)->str, 1, oldsize, zend_string_safe_offset(1, oldsize, growth), /* fallible */ true);
if (!newstr) {
/* An earlier growth may have moved the buffer. */
buf->out = *out;
buf->limit = *limit;
return FAILURE;
}
/* GCC can't see that allocation fails if growth is too large, so make it explicit. */
ZEND_ASSERT(growth <= ZSTR_MAX_LEN);
*out = (unsigned char*)ZSTR_VAL(newstr) + (*out - (unsigned char*)ZSTR_VAL((buf)->str));
*limit = (unsigned char*)ZSTR_VAL(newstr) + newsize;
*limit = (unsigned char*)ZSTR_VAL(newstr) + oldsize + growth;
(buf)->str = newstr;
}
return SUCCESS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ var_dump(chunk_split($a,$b,$c));
--EXPECTF--
*** Testing chunk_split() : unexpected large 'end' string argument variation 2 ***

Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %r65556|65560%r) in %s on line %d
Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %d) in %s on line %d
Loading