Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ PHP NEWS
request paths. (Marcel Hernandez)
. Fixed use-after-free of the scoreboard copy when logging invalid status
values. (Marcel Hernandez)
. Fixed bug GH-19520 (php_admin_value[extension] in FPM unsafely runs RINIT).
(Jakub Zelenka)
. Fixed null pointer dereference in fpm_get_status() when the scoreboard
copy fails. (Marcel Hernandez)

Expand Down
13 changes: 7 additions & 6 deletions ext/standard/dl.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ PHPAPI PHP_FUNCTION(dl)
zend_rc_debug = false;
#endif

php_dl(filename, MODULE_TEMPORARY, return_value, 0);
php_dl(filename, MODULE_TEMPORARY, return_value, PHP_DL_START_NONE);
if (Z_TYPE_P(return_value) == IS_TRUE) {
EG(full_tables_cleanup) = 1;
}
Expand Down Expand Up @@ -107,7 +107,7 @@ PHPAPI void *php_load_shlib(const char *path, char **errp)
/* }}} */

/* {{{ php_load_extension */
PHPAPI int php_load_extension(const char *filename, int type, int start_now)
PHPAPI int php_load_extension(const char *filename, int type, int start_mode)
{
void *handle;
char *libpath;
Expand Down Expand Up @@ -238,12 +238,13 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)

module_entry->handle = handle;

if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry) == FAILURE) {
if ((type == MODULE_TEMPORARY || start_mode != PHP_DL_START_NONE) && zend_startup_module_ex(module_entry) == FAILURE) {
DL_UNLOAD(handle);
return FAILURE;
}

if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) {
if ((type == MODULE_TEMPORARY || (start_mode != PHP_DL_START_NONE && start_mode != PHP_DL_START_MODULE))
&& module_entry->request_startup_func) {
if (module_entry->request_startup_func(type, module_entry->module_number) == FAILURE) {
php_error_docref(NULL, error_type, "Unable to initialize module '%s'", module_entry->name);
DL_UNLOAD(handle);
Expand Down Expand Up @@ -278,10 +279,10 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)
#endif

/* {{{ php_dl */
PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_now)
PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_mode)
{
/* Load extension */
if (php_load_extension(file, type, start_now) == FAILURE) {
if (php_load_extension(file, type, start_mode) == FAILURE) {
RETVAL_FALSE;
} else {
RETVAL_TRUE;
Expand Down
9 changes: 7 additions & 2 deletions ext/standard/dl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@
#ifndef DL_H
#define DL_H

PHPAPI int php_load_extension(const char *filename, int type, int start_now);
PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_now);
/* start modes (values 0 and 1 match the former start_now argument) */
#define PHP_DL_START_NONE 0 /* no startup */
#define PHP_DL_START_REQUEST 1 /* module and request startup */
#define PHP_DL_START_MODULE 2 /* module startup only */

PHPAPI int php_load_extension(const char *filename, int type, int start_mode);
PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_mode);
PHPAPI void *php_load_shlib(const char *path, char **errp);

/* dynamic loading functions */
Expand Down
2 changes: 1 addition & 1 deletion main/php_ini.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_t
static void php_load_php_extension_cb(void *arg)
{
#ifdef HAVE_LIBDL
php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0);
php_load_extension(*((char **) arg), MODULE_PERSISTENT, PHP_DL_START_NONE);
#endif
}
/* }}} */
Expand Down
2 changes: 1 addition & 1 deletion sapi/fpm/fpm/fpm_php.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
zend_rc_debug = false;
#endif

php_dl(value, MODULE_PERSISTENT, &zv, 1);
php_dl(value, MODULE_PERSISTENT, &zv, PHP_DL_START_MODULE);

#if ZEND_RC_DEBUG
zend_rc_debug = orig_rc_debug;
Expand Down
54 changes: 54 additions & 0 deletions sapi/fpm/tests/gh19520-php-value-ext-no-rinit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
FPM: GH-19520 - loading shared ext in FPM config must not run RINIT outside of a request
--SKIPIF--
<?php
include "skipif.inc";
FPM\Tester::skipIfSharedExtensionNotFound('dl_test');
?>
--FILE--
<?php

require_once "tester.inc";

$cfg = <<<EOT
[global]
error_log = {{FILE:LOG}}
[unconfined]
listen = {{ADDR}}
pm = static
pm.max_children = 1
catch_workers_output = yes
env[PHP_DL_TEST_MODULE_DEBUG] = 1
php_admin_value[extension] = dl_test
EOT;

$code = <<<EOT
<?php
var_dump(extension_loaded('dl_test'));
EOT;

$tester = new FPM\Tester($cfg, $code);
$tester->start();
$tester->expectLogStartNotices();
$tester->expectLogPattern('/DL TEST MINIT/');
// RINIT must not run when the extension is loaded during the child init (before any request)
$tester->expectNoLogPattern('/DL TEST RINIT/', checkAllLogs: false, timeoutMicroseconds: 200_000);
$tester->request()->expectBody('bool(true)');
$tester->expectLogPattern('/DL TEST RINIT/');
$tester->expectLogPattern('/DL TEST RSHUTDOWN/');
$tester->request()->expectBody('bool(true)');
$tester->expectLogPattern('/DL TEST RINIT/');
$tester->expectLogPattern('/DL TEST RSHUTDOWN/');
$tester->terminate();
$tester->expectLogTerminatingNotices();
$tester->close();

?>
Done
--EXPECT--
Done
--CLEAN--
<?php
require_once "tester.inc";
FPM\Tester::clean();
?>
Loading