diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 4221e4fe359a..4e78d505d373 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -1037,19 +1037,21 @@ static zend_always_inline void zend_mm_chunk_init(zend_mm_heap *heap, zend_mm_ch static zend_always_inline zend_mm_chunk *zend_mm_encode_cached_chunk(const zend_mm_heap *heap, const void *holder, const zend_mm_chunk *next) { #ifdef WORDS_BIGENDIAN - return (zend_mm_chunk*)((uintptr_t)next ^ heap->shadow_key ^ (uintptr_t)holder); + uintptr_t p = (uintptr_t)next; #else - return (zend_mm_chunk*)(BSWAPPTR((uintptr_t)next) ^ heap->shadow_key ^ (uintptr_t)holder); + uintptr_t p = BSWAPPTR((uintptr_t)next); #endif + /* ARX (Addition-XOR) non-linear mixing prevents linear algebraic shadow_key recovery */ + return (zend_mm_chunk*)((p + heap->shadow_key) ^ (uintptr_t)holder); } static zend_always_inline zend_mm_chunk *zend_mm_decode_cached_chunk_key(uintptr_t key, const void *holder, const zend_mm_chunk *encoded) { -#ifdef WORDS_BIGENDIAN - zend_mm_chunk *next = (zend_mm_chunk*)((uintptr_t)encoded ^ key ^ (uintptr_t)holder); -#else - zend_mm_chunk *next = (zend_mm_chunk*)(BSWAPPTR((uintptr_t)encoded ^ key ^ (uintptr_t)holder)); + uintptr_t p = ((uintptr_t)encoded ^ (uintptr_t)holder) - key; +#ifndef WORDS_BIGENDIAN + p = BSWAPPTR(p); #endif + zend_mm_chunk *next = (zend_mm_chunk*)p; ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(next, ZEND_MM_CHUNK_SIZE) == 0, "zend_mm_heap corrupted"); return next; diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index f57e69de7408..7ab4d11546fe 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -421,7 +421,10 @@ static zend_always_inline gc_root_buffer* gc_decompress(zend_refcounted *ref, ui while (1) { idx += GC_MAX_UNCOMPRESSED; - ZEND_ASSERT(idx < GC_G(first_unused)); + if (UNEXPECTED(idx >= GC_G(first_unused))) { + zend_error_noreturn(E_CORE_ERROR, "GC root buffer corruption detected: unable to resolve compressed address"); + return NULL; + } root = GC_IDX2PTR(idx); if (GC_GET_PTR(root->ref) == ref) { return root; diff --git a/main/streams/memory.c b/main/streams/memory.c index c43ddca579b6..751b79948cb2 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -52,8 +52,12 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size if (ms->mode & TEMP_STREAM_APPEND) { ms->fpos = data_len; } - if (ms->fpos + count > data_len) { - zend_string *grown = zend_string_frealloc(ms->data, ms->fpos + count, 0, /* fallible */ true); + if (UNEXPECTED(count > SIZE_MAX - ms->fpos)) { + return (ssize_t) -1; + } + size_t new_pos = ms->fpos + count; + if (new_pos > data_len) { + zend_string *grown = zend_string_frealloc(ms->data, new_pos, 0, /* fallible */ true); if (UNEXPECTED(!grown)) { return (ssize_t) -1; } @@ -69,7 +73,7 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size ZEND_ASSERT(buf != NULL); memcpy(ZSTR_VAL(ms->data) + ms->fpos, (char*) buf, count); ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0'; - ms->fpos += count; + ms->fpos = new_pos; } return count; } @@ -142,9 +146,13 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe return 0; } } else { + if (UNEXPECTED((size_t)offset > SIZE_MAX - ms->fpos)) { + *newoffs = -1; + return -1; + } stream->eof = 0; stream->fatal_error = 0; - ms->fpos = ms->fpos + offset; + ms->fpos += (size_t)offset; *newoffs = ms->fpos; return 0; } @@ -154,7 +162,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe *newoffs = -1; return -1; } else { - ms->fpos = offset; + ms->fpos = (size_t)offset; *newoffs = ms->fpos; stream->eof = 0; stream->fatal_error = 0; @@ -162,7 +170,11 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe } case SEEK_END: if (offset > 0) { - ms->fpos = ZSTR_LEN(ms->data) + offset; + if (UNEXPECTED((size_t)offset > SIZE_MAX - ZSTR_LEN(ms->data))) { + *newoffs = -1; + return -1; + } + ms->fpos = ZSTR_LEN(ms->data) + (size_t)offset; *newoffs = ms->fpos; stream->eof = 0; stream->fatal_error = 0; diff --git a/main/streams/userspace.c b/main/streams/userspace.c index 6f2949a44cca..6fa5bf29c7aa 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -612,6 +612,9 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ } else { convert_to_long(&retval); didwrite = Z_LVAL(retval); + if (didwrite < 0) { + didwrite = -1; + } } /* don't allow strange buffer overruns due to bogus return */