From 4ee25395d5ebf6cffda3d71db51b571602c55a78 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Mon, 10 Nov 2025 19:14:11 +0100 Subject: [PATCH 1/2] Fix GH-20442: Phar does not respect case-insensitiveness of __halt_compiler() when reading stub Functions are case insensitive. The flush code already takes this into account by checking for the __halt_compiler() symbol in a case insensitive manner; however the parsing code did not do that yet. Closes GH-20445. --- NEWS | 4 ++++ ext/phar/phar.c | 36 ++++-------------------------- ext/phar/tests/files/gh20442.phar | Bin 0 -> 144 bytes ext/phar/tests/gh20442.phpt | 18 +++++++++++++++ 4 files changed, 26 insertions(+), 32 deletions(-) create mode 100644 ext/phar/tests/files/gh20442.phar create mode 100644 ext/phar/tests/gh20442.phpt diff --git a/NEWS b/NEWS index ba45d98c377..844c2851013 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,10 @@ PHP NEWS . Fixed bug GH-20329 (opcache.file_cache broken with full interned string buffer). (Arnaud) +- Phar: + . Fixed bug GH-20442 (Phar does not respect case-insensitiveness of + __halt_compiler() when reading stub). (ndossche, TimWolla) + - Standard: . Fix memory leak in array_diff() with custom type checks. (ndossche) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index a9aff9489df..aa9a8821d8e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1590,35 +1590,6 @@ int phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t a } /* }}}*/ -static inline char *phar_strnstr(const char *buf, size_t buf_len, const char *search, size_t search_len) /* {{{ */ -{ - const char *c; - ptrdiff_t so_far = 0; - - if (buf_len < search_len) { - return NULL; - } - - c = buf - 1; - - do { - if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) { - return (char *) NULL; - } - - so_far = c - buf; - - if (so_far >= (buf_len - search_len)) { - return (char *) NULL; - } - - if (!memcmp(c, search, search_len)) { - return (char *) c; - } - } while (1); -} -/* }}} */ - /** * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS @@ -1630,7 +1601,8 @@ static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char static const char zip_magic[] = "PK\x03\x04"; static const char gz_magic[] = "\x1f\x8b\x08"; static const char bz_magic[] = "BZh"; - char *pos, test = '\0'; + const char *pos; + char test = '\0'; int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion const int window_size = 1024; char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ @@ -1779,14 +1751,14 @@ static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char } if (got >= 512) { - if (phar_is_tar(pos, fname)) { + if (phar_is_tar((char *) pos, fname)) { /* TODO: fix const correctness */ php_stream_rewind(fp); return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error); } } } - if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) { + if (got > 0 && (pos = php_memnistr(buffer, token, tokenlen, buffer + got + sizeof(token))) != NULL) { halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */ return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error); } diff --git a/ext/phar/tests/files/gh20442.phar b/ext/phar/tests/files/gh20442.phar new file mode 100644 index 0000000000000000000000000000000000000000..26fac67ede58722561e2e65f98d1c2780592f5c6 GIT binary patch literal 144 zcmcDqFUTn1N=?qlS5Wdu&B@7E2+uFdNl{d?=8BKcNX#jTPtMOR$jnJC($KV4u(#vo zGGbt0U<6`80SFCb0s#vU7Z)Y#gV-gSLYW{M1pb4R0>KTN>6x5|x)`%GawXK)*A`AS bE9&^Sd*6ya?!N)AKV^q81J$@Y`8ojr!b~J& literal 0 HcmV?d00001 diff --git a/ext/phar/tests/gh20442.phpt b/ext/phar/tests/gh20442.phpt new file mode 100644 index 00000000000..e6862f3d33d --- /dev/null +++ b/ext/phar/tests/gh20442.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-20442 (Phar does not respect case-insensitiveness of __halt_compiler() when reading stub) +--EXTENSIONS-- +phar +--FILE-- +count()); +var_dump($phar->getStub()); + +?> +--EXPECT-- +int(1) +string(50) " +" From 33a2acba445aa50abddf62e247f394f35177124d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sun, 9 Nov 2025 15:18:22 +0100 Subject: [PATCH 2/2] Fix GH-20435: SensitiveParameter doesn't work for named argument passing to variadic parameter Closes GH-20436. --- NEWS | 2 ++ Zend/tests/function_arguments/gh20435.phpt | 14 ++++++++++++++ Zend/zend_builtin_functions.c | 22 ++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/function_arguments/gh20435.phpt diff --git a/NEWS b/NEWS index 844c2851013..28263cc2c0d 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Sync all boost.context files with release 1.86.0. (mvorisek) + . Fixed bug GH-20435 (SensitiveParameter doesn't work for named argument + passing to variadic parameter). (ndossche) - Date: . Fix crashes when trying to instantiate uninstantiable classes via date diff --git a/Zend/tests/function_arguments/gh20435.phpt b/Zend/tests/function_arguments/gh20435.phpt new file mode 100644 index 00000000000..e360b873d3c --- /dev/null +++ b/Zend/tests/function_arguments/gh20435.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20435 (SensitiveParameter doesn't work for named argument passing to variadic parameter) +--FILE-- + +--EXPECTF-- +#0 %s(%d): test(2, b: Object(SensitiveParameterValue), c: Object(SensitiveParameterValue)) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index a7e8a4fabf1..344983a6e28 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1683,11 +1683,29 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { zend_string *name; zval *arg; + + ZEND_ASSERT(call->func->common.fn_flags & ZEND_ACC_VARIADIC); + + zend_attribute *attribute = zend_get_parameter_attribute_str( + call->func->common.attributes, + "sensitiveparameter", + sizeof("sensitiveparameter") - 1, + call->func->common.num_args + ); + bool is_sensitive = attribute != NULL; + SEPARATE_ARRAY(arg_array); ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) { ZVAL_DEREF(arg); - Z_TRY_ADDREF_P(arg); - zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg); + if (is_sensitive) { + zval redacted_arg; + object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value); + zend_call_method_with_1_params(Z_OBJ_P(&redacted_arg), zend_ce_sensitive_parameter_value, &zend_ce_sensitive_parameter_value->constructor, "__construct", NULL, arg); + zend_hash_add_new(Z_ARRVAL_P(arg_array), name, &redacted_arg); + } else { + Z_TRY_ADDREF_P(arg); + zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg); + } } ZEND_HASH_FOREACH_END(); } }