From 6434c93a27fd23cb1b05f8ab092bb4a43df2e9d5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 26 Aug 2021 12:27:25 +0200 Subject: [PATCH] Explicitly store real map ptr base If we only store the biased pointer, the map ptr region will not be recognized as reachable memory by leak checkers. This is primarily problematic for fuzzing, because this is persistent memory that may be reallocated during the request, without being an actual leak. Avoid this by simply storing both the real base pointer of the allocation, as well as the biased base pointer used for accesses. --- Zend/zend.c | 48 ++++++++++++++++++++--------------- Zend/zend_globals.h | 1 + Zend/zend_map_ptr.h | 14 +++------- ext/opcache/ZendAccelerator.c | 5 ++-- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index f14f9c42ca3..b5339c4f87a 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -704,15 +704,16 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ #if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET /* Map region is going to be created and resized at run-time. */ - ZEND_MAP_PTR_SET_REAL_BASE(compiler_globals->map_ptr_base, NULL); + compiler_globals->map_ptr_real_base = NULL; + compiler_globals->map_ptr_base = ZEND_MAP_PTR_BIASED_BASE(NULL); compiler_globals->map_ptr_size = 0; compiler_globals->map_ptr_last = global_map_ptr_last; if (compiler_globals->map_ptr_last) { /* Allocate map_ptr table */ - void *base; compiler_globals->map_ptr_size = ZEND_MM_ALIGNED_SIZE_EX(compiler_globals->map_ptr_last, 4096); - base = pemalloc(compiler_globals->map_ptr_size * sizeof(void*), 1); - ZEND_MAP_PTR_SET_REAL_BASE(compiler_globals->map_ptr_base, base); + void *base = pemalloc(compiler_globals->map_ptr_size * sizeof(void*), 1); + compiler_globals->map_ptr_real_base = base; + compiler_globals->map_ptr_base = ZEND_MAP_PTR_BIASED_BASE(base); memset(base, 0, compiler_globals->map_ptr_last * sizeof(void*)); } #else @@ -739,9 +740,10 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ if (compiler_globals->script_encoding_list) { pefree((char*)compiler_globals->script_encoding_list, 1); } - if (ZEND_MAP_PTR_REAL_BASE(compiler_globals->map_ptr_base)) { - free(ZEND_MAP_PTR_REAL_BASE(compiler_globals->map_ptr_base)); - ZEND_MAP_PTR_SET_REAL_BASE(compiler_globals->map_ptr_base, NULL); + if (compiler_globals->map_ptr_real_base) { + free(compiler_globals->map_ptr_real_base); + compiler_globals->map_ptr_real_base = NULL; + compiler_globals->map_ptr_base = ZEND_MAP_PTR_BIASED_BASE(NULL); compiler_globals->map_ptr_size = 0; } } @@ -972,10 +974,12 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ */ CG(map_ptr_size) = 1024 * 1024; // TODO: initial size ??? CG(map_ptr_last) = 0; - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), pemalloc(CG(map_ptr_size) * sizeof(void*), 1)); + CG(map_ptr_real_base) = pemalloc(CG(map_ptr_size) * sizeof(void*), 1); + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base)); # elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET /* Map region is going to be created and resized at run-time. */ - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), NULL); + CG(map_ptr_real_base) = NULL; + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(NULL); CG(map_ptr_size) = 0; CG(map_ptr_last) = 0; # else @@ -1057,10 +1061,11 @@ zend_result zend_post_startup(void) /* {{{ */ compiler_globals->function_table = NULL; free(compiler_globals->class_table); compiler_globals->class_table = NULL; - if (ZEND_MAP_PTR_REAL_BASE(compiler_globals->map_ptr_base)) { - free(ZEND_MAP_PTR_REAL_BASE(compiler_globals->map_ptr_base)); + if (compiler_globals->map_ptr_real_base) { + free(compiler_globals->map_ptr_real_base); } - ZEND_MAP_PTR_SET_REAL_BASE(compiler_globals->map_ptr_base, NULL); + compiler_globals->map_ptr_real_base = NULL; + compiler_globals->map_ptr_base = ZEND_MAP_PTR_BIASED_BASE(NULL); if ((script_encoding_list = (zend_encoding **)compiler_globals->script_encoding_list)) { compiler_globals_ctor(compiler_globals); compiler_globals->script_encoding_list = (const zend_encoding **)script_encoding_list; @@ -1117,9 +1122,10 @@ void zend_shutdown(void) /* {{{ */ ts_free_id(executor_globals_id); ts_free_id(compiler_globals_id); #else - if (ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base))) { - free(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base))); - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), NULL); + if (CG(map_ptr_real_base)) { + free(CG(map_ptr_real_base)); + CG(map_ptr_real_base) = NULL; + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(NULL); CG(map_ptr_size) = 0; } if (CG(script_encoding_list)) { @@ -1224,7 +1230,7 @@ ZEND_API void zend_activate(void) /* {{{ */ init_executor(); startup_scanner(); if (CG(map_ptr_last)) { - memset(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)), 0, CG(map_ptr_last) * sizeof(void*)); + memset(CG(map_ptr_real_base), 0, CG(map_ptr_last) * sizeof(void*)); } zend_observer_activate(); } @@ -1821,12 +1827,13 @@ ZEND_API void *zend_map_ptr_new(void) #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET /* Grow map_ptr table */ CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096); - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), perealloc(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)), CG(map_ptr_size) * sizeof(void*), 1)); + CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1); + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base)); #else # error "Unknown ZEND_MAP_PTR_KIND" #endif } - ptr = (void**)ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)) + CG(map_ptr_last); + ptr = (void**)CG(map_ptr_real_base) + CG(map_ptr_last); *ptr = NULL; CG(map_ptr_last)++; #if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR @@ -1850,12 +1857,13 @@ ZEND_API void zend_map_ptr_extend(size_t last) #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET /* Grow map_ptr table */ CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(last, 4096); - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), perealloc(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)), CG(map_ptr_size) * sizeof(void*), 1)); + CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1); + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base)); #else # error "Unknown ZEND_MAP_PTR_KIND" #endif } - ptr = (void**)ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)) + CG(map_ptr_last); + ptr = (void**)CG(map_ptr_real_base) + CG(map_ptr_last); memset(ptr, 0, (last - CG(map_ptr_last)) * sizeof(void*)); CG(map_ptr_last) = last; } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index d1ac6dbacfd..1726dee9ac1 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -125,6 +125,7 @@ struct _zend_compiler_globals { HashTable *memoized_exprs; int memoize_mode; + void *map_ptr_real_base; void *map_ptr_base; size_t map_ptr_size; size_t map_ptr_last; diff --git a/Zend/zend_map_ptr.h b/Zend/zend_map_ptr.h index 7074a8eeabf..0f8bcbeea98 100644 --- a/Zend/zend_map_ptr.h +++ b/Zend/zend_map_ptr.h @@ -57,11 +57,8 @@ } while (0) # define ZEND_MAP_PTR_SET_IMM(ptr, val) \ ZEND_MAP_PTR_SET(ptr, val) -# define ZEND_MAP_PTR_REAL_BASE(base) \ - (base) -# define ZEND_MAP_PTR_SET_REAL_BASE(base, ptr) do { \ - base = (ptr); \ - } while (0) +# define ZEND_MAP_PTR_BIASED_BASE(real_base) \ + (real_base) #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET # define ZEND_MAP_PTR_NEW_OFFSET() \ ((uint32_t)(uintptr_t)zend_map_ptr_new()) @@ -84,11 +81,8 @@ void **__p = ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)); \ *__p = (val); \ } while (0) -# define ZEND_MAP_PTR_REAL_BASE(base) \ - ((void*)(((uintptr_t)(base)) + 1)) -# define ZEND_MAP_PTR_SET_REAL_BASE(base, ptr) do { \ - base = (void*)(((uintptr_t)(ptr)) - 1); \ - } while (0) +# define ZEND_MAP_PTR_BIASED_BASE(real_base) \ + ((void*)(((uintptr_t)(real_base)) - 1)) #else # error "Unknown ZEND_MAP_PTR_KIND" #endif diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 040334ec924..19c7f35ff59 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4347,8 +4347,9 @@ static void preload_load(void) size_t old_map_ptr_last = CG(map_ptr_last); CG(map_ptr_last) = ZCSG(map_ptr_last); CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096); - ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), perealloc(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)), CG(map_ptr_size) * sizeof(void*), 1)); - memset((void **) ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)) + old_map_ptr_last, 0, + CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1); + CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base)); + memset((void **) CG(map_ptr_real_base) + old_map_ptr_last, 0, (CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *)); } }