From cbda101fe3008d61e8474da41beff876daa82dcb Mon Sep 17 00:00:00 2001 From: Martin Mirchev Date: Tue, 27 Oct 2026 00:30:51 +0800 Subject: [PATCH] Fix unmapping of an unrelated range when the aligned chunk mmap fails (#24542) When the first mmap() in zend_mm_chunk_alloc_int() is not suitably aligned, it is released and a larger mapping is requested. If that second mmap() failed, the POSIX code carried on with ptr == NULL and called munmap() on [size, size + alignment - page size), an absolute low address range. In a non-PIE binary this range can contain the executable itself, so the process crashed instead of reporting "Out of memory". Return NULL when the retry fails. --- NEWS | 4 ++- .../zend_mm_chunk_alloc_mmap_failure.phpt | 32 +++++++++++++++++++ Zend/zend_alloc.c | 3 ++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/zend_mm_chunk_alloc_mmap_failure.phpt diff --git a/NEWS b/NEWS index 5ea9ecbafb0..480df545c24 100644 --- a/NEWS +++ b/NEWS @@ -30,7 +30,9 @@ PHP NEWS for grouping. (Klaas Skelte van der Werf) . Fixed bug GH-24265 (Unwind/GracefulExit discarded in zend_fiber_execute()). (David Carlier) - + . Fixed unmapping of an unrelated range when the aligned chunk mmap fails + (Marti2203). + - Date: . Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property hash construction). (heathdutton) diff --git a/Zend/tests/zend_mm_chunk_alloc_mmap_failure.phpt b/Zend/tests/zend_mm_chunk_alloc_mmap_failure.phpt new file mode 100644 index 00000000000..b137f25620c --- /dev/null +++ b/Zend/tests/zend_mm_chunk_alloc_mmap_failure.phpt @@ -0,0 +1,32 @@ +--TEST-- +Failed retry mmap() in zend_mm_chunk_alloc_int() must not unmap an unrelated range +--EXTENSIONS-- +posix +--SKIPIF-- + 0x40000000) { + die('skip only for non-PIE builds'); +} +?> +--INI-- +memory_limit=-1 +--FILE-- + +--EXPECTREGEX-- +bool\(true\)\s+(.*Out of memory|allocation succeeded)\s* diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 3cbdd1e5f5d..2b0b2d62a19 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -905,6 +905,9 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) /* chunk has to be aligned */ zend_mm_munmap(ptr, size); ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE); + if (ptr == NULL) { + return NULL; + } #ifdef _WIN32 offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment); if (offset != 0) {