From bf2ba7a8006f96794307f9184672eee61381b253 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 6 Aug 2026 20:49:08 +0100 Subject: [PATCH] Zend: include() with a non-literal argument reads out of bounds with error_include_args=1. Fix #23083 RT_CONSTANT() is only valid when op1 is a literal, so a CV or TMP operand turned a frame offset into a pointer inside the opline array. Read the operand from the call frame instead unless op1_type is IS_CONST. Close GH-23095 --- NEWS | 2 ++ Zend/tests/gh23083.phpt | 32 ++++++++++++++++++++++++++++++++ Zend/zend_exceptions.c | 12 +++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh23083.phpt diff --git a/NEWS b/NEWS index b6d2b227ce2f..7bad8e58adcb 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - Core: . Changed run-tests.php to run test subprocesses without a shell where possible. (NickSdot) + . Fixed GH-23083 (SEGV build_trace_args in zend_exceptions.c with + -d error_include_args=On). (David Carlier) - Curl: . Improved cURL option validation errors to include the option name. diff --git a/Zend/tests/gh23083.phpt b/Zend/tests/gh23083.phpt new file mode 100644 index 000000000000..a731a987967d --- /dev/null +++ b/Zend/tests/gh23083.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-23083 (SEGV in build_trace_args() with error_include_args=On and a non-literal include argument) +--INI-- +error_include_args=On +--FILE-- + +--EXPECTF-- +Warning: include('no_such_file'): Failed to open stream: No such file or directory in %s on line %d + +Warning: include('no_such_file'): Failed opening 'no_such_file' for inclusion (include_path='%s') in %s on line %d + +Warning: include('no_such_file_2'): Failed to open stream: No such file or directory in %s on line %d + +Warning: include('no_such_file_2'): Failed opening 'no_such_file_2' for inclusion (include_path='%s') in %s on line %d + +Warning: include('no_such_file'): Failed to open stream: No such file or directory in %s on line %d + +Warning: include('no_such_file'): Failed opening 'no_such_file' for inclusion (include_path='%s') in %s on line %d diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index ca91ec0ce12b..1b8297881d60 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -637,7 +637,17 @@ ZEND_API zend_string *zend_trace_current_function_args_string(void) { if (execute_data && execute_data->func && ZEND_USER_CODE(execute_data->func->common.type) && (execute_data->opline->opcode == ZEND_INCLUDE_OR_EVAL)) { - zval *inc_filename = RT_CONSTANT(execute_data->opline, execute_data->opline->op1); + zval *inc_filename; + + switch (execute_data->opline->op1_type) { + /* op1 may be CONST, TMP or CV; RT_CONSTANT() is only valid for the former. */ + case IS_CONST: + inc_filename = RT_CONSTANT(execute_data->opline, execute_data->opline->op1); + break; + default: + inc_filename = EX_VAR(execute_data->opline->op1.var); + } + smart_str str = {0}; build_trace_args(inc_filename, &str); return smart_str_extract(&str);