diff --git a/NEWS b/NEWS index b6a8f22b725..43f4ec3770d 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ PHP NEWS - Opcache: . Fixed oss-fuzz #64727 (JIT undefined array key warning may overwrite DIM with NULL when DIM is the same var as result). (ilutov) + . Added workaround for SELinux mprotect execheap issue. + See https://bugzilla.kernel.org/show_bug.cgi?id=218258. (ilutov) 07 Dec 2023, PHP 8.3.1RC1 diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index ac1ee89c562..d5e4612bc10 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -65,6 +65,18 @@ static void *find_prefered_mmap_base(size_t requested_size) } while (fgets(buffer, MAXPATHLEN, f) && sscanf(buffer, "%lx-%lx", &start, &end) == 2) { + /* Don't place the segment directly before or after the heap segment. Due to an selinux bug, + * a segment directly preceding or following the heap is interpreted as heap memory, which + * will result in an execheap violation for the JIT. + * See https://bugzilla.kernel.org/show_bug.cgi?id=218258. */ + bool heap_segment = strstr(buffer, "[heap]") != NULL; + if (heap_segment) { + uintptr_t start_base = start & ~(huge_page_size - 1); + if (last_free_addr + requested_size >= start_base) { + last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(end + huge_page_size, huge_page_size); + continue; + } + } if ((uintptr_t)execute_ex >= start) { /* the current segment lays before PHP .text segment or PHP .text segment itself */ /*Search for candidates at the end of the free segment near the .text segment @@ -98,7 +110,9 @@ static void *find_prefered_mmap_base(size_t requested_size) } } last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(end, huge_page_size); - + if (heap_segment) { + last_free_addr += huge_page_size; + } } fclose(f); #elif defined(__FreeBSD__)