Source: php8.4
Severity: normal
Tags: patch upstream

Dear Maintainer,

running php with a custom system wide memory allocator, like hardened
malloc[1], leads to crashes due to the used dlopen(3) flag
RTLD_DEEPBIND (upstream issue #10670).
Thus I like to propose the patch from #11094, which by default does
not change anything but adds a configuration setting
`zend.dlopen_deepbind` to support custom allocators.

Best regards,
       Christian Göttsche


[1]: https://github.com/GrapheneOS/hardened_malloc/
[2]: https://github.com/php/php-src/issues/10670
[3]: https://github.com/php/php-src/pull/11094
From: =?utf-8?q?Christian_G=C3=B6ttsche?= <cgzo...@googlemail.com>
Date: Thu, 13 Apr 2023 12:28:34 +0200
Forwarded: https://github.com/php/php-src/pull/11094
Subject: Add zend.dlopen_deepbind php.ini directive

Add a runtime configuration option to control whether loading shared
libraries via dlopen(3) uses the GNU extension flag RTLD_DEEPBIND, if
available.

The flag ensures symbol lookup will prefer symbols from the shared
object itself over global ones, which can resolve symbol namespace
collisions in third party dependencies, see 601140c ("New versions
of glibc support a RTLD_DEEPBIND flag to dlopen. The").

However using this flag symbols from preloaded libraries might be de-
prioritized, e.g. free(3) from a preloaded allocator by the standard
libc.  This results in one allocator allocating memory and another one
deallocating it, triggering double/invalid-free assertions.

Closes: https://github.com/php/php-src/issues/10670
---
 Zend/zend.c             | 1 +
 Zend/zend_globals.h     | 2 ++
 Zend/zend_portability.h | 2 +-
 php.ini-development     | 6 ++++++
 php.ini-production      | 6 ++++++
 5 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/Zend/zend.c b/Zend/zend.c
index b4a084b..c83c2bc 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -261,6 +261,7 @@ static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */
 ZEND_INI_BEGIN()
 	ZEND_INI_ENTRY("error_reporting",				NULL,		ZEND_INI_ALL,		OnUpdateErrorReporting)
 	STD_ZEND_INI_ENTRY("zend.assertions",				"1",    ZEND_INI_ALL,       OnUpdateAssertions,           assertions,   zend_executor_globals,  executor_globals)
+	STD_ZEND_INI_BOOLEAN("zend.dlopen_deepbind",		"1",	ZEND_INI_SYSTEM,	OnUpdateBool, dlopen_deepbind, zend_compiler_globals, compiler_globals)
 	ZEND_INI_ENTRY3_EX("zend.enable_gc",				"1",	ZEND_INI_ALL,		OnUpdateGCEnabled, NULL, NULL, NULL, zend_gc_enabled_displayer_cb)
 	STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte,      zend_compiler_globals, compiler_globals)
 	ZEND_INI_ENTRY("zend.script_encoding",			NULL,		ZEND_INI_ALL,		OnUpdateScriptEncoding)
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 62a97d7..a82c8f6 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -106,6 +106,8 @@ struct _zend_compiler_globals {
 
 	bool ini_parser_unbuffered_errors;
 
+	bool dlopen_deepbind;
+
 	zend_llist open_files;
 
 	struct _zend_ini_parser_param *ini_parser_param;
diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h
index 5be8d7e..80ded3c 100644
--- a/Zend/zend_portability.h
+++ b/Zend/zend_portability.h
@@ -162,7 +162,7 @@
 # if defined(RTLD_GROUP) && defined(RTLD_WORLD) && defined(RTLD_PARENT)
 #  define DL_LOAD(libname)			dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | RTLD_GROUP | RTLD_WORLD | RTLD_PARENT)
 # elif defined(RTLD_DEEPBIND) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(memory_sanitizer)
-#  define DL_LOAD(libname)			dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | RTLD_DEEPBIND)
+#  define DL_LOAD(libname)			dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | (CG(dlopen_deepbind) ? RTLD_DEEPBIND : 0))
 # else
 #  define DL_LOAD(libname)			dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL)
 # endif
diff --git a/php.ini-development b/php.ini-development
index ef35f3e..e4088c2 100644
--- a/php.ini-development
+++ b/php.ini-development
@@ -392,6 +392,12 @@ zend.exception_ignore_args = Off
 ; Production Value: 0
 zend.exception_string_param_max_len = 15
 
+; Decides whether to use the dlopen(3) flag RTLD_DEEPBIND, if available, when
+; loading shared libraries.  This ensures symbol lookup will prefer symbols from
+; the shared object itself over global ones.  Conflicts with the use of custom
+; memory allocators.
+zend.dlopen_deepbind = On
+
 ;;;;;;;;;;;;;;;;;
 ; Miscellaneous ;
 ;;;;;;;;;;;;;;;;;
diff --git a/php.ini-production b/php.ini-production
index d0ef58b..faffe38 100644
--- a/php.ini-production
+++ b/php.ini-production
@@ -388,6 +388,12 @@ zend.exception_ignore_args = On
 ; of sensitive information in stack traces.
 zend.exception_string_param_max_len = 0
 
+; Decides whether to use the dlopen(3) flag RTLD_DEEPBIND, if available, when
+; loading shared libraries.  This ensures symbol lookup will prefer symbols from
+; the shared object itself over global ones.  Conflicts with the use of custom
+; memory allocators.
+zend.dlopen_deepbind = On
+
 ;;;;;;;;;;;;;;;;;
 ; Miscellaneous ;
 ;;;;;;;;;;;;;;;;;

Reply via email to