From 6d9c84d9f0981fe87ea5ea86bc945d116f4b2b52 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 7 Oct 2022 16:19:24 +0200 Subject: [PATCH 1/2] Fix GH-9589: dl() segfaults when module is already loaded As of PHP 8.2.0, `zend_module_entry` structures are no longer copied, so when a module is permanently loaded, and users try to dynamically load that module again, the structure is corrupted[1], causing a segfault on shutdown. We catch that by checking whether any dynamically loaded module is already loaded, and bailing out in that case without modifying the `zend_module_entry` structure. [1] --- ext/standard/dl.c | 4 ++++ ext/standard/tests/general_functions/gh9589.phpt | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 ext/standard/tests/general_functions/gh9589.phpt diff --git a/ext/standard/dl.c b/ext/standard/dl.c index aae0996384562..b8d1cbc78c241 100644 --- a/ext/standard/dl.c +++ b/ext/standard/dl.c @@ -205,6 +205,10 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now) return FAILURE; } module_entry = get_module(); + if (zend_hash_str_exists(&module_registry, module_entry->name, strlen(module_entry->name))) { + zend_error(E_CORE_WARNING, "Module \"%s\" is already loaded", module_entry->name); + return FAILURE; + } if (module_entry->zend_api != ZEND_MODULE_API_NO) { php_error_docref(NULL, error_type, "%s: Unable to initialize module\n" diff --git a/ext/standard/tests/general_functions/gh9589.phpt b/ext/standard/tests/general_functions/gh9589.phpt new file mode 100644 index 0000000000000..a26f052debeb8 --- /dev/null +++ b/ext/standard/tests/general_functions/gh9589.phpt @@ -0,0 +1,10 @@ +--TEST-- +dl() segfaults when module is already loaded +--EXTENSIONS-- +dl_test +--FILE-- + +--EXPECT-- +Warning: Module "dl_test" is already loaded in Unknown on line 0 From 82562182c5d702e1370a820c00a935f8e6b48468 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 7 Oct 2022 16:51:01 +0200 Subject: [PATCH 2/2] Unload handle before bailing out --- ext/standard/dl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/standard/dl.c b/ext/standard/dl.c index b8d1cbc78c241..7b47c4726d1a7 100644 --- a/ext/standard/dl.c +++ b/ext/standard/dl.c @@ -206,6 +206,7 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now) } module_entry = get_module(); if (zend_hash_str_exists(&module_registry, module_entry->name, strlen(module_entry->name))) { + DL_UNLOAD(handle); zend_error(E_CORE_WARNING, "Module \"%s\" is already loaded", module_entry->name); return FAILURE; }