From 627c44a333a65597d885083feea526eae1f4819e Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Fri, 22 Nov 2024 12:14:16 +0000 Subject: [PATCH] Fix appsec tests in 8.1-8.3 The use of pipe() creates an extra file descriptor which makes the helper unable to find the correct pipe file descriptor. While this could perhaps be improved by telling the helper explicitly the id of the correct file descriptor, it's probably better to swap write() calls of reading invalid addresses with mincore(). --- .../jit_utils/jit_blacklist.c | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/zend_abstract_interface/jit_utils/jit_blacklist.c b/zend_abstract_interface/jit_utils/jit_blacklist.c index 059c5bba2bf..a9d065ebd01 100644 --- a/zend_abstract_interface/jit_utils/jit_blacklist.c +++ b/zend_abstract_interface/jit_utils/jit_blacklist.c @@ -88,10 +88,6 @@ typedef union _zend_op_trace_info { #define ZEND_OP_TRACE_INFO(opline, offset) \ ((zend_op_trace_info*)(((char*)opline) + offset)) - -#ifndef _WIN32 -static int dd_probe_pipes[2]; -#endif #endif #define ZEND_FUNC_INFO(op_array) \ @@ -107,9 +103,6 @@ static void zai_jit_find_opcache_handle(void *ext) { // opcache startup NULLs its handle. MINIT is executed before extension startup. void zai_jit_minit(void) { -#if PHP_VERSION_ID < 80400 && !defined(_WIN32) - pipe(dd_probe_pipes); -#endif zend_llist_apply(&zend_extensions, zai_jit_find_opcache_handle); } @@ -185,6 +178,42 @@ int zai_get_zend_func_rid(zend_op_array *op_array) { return zend_func_info_rid; } +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) && PHP_VERSION_ID < 80400 +static bool is_mapped(void *addr, size_t size) { + uintptr_t page_size = sysconf(_SC_PAGESIZE); + assert(size <= page_size); + uintptr_t page_addr = ((uintptr_t)addr & ~(page_size - 1)); + unsigned char vec; + + uintptr_t last_page_addr = ((uintptr_t)(addr + size - 1) & ~(page_size - 1)); + +#ifdef __x86_64__ +#define SYS_mincore 0x1B +#else // aarch64 +#define SYS_mincore 0xE8 +#endif + +again: + if (syscall(SYS_mincore, page_addr, page_size, &vec) == 0) { + if (page_addr == last_page_addr) { + return true; + } else { + page_addr = last_page_addr; + goto again; + } + } else if (errno == EFAULT || errno == ENOMEM) { + return false; + } else { + // we don't know... asume true +#ifdef ZEND_DEBUG + abort(); +#else + return true; +#endif + } +} +#endif + void zai_jit_blacklist_function_inlining(zend_op_array *op_array) { #if PHP_VERSION_ID >= 80400 if (opcache_handle) { @@ -210,14 +239,12 @@ void zai_jit_blacklist_function_inlining(zend_op_array *op_array) { size_t offset = jit_extension->offset; -#ifndef _WIN32 +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) // check whether the op_trace_info is actually readable or EFAULTing // we can't trust opcache too much here... - char dummy_buf[sizeof(zend_op_trace_info)]; - if (write(dd_probe_pipes[1], ZEND_OP_TRACE_INFO(opline, offset), sizeof(zend_op_trace_info)) < 0) { + if (!is_mapped(ZEND_OP_TRACE_INFO(opline, offset), sizeof(zend_op_trace_info))) { return; } - read(dd_probe_pipes[0], dummy_buf, sizeof(zend_op_trace_info)); #endif if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {