From b57f425cfe20a11003253427424cc0517483550b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 25 Mar 2025 22:09:16 +0100 Subject: [PATCH 01/31] PHP 8.3 is now for PHP 8.3.21-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index caad04f9d0895..22f3d75974629 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.20 +?? ??? ????, PHP 8.3.21 + + +10 Apr 2025, PHP 8.3.20 - Core: . Fixed bug GH-17961 (use-after-free during dl()'ed module class destruction). diff --git a/Zend/zend.h b/Zend/zend.h index 927088ea18706..139e6a70e15dd 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.20-dev" +#define ZEND_VERSION "4.3.21-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index a94d4958492fd..d721458a73eb2 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.20-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.21-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index 3dee6de933251..eb91f434188c6 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 -#define PHP_RELEASE_VERSION 20 +#define PHP_RELEASE_VERSION 21 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.20-dev" -#define PHP_VERSION_ID 80320 +#define PHP_VERSION "8.3.21-dev" +#define PHP_VERSION_ID 80321 From f994c2f1fa8f3fdca303e8efb1e0d7530d1dcd04 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 26 Mar 2025 19:22:15 +0100 Subject: [PATCH 02/31] Implement benchmark diff commit fallback When the base commit is not benchmarked (yet), iterate first parents of the commit until we find one that is. Fixes GH-18094 Closes GH-18152 --- benchmark/generate_diff.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/benchmark/generate_diff.php b/benchmark/generate_diff.php index b62f55c06d9e4..3a1e0d7b1370f 100644 --- a/benchmark/generate_diff.php +++ b/benchmark/generate_diff.php @@ -10,6 +10,7 @@ function main(?string $headCommitHash, ?string $baseCommitHash) { $repo = __DIR__ . '/repos/data'; cloneRepo($repo, 'git@github.com:php/benchmarking-data.git'); + $baseCommitHash = find_benchmarked_commit_hash($repo, $baseCommitHash); $headSummaryFile = $repo . '/' . substr($headCommitHash, 0, 2) . '/' . $headCommitHash . '/summary.json'; $baseSummaryFile = $repo . '/' . substr($baseCommitHash, 0, 2) . '/' . $baseCommitHash . '/summary.json'; if (!file_exists($headSummaryFile)) { @@ -60,6 +61,24 @@ function formatDiff(?int $baseInstructions, int $headInstructions): string { return sprintf('%.2f%%', $instructionDiff / $baseInstructions * 100); } +function find_benchmarked_commit_hash(string $repo, string $commitHash): ?string { + $repeat = 10; + + while (true) { + if ($repeat-- <= 0) { + fwrite(STDERR, "Count not find benchmarked commit hash\n"); + exit(1); + } + $summaryFile = $repo . '/' . substr($commitHash, 0, 2) . '/' . $commitHash . '/summary.json'; + if (file_exists($summaryFile)) { + break; + } + $commitHash = trim(runCommand(['git', 'rev-parse', $commitHash . '^'], dirname(__DIR__))->stdout); + } + + return $commitHash; +} + $headCommitHash = $argv[1] ?? null; $baseCommitHash = $argv[2] ?? null; $output = main($headCommitHash, $baseCommitHash); From 2197a490f77d018be1517913a54d24029745682c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 26 Mar 2025 22:35:21 +0100 Subject: [PATCH 03/31] Fix GH-18145: basic_globals_ctor initialization This resets all basic globals during ctor and just modifies the ones with a special value. It also switches to using basic_globals_p which what should be used in this context. Closes GH-18156 --- NEWS | 4 ++++ ext/standard/basic_functions.c | 29 +++++++---------------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 22f3d75974629..4b981f7bdd953 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,10 @@ PHP NEWS . Fixed bug GH-18018 (RC1 data returned from offsetGet causes UAF in ArrayObject). (nielsdos) +- Standard: + . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). + (Jakub Zelenka) + - Treewide: . Fixed bug GH-17736 (Assertion failure zend_reference_destroy()). (nielsdos) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 36cf727b82a24..99d92af167f0e 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -215,31 +215,16 @@ static void php_putenv_destructor(zval *zv) /* {{{ */ static void basic_globals_ctor(php_basic_globals *basic_globals_p) /* {{{ */ { - BG(umask) = -1; - BG(user_tick_functions) = NULL; - BG(user_filter_map) = NULL; - BG(serialize_lock) = 0; - - memset(&BG(serialize), 0, sizeof(BG(serialize))); - memset(&BG(unserialize), 0, sizeof(BG(unserialize))); - - memset(&BG(url_adapt_session_ex), 0, sizeof(BG(url_adapt_session_ex))); - memset(&BG(url_adapt_output_ex), 0, sizeof(BG(url_adapt_output_ex))); + memset(basic_globals_p, 0, sizeof(php_basic_globals)); - BG(url_adapt_session_ex).type = 1; - BG(url_adapt_output_ex).type = 0; + basic_globals_p->umask = -1; + basic_globals_p->url_adapt_session_ex.type = 1; - zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1); - zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1); - -#if defined(_REENTRANT) - memset(&BG(mblen_state), 0, sizeof(BG(mblen_state))); -#endif - - BG(page_uid) = -1; - BG(page_gid) = -1; + zend_hash_init(&basic_globals_p->url_adapt_session_hosts_ht, 0, NULL, NULL, 1); + zend_hash_init(&basic_globals_p->url_adapt_output_hosts_ht, 0, NULL, NULL, 1); - BG(syslog_device) = NULL; + basic_globals_p->page_uid = -1; + basic_globals_p->page_gid = -1; } /* }}} */ From fe4930612a2f116f229f743a4723bbc735637663 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 27 Mar 2025 11:53:24 +0100 Subject: [PATCH 04/31] [ci skip] Fix NEWS --- NEWS | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 4b981f7bdd953..bee2ce0e09276 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.21 +- Standard: + . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). + (Jakub Zelenka) 10 Apr 2025, PHP 8.3.20 @@ -55,10 +58,6 @@ PHP NEWS . Fixed bug GH-18018 (RC1 data returned from offsetGet causes UAF in ArrayObject). (nielsdos) -- Standard: - . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). - (Jakub Zelenka) - - Treewide: . Fixed bug GH-17736 (Assertion failure zend_reference_destroy()). (nielsdos) From a1620048fb4714ea503560406bc782e7eacfb890 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 9 Mar 2025 14:04:01 +0000 Subject: [PATCH 05/31] ext/gd: imagecrop rect argument overflow fixes. ``` ext/gd/libgd/gd.c:2275:14: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' #0 0x5d6a2103e1db in php_gd_gdImageCopy /home/dcarlier/Contribs/php-src/ext/gd/libgd/gd.c:2275 #1 0x5d6a210a2b63 in gdImageCrop /home/dcarlier/Contribs/php-src/ext/gd/libgd/gd_crop.c:57 #2 0x5d6a21018ca4 in zif_imagecrop /home/dcarlier/Contribs/php-src/ext/gd/gd.c:3575 #3 0x5d6a21e46e7a in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/dcarlier/Contribs/php-src/Zend/zend_vm_execute.h:1337 #4 0x5d6a221188da in execute_ex /home/dcarlier/Contribs/php-src/Zend/zend_vm_execute.h:57246 #5 0x5d6a221366bd in zend_execute /home/dcarlier/Contribs/php-src/Zend/zend_vm_execute.h:61634 #6 0x5d6a21d107a6 in zend_execute_scripts /home/dcarlier/Contribs/php-src/Zend/zend.c:1895 #7 0x5d6a21a63409 in php_execute_script /home/dcarlier/Contribs/php-src/main/main.c:2529 #8 0x5d6a22516d5e in do_cli /home/dcarlier/Contribs/php-src/sapi/cli/php_cli.c:966 #9 0x5d6a2251981d in main /home/dcarlier/Contribs/php-src/sapi/cli/php_cli.c:1341 #10 0x7f10d002a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #11 0x7f10d002a47a in __libc_start_main_impl ../csu/libc-start.c:360 #12 0x5d6a20a06da4 in _start (/home/dcarlier/Contribs/php-src/sapi/cli/php+0x2806da4) (BuildId: d9a79c7e0e4872311439d7313cb3a81fe04190a2) ``` close GH-18006 --- NEWS | 4 +++ ext/gd/gd.c | 20 +++++++++++++ ext/gd/tests/imagecrop_overflow.phpt | 45 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 ext/gd/tests/imagecrop_overflow.phpt diff --git a/NEWS b/NEWS index bee2ce0e09276..c08d732697cb3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.21 +- GD: + . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage + in gdImageCrop(). (David Carlier) + - Standard: . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 2585923edcc22..ae03b602cdc5b 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -3560,6 +3560,26 @@ PHP_FUNCTION(imagecrop) RETURN_THROWS(); } + if ((rect.width > 0 && rect.x > INT_MAX - rect.width)) { + zend_argument_value_error(2, "overflow with \"x\" and \"width\" keys"); + RETURN_THROWS(); + } + + if ((rect.width < 0 && rect.x < INT_MIN - rect.width)) { + zend_argument_value_error(2, "underflow with \"x\" and \"width\" keys"); + RETURN_THROWS(); + } + + if ((rect.height > 0 && rect.y > INT_MAX - rect.height)) { + zend_argument_value_error(2, "overflow with \"y\" and \"height\" keys"); + RETURN_THROWS(); + } + + if ((rect.height < 0 && rect.y < INT_MIN - rect.height)) { + zend_argument_value_error(2, "underflow with \"y\" and \"height\" keys"); + RETURN_THROWS(); + } + im_crop = gdImageCrop(im, &rect); if (im_crop == NULL) { diff --git a/ext/gd/tests/imagecrop_overflow.phpt b/ext/gd/tests/imagecrop_overflow.phpt new file mode 100644 index 0000000000000..3331a6267168a --- /dev/null +++ b/ext/gd/tests/imagecrop_overflow.phpt @@ -0,0 +1,45 @@ +--TEST-- +imagecrop() overflows when the combo x/width or y/height is over INT_MAX or under INT_MIN. +--EXTENSIONS-- +gd +--FILE-- + 2147483647, "y" => 2147483647, "width" => 10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => -2147483648, "y" => 0, "width" => -10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => 1, "y" => 2147483647, "width" => 10, "height" => 10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +$arr = ["x" => 1, "y" => -2147483648, "width" => 10, "height" => -10]; + +try { + imagecrop($img, $arr); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +imagecrop(): Argument #2 ($rectangle) overflow with "x" and "width" keys +imagecrop(): Argument #2 ($rectangle) underflow with "x" and "width" keys +imagecrop(): Argument #2 ($rectangle) overflow with "y" and "height" keys +imagecrop(): Argument #2 ($rectangle) underflow with "y" and "height" keys From c0b441f8fde516e714586d85603d8a25aea1d4e8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sun, 30 Mar 2025 00:42:59 +0100 Subject: [PATCH 06/31] [skip ci] Fix valgrind benchmark diff output Don't print command when searching benchmarked commit, as this breaks the markdown summary. --- benchmark/generate_diff.php | 6 +++++- benchmark/shared.php | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/benchmark/generate_diff.php b/benchmark/generate_diff.php index 3a1e0d7b1370f..94c020df4b998 100644 --- a/benchmark/generate_diff.php +++ b/benchmark/generate_diff.php @@ -73,7 +73,11 @@ function find_benchmarked_commit_hash(string $repo, string $commitHash): ?string if (file_exists($summaryFile)) { break; } - $commitHash = trim(runCommand(['git', 'rev-parse', $commitHash . '^'], dirname(__DIR__))->stdout); + $commitHash = trim(runCommand( + ['git', 'rev-parse', $commitHash . '^'], + dirname(__DIR__), + printCommand: false, + )->stdout); } return $commitHash; diff --git a/benchmark/shared.php b/benchmark/shared.php index 450101770b28b..0f58a2a1bf870 100644 --- a/benchmark/shared.php +++ b/benchmark/shared.php @@ -5,12 +5,14 @@ class ProcessResult { public $stderr; } -function runCommand(array $args, ?string $cwd = null): ProcessResult { +function runCommand(array $args, ?string $cwd = null, bool $printCommand = true): ProcessResult { $cmd = implode(' ', array_map('escapeshellarg', $args)); $pipes = null; $result = new ProcessResult(); $descriptorSpec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; - fwrite(STDOUT, "> $cmd\n"); + if ($printCommand) { + fwrite(STDOUT, "> $cmd\n"); + } $processHandle = proc_open($cmd, $descriptorSpec, $pipes, $cwd ?? getcwd(), null); $stdin = $pipes[0]; From 13d51f895b44c866858ee31f200f2619f99c731d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 31 Mar 2025 23:05:07 +0200 Subject: [PATCH 07/31] Add missing EXTENSIONS section to intl test [ci skip] --- ext/intl/tests/dateformat_format_references.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/intl/tests/dateformat_format_references.phpt b/ext/intl/tests/dateformat_format_references.phpt index da1a52955f121..576d901edeb82 100644 --- a/ext/intl/tests/dateformat_format_references.phpt +++ b/ext/intl/tests/dateformat_format_references.phpt @@ -1,5 +1,7 @@ --TEST-- Fix dateformat_format() with array argument with values as references. +--EXTENSIONS-- +intl --SKIPIF-- Date: Mon, 31 Mar 2025 22:06:17 +0200 Subject: [PATCH 08/31] Use-after-free in extract() with EXTR_REFS Fixes GH-18209 Closes GH-18211 --- NEWS | 1 + ext/standard/array.c | 4 +++- ext/standard/tests/gh18209.phpt | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/gh18209.phpt diff --git a/NEWS b/NEWS index c08d732697cb3..37a320d27be07 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ PHP NEWS - Standard: . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) + . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) 10 Apr 2025, PHP 8.3.20 diff --git a/ext/standard/array.c b/ext/standard/array.c index 7382e1e9f8bd9..b89deb241f046 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1863,8 +1863,10 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t } else { ZVAL_MAKE_REF_EX(entry, 2); } - zval_ptr_dtor(orig_var); + zval garbage; + ZVAL_COPY_VALUE(&garbage, orig_var); ZVAL_REF(orig_var, Z_REF_P(entry)); + zval_ptr_dtor(&garbage); } else { if (Z_ISREF_P(entry)) { Z_ADDREF_P(entry); diff --git a/ext/standard/tests/gh18209.phpt b/ext/standard/tests/gh18209.phpt new file mode 100644 index 0000000000000..6a759639f7dcb --- /dev/null +++ b/ext/standard/tests/gh18209.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-18209: Use-after-free in extract() with EXTR_REFS +--CREDITS-- +Noam Rathaus (nrathaus) +--FILE-- + 42]; +extract($array, EXTR_REFS); +var_dump($b); + +?> +--EXPECT-- +int(42) +int(43) From 2e47442a6b1e9a47d449008df2a853e6e99fada3 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 1 Apr 2025 18:58:31 +0100 Subject: [PATCH 09/31] Fix GH-18212: fseek with SEEK_CUR and negative offset crash on debug Triggers the assertion as with SEEK_CUR the stream position is set to a negative value so we force the failure without affecting its position instead. close GH-18224 --- NEWS | 2 ++ ext/standard/tests/file/gh18212.phpt | 13 +++++++++++++ ext/standard/tests/file/stream_rfc2397_007.phpt | 2 +- main/streams/streams.c | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/file/gh18212.phpt diff --git a/NEWS b/NEWS index 37a320d27be07..335903eee23c0 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) + . Fixed bug GH-18212 (fseek with SEEK_CUR whence value and negative offset + leads to negative stream position). (David Carlier) 10 Apr 2025, PHP 8.3.20 diff --git a/ext/standard/tests/file/gh18212.phpt b/ext/standard/tests/file/gh18212.phpt new file mode 100644 index 0000000000000..6e4d8ad9bd328 --- /dev/null +++ b/ext/standard/tests/file/gh18212.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-18212: fseek with SEEK_CUR and negative offset leads to negative file stream position. +--FILE-- + +--EXPECT-- +int(-1) +int(-1) + diff --git a/ext/standard/tests/file/stream_rfc2397_007.phpt b/ext/standard/tests/file/stream_rfc2397_007.phpt index dcbe5beeb3dc9..49a037e855fbd 100644 --- a/ext/standard/tests/file/stream_rfc2397_007.phpt +++ b/ext/standard/tests/file/stream_rfc2397_007.phpt @@ -118,7 +118,7 @@ int(2) bool(false) ===S:-10,C=== int(-1) -bool(false) +int(2) bool(false) ===S:3,S=== int(0) diff --git a/main/streams/streams.c b/main/streams/streams.c index 7a5dc2a58aaf1..4e0aaa53b443e 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1390,6 +1390,10 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) } whence = SEEK_SET; break; + case SEEK_SET: + if (offset < 0) { + return -1; + } } ret = stream->ops->seek(stream, offset, whence, &stream->position); From 74720a22f332cb09435405d50c312413c86af45e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 29 Mar 2025 23:36:57 +0100 Subject: [PATCH 10/31] Fix memory leak in openssl_sign() when passing invalid algorithm Closes GH-18185. --- NEWS | 4 ++++ ext/openssl/openssl.c | 1 + .../tests/openssl_sign_invalid_algorithm.phpt | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 ext/openssl/tests/openssl_sign_invalid_algorithm.phpt diff --git a/NEWS b/NEWS index 335903eee23c0..188c5a877968c 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage in gdImageCrop(). (David Carlier) +- OpenSSL: + . Fix memory leak in openssl_sign() when passing invalid algorithm. + (nielsdos) + - Standard: . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index c5720ee97e38c..bd386dbe8ae7a 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -6959,6 +6959,7 @@ PHP_FUNCTION(openssl_sign) mdtype = php_openssl_get_evp_md_from_algo(method_long); } if (!mdtype) { + EVP_PKEY_free(pkey); php_error_docref(NULL, E_WARNING, "Unknown digest algorithm"); RETURN_FALSE; } diff --git a/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt b/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt new file mode 100644 index 0000000000000..c669a373a1079 --- /dev/null +++ b/ext/openssl/tests/openssl_sign_invalid_algorithm.phpt @@ -0,0 +1,18 @@ +--TEST-- +openssl_sign: invalid algorithm +--EXTENSIONS-- +openssl +--FILE-- + +--EXPECTF-- +Warning: openssl_sign(): Unknown digest algorithm in %s on line %d From 0dc600c69aaf90361775c2d9c83094e324fae3d5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:51:58 +0200 Subject: [PATCH 11/31] Fix openssl_random_pseudo_bytes() always setting strong_result to true This regressed in 62c7432f, prior to that commit the value was set to false in case random number generation failed, but now even if an exception is thrown it is set to true. This likely does not _really_ matter as the user will handle the exception, still the value in $strong_result is observable. --- ext/openssl/openssl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index bd386dbe8ae7a..9eb052335b8d5 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -7961,17 +7961,15 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) RETURN_THROWS(); } - if (zstrong_result_returned) { - ZEND_TRY_ASSIGN_REF_FALSE(zstrong_result_returned); - } - if ((buffer = php_openssl_random_pseudo_bytes(buffer_length))) { ZSTR_VAL(buffer)[buffer_length] = 0; RETVAL_NEW_STR(buffer); - } - if (zstrong_result_returned) { - ZEND_TRY_ASSIGN_REF_TRUE(zstrong_result_returned); + if (zstrong_result_returned) { + ZEND_TRY_ASSIGN_REF_TRUE(zstrong_result_returned); + } + } else if (zstrong_result_returned) { + ZEND_TRY_ASSIGN_REF_FALSE(zstrong_result_returned); } } /* }}} */ From 5e68671f88ef92f0612bfa3e2819e5107e624418 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:54:56 +0200 Subject: [PATCH 12/31] Fix inverted call to php_openssl_store_errors() This calls php_openssl_store_errors() in the success path right now, change it to call php_openssl_store_errors() in the error path. --- ext/openssl/openssl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 9eb052335b8d5..bfbf51ff6442c 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -7940,11 +7940,10 @@ PHP_OPENSSL_API zend_string* php_openssl_random_pseudo_bytes(zend_long buffer_le PHP_OPENSSL_CHECK_LONG_TO_INT_NULL_RETURN(buffer_length, length); PHP_OPENSSL_RAND_ADD_TIME(); if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) { + php_openssl_store_errors(); zend_string_release_ex(buffer, 0); zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); return NULL; - } else { - php_openssl_store_errors(); } return buffer; From 8a1f6711bf75da789fbc23a63629d16a1925e252 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 1 Apr 2025 22:54:17 +0200 Subject: [PATCH 13/31] Fix resource leak in iptcembed() on error Closes GH-18225. --- NEWS | 1 + ext/standard/iptc.c | 1 + 2 files changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 188c5a877968c..92b199270cf4d 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ PHP NEWS . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) . Fixed bug GH-18212 (fseek with SEEK_CUR whence value and negative offset leads to negative stream position). (David Carlier) + . Fix resource leak in iptcembed() on error. (nielsdos) 10 Apr 2025, PHP 8.3.20 diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index e4dd38637570a..44dd33bab10ac 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -204,6 +204,7 @@ PHP_FUNCTION(iptcembed) if (spool < 2) { if (zend_fstat(fileno(fp), &sb) != 0) { + fclose(fp); RETURN_FALSE; } From 7a3383b482af333c03aca7d52a2012857840e746 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 3 Apr 2025 13:01:59 +0200 Subject: [PATCH 14/31] [skip ci] Restrict on-push freebsd build to main repo The same applies to all other push jobs, it was just forgotten here. --- .github/workflows/push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index ddc90935018ba..214798af62b5c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -171,6 +171,7 @@ jobs: - name: Test run: .github/scripts/windows/test.bat FREEBSD: + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' name: FREEBSD runs-on: ubuntu-latest steps: From fe8dffef5df949a3bf574023c2ee442fcc0adb3e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 4 Apr 2025 06:55:59 +0100 Subject: [PATCH 15/31] Fixed GH-18243: imagettftext underflow/overflow on size argument. close GH-18245 --- NEWS | 2 ++ ext/gd/gd.c | 11 ++++++++++ ext/gd/tests/gh18243.phpt | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 ext/gd/tests/gh18243.phpt diff --git a/NEWS b/NEWS index 92b199270cf4d..774058d253783 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - GD: . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage in gdImageCrop(). (David Carlier) + . Fixed GH-18243 imagettftext() overflow/underflow on font size value. + (David Carlier) - OpenSSL: . Fix memory leak in openssl_sign() when passing invalid algorithm. diff --git a/ext/gd/gd.c b/ext/gd/gd.c index ae03b602cdc5b..6b727a211189a 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -3082,6 +3082,17 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode) im = php_gd_libgdimageptr_from_zval_p(IM); } + // FT_F26Dot6 is a signed long alias + if (ptsize < (double)LONG_MIN / 64 || ptsize > (double)LONG_MAX / 64) { + zend_argument_value_error(2, "must be between " ZEND_LONG_FMT " and " ZEND_LONG_FMT, (zend_long)((double)LONG_MIN / 64), (zend_long)((double)LONG_MAX / 64)); + RETURN_THROWS(); + } + + if (UNEXPECTED(!zend_finite(ptsize))) { + zend_argument_value_error(2, "must be finite"); + RETURN_THROWS(); + } + /* convert angle to radians */ angle = angle * (M_PI/180); diff --git a/ext/gd/tests/gh18243.phpt b/ext/gd/tests/gh18243.phpt new file mode 100644 index 0000000000000..3235098a3dcc2 --- /dev/null +++ b/ext/gd/tests/gh18243.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-18243: imagefttext underflow/overflow on $size +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +try { + imagettftext($im, PHP_INT_MIN, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + imagettftext($im, NAN, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + imagettftext($im, INF, 0, 15, 60, 0, $font, ""); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +imagettftext(): Argument #2 ($size) must be between %i and %d +imagettftext(): Argument #2 ($size) must be between %i and %d +imagettftext(): Argument #2 ($size) must be finite +imagettftext(): Argument #2 ($size) must be between %i and %d From 61f704f26990326a86d925e1374093e9b2e2bed2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 17 Mar 2025 14:12:11 +0000 Subject: [PATCH 16/31] ext/libxml: Fixed custom external entity loader returning an invalid resource leading to a confusing TypeError message Closes GH-18096 --- NEWS | 4 ++++ ext/libxml/libxml.c | 19 ++++++++++++------- ...nal_entity_loader_error_callback_name.phpt | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 774058d253783..71430bc20b0ff 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ PHP NEWS . Fixed GH-18243 imagettftext() overflow/underflow on font size value. (David Carlier) +- libxml: + . Fixed custom external entity loader returning an invalid resource leading + to a confusing TypeError message. (Girgias) + - OpenSSL: . Fix memory leak in openssl_sign() when passing invalid algorithm. (nielsdos) diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 18ca51e36a052..5c903d2c9a228 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -793,13 +793,18 @@ static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, is_string: resource = Z_STRVAL(retval); } else if (Z_TYPE(retval) == IS_RESOURCE) { - php_stream *stream; - php_stream_from_zval_no_verify(stream, &retval); - if (stream == NULL) { - php_libxml_ctx_error(context, - "The user entity loader callback '%s' has returned a " - "resource, but it is not a stream", - ZSTR_VAL(LIBXML(entity_loader_callback).function_handler->common.function_name)); + php_stream *stream = (php_stream*)zend_fetch_resource2_ex(&retval, NULL, php_file_le_stream(), php_file_le_pstream()); + if (UNEXPECTED(stream == NULL)) { + zval callable; + zend_get_callable_zval_from_fcc(&LIBXML(entity_loader_callback), &callable); + zend_string *callable_name = zend_get_callable_name(&callable); + zend_string *func_name = get_active_function_or_method_name(); + zend_type_error( + "%s(): The user entity loader callback \"%s\" has returned a resource, but it is not a stream", + ZSTR_VAL(func_name), ZSTR_VAL(callable_name)); + zend_string_release(func_name); + zend_string_release(callable_name); + zval_ptr_dtor(&callable); } else { /* TODO: allow storing the encoding in the stream context? */ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; diff --git a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt index 1bdbbfb5b817e..2122785ef5b9b 100644 --- a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt +++ b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt @@ -40,4 +40,4 @@ $file = __DIR__ . '/db.dba'; unlink($file); ?> --EXPECT-- -string(73) "DOMDocument::validate(): supplied resource is not a valid stream resource" +string(122) "DOMDocument::validate(): The user entity loader callback "Handler::handle" has returned a resource, but it is not a stream" From 389de7c6bf59e14145e932f4d3c0171803a3ba97 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 26 Feb 2025 17:26:08 +0100 Subject: [PATCH 17/31] Fix #17776 LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden --- ext/ldap/ldap.c | 89 ++++++++++++++++++------ ext/ldap/php_ldap.h | 1 + ext/ldap/tests/ldap_start_tls_basic.phpt | 21 +++++- ext/ldap/tests/ldaps_basic.phpt | 55 +++++++++++++++ 4 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 ext/ldap/tests/ldaps_basic.phpt diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index db4c5ab231042..1a878bfc58483 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -835,6 +835,21 @@ static PHP_GINIT_FUNCTION(ldap) } /* }}} */ +/* {{{ PHP_RINIT_FUNCTION */ +static PHP_RINIT_FUNCTION(ldap) +{ +#if defined(COMPILE_DL_LDAP) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + + /* needed before first connect and after TLS option changes */ + LDAPG(tls_newctx) = true; + + return SUCCESS; +} +/* }}} */ + + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(ldap) { @@ -987,6 +1002,20 @@ PHP_FUNCTION(ldap_connect) snprintf( url, urllen, "ldap://%s:" ZEND_LONG_FMT, host, port ); } +#ifdef LDAP_OPT_X_TLS_NEWCTX + if (LDAPG(tls_newctx) && url && !strncmp(url, "ldaps:", 6)) { + int val = 0; + + /* ensure all pending TLS options are applied in a new context */ + if (ldap_set_option(NULL, LDAP_OPT_X_TLS_NEWCTX, &val) != LDAP_OPT_SUCCESS) { + zval_ptr_dtor(return_value); + php_error_docref(NULL, E_WARNING, "Could not create new security context"); + RETURN_FALSE; + } + LDAPG(tls_newctx) = false; + } +#endif + #ifdef LDAP_API_FEATURE_X_OPENLDAP /* ldap_init() is deprecated, use ldap_initialize() instead. */ @@ -3172,15 +3201,7 @@ PHP_FUNCTION(ldap_set_option) } switch (option) { - /* options with int value */ - case LDAP_OPT_DEREF: - case LDAP_OPT_SIZELIMIT: - case LDAP_OPT_TIMELIMIT: - case LDAP_OPT_PROTOCOL_VERSION: - case LDAP_OPT_ERROR_NUMBER: -#ifdef LDAP_OPT_DEBUG_LEVEL - case LDAP_OPT_DEBUG_LEVEL: -#endif + /* TLS options with int value */ #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT case LDAP_OPT_X_TLS_REQUIRE_CERT: #endif @@ -3189,6 +3210,18 @@ PHP_FUNCTION(ldap_set_option) #endif #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN case LDAP_OPT_X_TLS_PROTOCOL_MIN: +#endif + /* TLS option change requires resetting TLS context */ + LDAPG(tls_newctx) = true; + ZEND_FALLTHROUGH; + /* other options with int value */ + case LDAP_OPT_DEREF: + case LDAP_OPT_SIZELIMIT: + case LDAP_OPT_TIMELIMIT: + case LDAP_OPT_PROTOCOL_VERSION: + case LDAP_OPT_ERROR_NUMBER: +#ifdef LDAP_OPT_DEBUG_LEVEL + case LDAP_OPT_DEBUG_LEVEL: #endif #ifdef LDAP_OPT_X_KEEPALIVE_IDLE case LDAP_OPT_X_KEEPALIVE_IDLE: @@ -3245,17 +3278,7 @@ PHP_FUNCTION(ldap_set_option) } } break; #endif - /* options with string value */ - case LDAP_OPT_ERROR_STRING: -#ifdef LDAP_OPT_HOST_NAME - case LDAP_OPT_HOST_NAME: -#endif -#ifdef HAVE_LDAP_SASL - case LDAP_OPT_X_SASL_MECH: - case LDAP_OPT_X_SASL_REALM: - case LDAP_OPT_X_SASL_AUTHCID: - case LDAP_OPT_X_SASL_AUTHZID: -#endif + /* TLS options with string value */ #if (LDAP_API_VERSION > 2000) case LDAP_OPT_X_TLS_CACERTDIR: case LDAP_OPT_X_TLS_CACERTFILE: @@ -3269,6 +3292,20 @@ PHP_FUNCTION(ldap_set_option) #endif #ifdef LDAP_OPT_X_TLS_DHFILE case LDAP_OPT_X_TLS_DHFILE: +#endif + /* TLS option change requires resetting TLS context */ + LDAPG(tls_newctx) = true; + ZEND_FALLTHROUGH; + /* other options with string value */ + case LDAP_OPT_ERROR_STRING: +#ifdef LDAP_OPT_HOST_NAME + case LDAP_OPT_HOST_NAME: +#endif +#ifdef HAVE_LDAP_SASL + case LDAP_OPT_X_SASL_MECH: + case LDAP_OPT_X_SASL_REALM: + case LDAP_OPT_X_SASL_AUTHCID: + case LDAP_OPT_X_SASL_AUTHZID: #endif #ifdef LDAP_OPT_MATCHED_DN case LDAP_OPT_MATCHED_DN: @@ -3688,6 +3725,9 @@ PHP_FUNCTION(ldap_start_tls) zval *link; ldap_linkdata *ld; int rc, protocol = LDAP_VERSION3; +#ifdef LDAP_OPT_X_TLS_NEWCTX + int val = 0; +#endif if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &link, ldap_link_ce) != SUCCESS) { RETURN_THROWS(); @@ -3697,13 +3737,16 @@ PHP_FUNCTION(ldap_start_tls) VERIFY_LDAP_LINK_CONNECTED(ld); if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) || +#ifdef LDAP_OPT_X_TLS_NEWCTX + (LDAPG(tls_newctx) && (rc = ldap_set_option(ld->link, LDAP_OPT_X_TLS_NEWCTX, &val)) != LDAP_OPT_SUCCESS) || +#endif ((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS) ) { php_error_docref(NULL, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc)); RETURN_FALSE; - } else { - RETURN_TRUE; } + LDAPG(tls_newctx) = false; + RETURN_TRUE; } /* }}} */ #endif @@ -4218,7 +4261,7 @@ zend_module_entry ldap_module_entry = { /* {{{ */ ext_functions, PHP_MINIT(ldap), PHP_MSHUTDOWN(ldap), - NULL, + PHP_RINIT(ldap), NULL, PHP_MINFO(ldap), PHP_LDAP_VERSION, diff --git a/ext/ldap/php_ldap.h b/ext/ldap/php_ldap.h index 5581f5b7671a8..a8c4a77af8010 100644 --- a/ext/ldap/php_ldap.h +++ b/ext/ldap/php_ldap.h @@ -39,6 +39,7 @@ PHP_MINFO_FUNCTION(ldap); ZEND_BEGIN_MODULE_GLOBALS(ldap) zend_long num_links; zend_long max_links; + bool tls_newctx; /* create new TLS context before connect */ ZEND_END_MODULE_GLOBALS(ldap) #if defined(ZTS) && defined(COMPILE_DL_LDAP) diff --git a/ext/ldap/tests/ldap_start_tls_basic.phpt b/ext/ldap/tests/ldap_start_tls_basic.phpt index 4dbdce034369f..b8816de9ac4f5 100644 --- a/ext/ldap/tests/ldap_start_tls_basic.phpt +++ b/ext/ldap/tests/ldap_start_tls_basic.phpt @@ -9,11 +9,28 @@ ldap --FILE-- --EXPECT-- +bool(false) bool(true) +bool(false) diff --git a/ext/ldap/tests/ldaps_basic.phpt b/ext/ldap/tests/ldaps_basic.phpt new file mode 100644 index 0000000000000..7a1a1383436d7 --- /dev/null +++ b/ext/ldap/tests/ldaps_basic.phpt @@ -0,0 +1,55 @@ +--TEST-- +ldap_connect() - Basic ldaps test +--EXTENSIONS-- +ldap +--XFAIL-- +Passes locally but fails on CI - need investigation (configuration ?) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) From 98fb27a5775a1d73029822280c7c67128008aa54 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 10 Apr 2025 17:09:03 +0200 Subject: [PATCH 18/31] NEWS for GH-17940 --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 71430bc20b0ff..416d97aeee93f 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,9 @@ PHP NEWS . Fixed GH-18243 imagettftext() overflow/underflow on font size value. (David Carlier) +- LDAP: + . Fixed bug GH-17940 (LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden). (Remi) + - libxml: . Fixed custom external entity loader returning an invalid resource leading to a confusing TypeError message. (Girgias) From 90f582b1880e7ff09f083dfd326e82a8730ee9fd Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 10 Apr 2025 17:21:15 +0200 Subject: [PATCH 19/31] [ci skip] fix news --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 416d97aeee93f..6e91f46dc6b18 100644 --- a/NEWS +++ b/NEWS @@ -9,7 +9,7 @@ PHP NEWS (David Carlier) - LDAP: - . Fixed bug GH-17940 (LDAP_OPT_X_TLS_REQUIRE_CERT can't be overridden). (Remi) + . Fixed bug GH-17776 (LDAP_OPT_X_TLS_* options can't be overridden). (Remi) - libxml: . Fixed custom external entity loader returning an invalid resource leading From 29f96fb1f19a87d92421ba8d45a96c3cf18f9994 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 29 Mar 2025 23:42:45 +0100 Subject: [PATCH 20/31] Fix potential leaks when writing to BIO fails When the BIO is created but writing fails, these can leak. Closes GH-18186. --- NEWS | 1 + ext/openssl/openssl.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 6e91f46dc6b18..045d9c8d9f431 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ PHP NEWS - OpenSSL: . Fix memory leak in openssl_sign() when passing invalid algorithm. (nielsdos) + . Fix potential leaks when writing to BIO fails. (nielsdos) - Standard: . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index bfbf51ff6442c..c978859b7ec00 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -5742,8 +5742,8 @@ PHP_FUNCTION(openssl_pkcs7_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -5757,8 +5757,8 @@ PHP_FUNCTION(openssl_pkcs7_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -6383,8 +6383,8 @@ PHP_FUNCTION(openssl_cms_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } @@ -6398,8 +6398,8 @@ PHP_FUNCTION(openssl_cms_read) BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); - BIO_free(bio_out); } + BIO_free(bio_out); } } From ba0853888d8735b1d46fbe26ca7254327b1423aa Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 11 Apr 2025 18:18:14 +0200 Subject: [PATCH 21/31] Fix GH-18304: Changing the properties of a DateInterval through dynamic properties triggers a SegFault For dynamic fetches the cache_slot will be NULL, so we have to check for that when resetting the cache. For zip and xmlreader this couldn't easily be tested because of a lack of writable properties. Closes GH-18307. --- NEWS | 4 ++++ ext/date/php_date.c | 4 +++- ext/date/tests/gh18304.phpt | 35 ++++++++++++++++++++++++++++++++ ext/dom/php_dom.c | 4 +++- ext/dom/tests/gh18304.phpt | 15 ++++++++++++++ ext/pdo/pdo_stmt.c | 5 +++-- ext/simplexml/simplexml.c | 4 +++- ext/simplexml/tests/gh18304.phpt | 18 ++++++++++++++++ ext/snmp/snmp.c | 4 +++- ext/snmp/tests/gh18304.phpt | 15 ++++++++++++++ ext/spl/spl_array.c | 4 +++- ext/spl/tests/gh18304.phpt | 14 +++++++++++++ ext/xmlreader/php_xmlreader.c | 4 ++-- ext/zip/php_zip.c | 4 ++-- 14 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 ext/date/tests/gh18304.phpt create mode 100644 ext/dom/tests/gh18304.phpt create mode 100644 ext/simplexml/tests/gh18304.phpt create mode 100644 ext/snmp/tests/gh18304.phpt create mode 100644 ext/spl/tests/gh18304.phpt diff --git a/NEWS b/NEWS index 045d9c8d9f431..64911472be3b3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.21 +- Core: + . Fixed bug GH-18304 (Changing the properties of a DateInterval through + dynamic properties triggers a SegFault). (nielsdos) + - GD: . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage in gdImageCrop(). (David Carlier) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 6f7796eec1250..c1faa842f8a12 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4399,7 +4399,9 @@ static zval *date_interval_get_property_ptr_ptr(zend_object *object, zend_string zend_string_equals_literal(name, "days") || zend_string_equals_literal(name, "invert") ) { /* Fallback to read_property. */ - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } ret = NULL; } else { ret = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); diff --git a/ext/date/tests/gh18304.phpt b/ext/date/tests/gh18304.phpt new file mode 100644 index 0000000000000..4bab058a7ec4a --- /dev/null +++ b/ext/date/tests/gh18304.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--FILE-- +$field += $i; +var_dump($di); +?> +--EXPECT-- +object(DateInterval)#1 (10) { + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(1) + ["h"]=> + int(0) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +} diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 1da53bae64b51..841dcd66186f8 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -303,7 +303,9 @@ static zval *dom_get_property_ptr_ptr(zend_object *object, zend_string *name, in return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); } - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } diff --git a/ext/dom/tests/gh18304.phpt b/ext/dom/tests/gh18304.phpt new file mode 100644 index 0000000000000..ead44306ff801 --- /dev/null +++ b/ext/dom/tests/gh18304.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +dom +--FILE-- +$field .= 'hello'; +var_dump($text->$field); +?> +--EXPECT-- +string(5) "hello" diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index efbf519e5411e..8454b4875374e 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2493,9 +2493,10 @@ static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name ZEND_IGNORE_VALUE(object); ZEND_IGNORE_VALUE(name); ZEND_IGNORE_VALUE(type); - ZEND_IGNORE_VALUE(cache_slot); - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 46ec3a2a788ab..11f497a6673ea 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -635,7 +635,9 @@ static zval *sxe_property_get_adr(zend_object *object, zend_string *zname, int f SXE_ITER type; zval member; - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } sxe = php_sxe_fetch_object(object); GET_NODE(sxe, node); diff --git a/ext/simplexml/tests/gh18304.phpt b/ext/simplexml/tests/gh18304.phpt new file mode 100644 index 0000000000000..b92690856e231 --- /dev/null +++ b/ext/simplexml/tests/gh18304.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +simplexml +--FILE-- +'); +$field = 'abc'; +$sxe->$field .= 'hello'; +var_dump($sxe->$field); +?> +--EXPECT-- +object(SimpleXMLElement)#3 (1) { + [0]=> + string(5) "hello" +} diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 02348a5fbca00..0ba39ed87c241 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1861,7 +1861,9 @@ static zval *php_snmp_get_property_ptr_ptr(zend_object *object, zend_string *nam return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); } - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } return NULL; } diff --git a/ext/snmp/tests/gh18304.phpt b/ext/snmp/tests/gh18304.phpt new file mode 100644 index 0000000000000..2faf503ac1a58 --- /dev/null +++ b/ext/snmp/tests/gh18304.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--EXTENSIONS-- +snmp +--FILE-- +$field++; +var_dump($snmp->$field); +?> +--EXPECT-- +int(1) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 8d4541797a1c5..0abaf743ac9d1 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -846,7 +846,9 @@ static zval *spl_array_get_property_ptr_ptr(zend_object *object, zend_string *na if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 && !zend_std_has_property(object, name, ZEND_PROPERTY_EXISTS, NULL)) { - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; + } /* If object has offsetGet() overridden, then fallback to read_property, * which will call offsetGet(). */ diff --git a/ext/spl/tests/gh18304.phpt b/ext/spl/tests/gh18304.phpt new file mode 100644 index 0000000000000..d93ee3534d0d4 --- /dev/null +++ b/ext/spl/tests/gh18304.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault) +--CREDITS-- +orose-assetgo +--FILE-- + 1]); +$ao->setFlags(ArrayObject::ARRAY_AS_PROPS); +$field = 'abc'; +$ao->$field++; +var_dump($ao->$field); +?> +--EXPECT-- +int(2) diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 569058e91a454..dca1898f1c044 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -121,8 +121,6 @@ zval *xmlreader_get_property_ptr_ptr(zend_object *object, zend_string *name, int zval *retval = NULL; xmlreader_prop_handler *hnd = NULL; - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; - obj = php_xmlreader_fetch_object(object); if (obj->prop_handler != NULL) { @@ -131,6 +129,8 @@ zval *xmlreader_get_property_ptr_ptr(zend_object *object, zend_string *name, int if (hnd == NULL) { retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); + } else if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; } return retval; diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index e28cf688dcff8..172057685105b 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -890,8 +890,6 @@ static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name zval *retval = NULL; zip_prop_handler *hnd = NULL; - cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; - obj = php_zip_fetch_object(object); if (obj->prop_handler != NULL) { @@ -900,6 +898,8 @@ static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name if (hnd == NULL) { retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot); + } else if (cache_slot) { + cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL; } return retval; From 8849a5336ea6feda910567acca34407901d3fc57 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 11 Apr 2025 20:59:34 +0200 Subject: [PATCH 22/31] Fix GH-18309: ipv6 filter integer overflow The intermediate computation can cause a signed integer overflow, but the input is correctly rejected later on by the check on variable `n`. Solve this by using an unsigned number. Closes GH-18312. --- NEWS | 3 +++ ext/filter/logical_filters.c | 3 ++- ext/filter/tests/gh18309.phpt | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 ext/filter/tests/gh18309.phpt diff --git a/NEWS b/NEWS index 64911472be3b3..c652b3b83744a 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ PHP NEWS . Fixed bug GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault). (nielsdos) +- Filter: + . Fixed bug GH-18309 (ipv6 filter integer overflow). (nielsdos) + - GD: . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage in gdImageCrop(). (David Carlier) diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 1bd9bad5afbe1..76656a218d281 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -762,7 +762,8 @@ static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) { int compressed_pos = -1; int blocks = 0; - int num, n, i; + unsigned int num, n; + int i; char *ipv4; const char *end; int ip4elm[4]; diff --git a/ext/filter/tests/gh18309.phpt b/ext/filter/tests/gh18309.phpt new file mode 100644 index 0000000000000..b541f10883fe6 --- /dev/null +++ b/ext/filter/tests/gh18309.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-18309 (ipv6 filter integer overflow) +--EXTENSIONS-- +filter +--FILE-- + +--EXPECT-- +bool(false) From 67503870ca2957aca9270bad324b32ab349559aa Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:29:08 +0200 Subject: [PATCH 23/31] Fix GH-18322: SplObjectStorage debug handler mismanages memory This hack was once necessary before there was a proper get_gc handler, but now it breaks the engine constraints. Closes GH-18323. --- NEWS | 4 ++++ ext/spl/spl_observer.c | 6 ++---- ext/spl/tests/gh18322.phpt | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 ext/spl/tests/gh18322.phpt diff --git a/NEWS b/NEWS index c652b3b83744a..6e5a4bc4cfc62 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ PHP NEWS (nielsdos) . Fix potential leaks when writing to BIO fails. (nielsdos) +- SPL: + . Fixed bug GH-18322 (SplObjectStorage debug handler mismanages memory). + (nielsdos) + - Standard: . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index b3a27cb10292c..83889c430b7a2 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -340,12 +340,10 @@ static inline HashTable* spl_object_storage_debug_info(zend_object *obj) /* {{{ ZEND_HASH_FOREACH_PTR(&intern->storage, element) { array_init(&tmp); - /* Incrementing the refcount of obj and inf would confuse the garbage collector. - * Prefer to null the destructor */ - Z_ARRVAL_P(&tmp)->pDestructor = NULL; zval obj; - ZVAL_OBJ(&obj, element->obj); + ZVAL_OBJ_COPY(&obj, element->obj); add_assoc_zval_ex(&tmp, "obj", sizeof("obj") - 1, &obj); + Z_TRY_ADDREF(element->inf); add_assoc_zval_ex(&tmp, "inf", sizeof("inf") - 1, &element->inf); zend_hash_next_index_insert(Z_ARRVAL(storage), &tmp); } ZEND_HASH_FOREACH_END(); diff --git a/ext/spl/tests/gh18322.phpt b/ext/spl/tests/gh18322.phpt new file mode 100644 index 0000000000000..e70cbd0d37dd5 --- /dev/null +++ b/ext/spl/tests/gh18322.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-18322 (SplObjectStorage debug handler mismanages memory) +--FILE-- +__debugInfo(); +$tmp2 = $tmp[array_key_first($tmp)]; +unset($tmp); // Drop $tmp2 RC to 1 +$tmp2[0]['obj'] = new stdClass; +var_dump($tmp2); + +?> +--EXPECT-- +array(1) { + [0]=> + array(2) { + ["obj"]=> + object(stdClass)#3 (0) { + } + ["inf"]=> + int(1) + } +} From 701f3a1af67029a1d953ca054f33385be32c7f4a Mon Sep 17 00:00:00 2001 From: haszi Date: Tue, 9 Jan 2024 14:43:44 +0100 Subject: [PATCH 24/31] Mark ob_start callback parameter nullable --- ext/standard/basic_functions.stub.php | 2 +- ext/standard/basic_functions_arginfo.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index be9b024258ee8..3bdc3827b4d36 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1513,7 +1513,7 @@ function header_register_callback(callable $callback): bool {} /* main/output.c */ -/** @param callable $callback */ +/** @param callable|null $callback */ function ob_start($callback = null, int $chunk_size = 0, int $flags = PHP_OUTPUT_HANDLER_STDFLAGS): bool {} function ob_flush(): bool {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 99e08feddf590..1361cf6062797 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7389d094a842a2289cd32cb37386e5e40ea7e031 */ + * Stub hash: 2a3d8da0b92134dcca74f2ac70454bd27768f20e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) From 9d4f8b5379f2dfb071f4311ed5d0c421e014dbf7 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 8 Apr 2025 23:32:36 +0900 Subject: [PATCH 25/31] Fixed GH-18276 - persistent connection - "zend_mm_heap corrupted" with setAttribute() (#18280) Closes #18280 Fixes #18276 --- NEWS | 4 ++++ ext/pdo_firebird/firebird_driver.c | 21 +++++++++-------- ext/pdo_firebird/tests/gh18276.phpt | 35 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 ext/pdo_firebird/tests/gh18276.phpt diff --git a/NEWS b/NEWS index 6e5a4bc4cfc62..7d660e26cef75 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ PHP NEWS (nielsdos) . Fix potential leaks when writing to BIO fails. (nielsdos) +- PDO Firebird: + . Fixed GH-18276 - persistent connection - "zend_mm_heap corrupted" + with setAttribute() (SakiTakamachi). + - SPL: . Fixed bug GH-18322 (SplObjectStorage debug handler mismanages memory). (nielsdos) diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 4f8cd83d7b8ab..504e739a974d9 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -492,13 +492,13 @@ static void firebird_handle_closer(pdo_dbh_t *dbh) /* {{{ */ } if (H->date_format) { - efree(H->date_format); + pefree(H->date_format, dbh->is_persistent); } if (H->time_format) { - efree(H->time_format); + pefree(H->time_format, dbh->is_persistent); } if (H->timestamp_format) { - efree(H->timestamp_format); + pefree(H->timestamp_format, dbh->is_persistent); } pefree(H, dbh->is_persistent); @@ -881,9 +881,10 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval * return false; } if (H->date_format) { - efree(H->date_format); + pefree(H->date_format, dbh->is_persistent); + H->date_format = NULL; } - spprintf(&H->date_format, 0, "%s", ZSTR_VAL(str)); + H->date_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); zend_string_release_ex(str, 0); } return true; @@ -895,9 +896,10 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval * return false; } if (H->time_format) { - efree(H->time_format); + pefree(H->time_format, dbh->is_persistent); + H->time_format = NULL; } - spprintf(&H->time_format, 0, "%s", ZSTR_VAL(str)); + H->time_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); zend_string_release_ex(str, 0); } return true; @@ -909,9 +911,10 @@ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval * return false; } if (H->timestamp_format) { - efree(H->timestamp_format); + pefree(H->timestamp_format, dbh->is_persistent); + H->timestamp_format = NULL; } - spprintf(&H->timestamp_format, 0, "%s", ZSTR_VAL(str)); + H->timestamp_format = pestrndup(ZSTR_VAL(str), ZSTR_LEN(str),dbh->is_persistent); zend_string_release_ex(str, 0); } return true; diff --git a/ext/pdo_firebird/tests/gh18276.phpt b/ext/pdo_firebird/tests/gh18276.phpt new file mode 100644 index 0000000000000..610876166ccf7 --- /dev/null +++ b/ext/pdo_firebird/tests/gh18276.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-18276 (persistent connection - setAttribute(Pdo\Firebird::ATTR_DATE_FORMAT, ..) results in "zend_mm_heap corrupted") +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- + true, + ], + ); + // Avoid interned + $dbh->setAttribute(PDO::FB_ATTR_DATE_FORMAT, str_repeat('Y----m----d', random_int(1, 1))); + $dbh->setAttribute(PDO::FB_ATTR_TIME_FORMAT, str_repeat('H::::i::::s', random_int(1, 1))); + $dbh->setAttribute(PDO::FB_ATTR_TIMESTAMP_FORMAT, str_repeat('Y----m----d....H::::i::::s', random_int(1, 1))); + unset($dbh); +} + +echo 'done!'; +?> +--EXPECT-- +done! From 0a6326c6ac93c53b8804d23d1d42bf91475a260d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:58:33 +0200 Subject: [PATCH 26/31] Fix uouv when handling empty options in ZipArchive::addGlob() Reported by OpenAI AARDVARK. php_zip_parse_option is only called when options are passed to the function. Prior to this patch, php_zip_parse_option was responsible for zeroing the opts variable. So in the case when php_zip_parse_option is not called, opts remains uninitialized yet it is being used anyway. By just always zeroing opts at declaration time, we avoid this issue and we are unlikely to reintroduce this in the future. Closes GH-18329. --- NEWS | 3 +++ ext/zip/php_zip.c | 4 ++-- ext/zip/tests/addGlob_empty_options.phpt | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ext/zip/tests/addGlob_empty_options.phpt diff --git a/NEWS b/NEWS index 7d660e26cef75..a3f2990962d42 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,9 @@ PHP NEWS leads to negative stream position). (David Carlier) . Fix resource leak in iptcembed() on error. (nielsdos) +- Zip: + . Fix uouv when handling empty options in ZipArchive::addGlob(). (nielsdos) + 10 Apr 2025, PHP 8.3.20 - Core: diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 172057685105b..be096ad56e29d 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -354,13 +354,13 @@ typedef struct { #endif } zip_options; +/* Expects opts to be zero-initialized. */ static int php_zip_parse_options(HashTable *options, zip_options *opts) /* {{{ */ { zval *option; /* default values */ - memset(opts, 0, sizeof(zip_options)); opts->flags = ZIP_FL_OVERWRITE; opts->comp_method = -1; /* -1 to not change default */ #ifdef HAVE_ENCRYPTION @@ -1732,7 +1732,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* size_t path_len = 1; zend_long glob_flags = 0; HashTable *options = NULL; - zip_options opts; + zip_options opts = {0}; int found; zend_string *pattern; diff --git a/ext/zip/tests/addGlob_empty_options.phpt b/ext/zip/tests/addGlob_empty_options.phpt new file mode 100644 index 0000000000000..f4a4126059a7b --- /dev/null +++ b/ext/zip/tests/addGlob_empty_options.phpt @@ -0,0 +1,22 @@ +--TEST-- +addGlob with empty options +--EXTENSIONS-- +zip +--FILE-- +open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$zip->addGlob(__FILE__, 0, []); +var_dump($zip->statIndex(0)['name'] === __FILE__); +$zip->close(); + +?> +--CLEAN-- + +--EXPECT-- +bool(true) From 91c6c727d516716855d6fa8bd75908cd3249d17e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:59:25 +0200 Subject: [PATCH 27/31] Fix memory leak when handling a too long path in ZipArchive::addGlob() Closes GH-18330. --- NEWS | 2 ++ ext/zip/php_zip.c | 3 +++ .../addGlob_too_long_add_path_option.phpt | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 ext/zip/tests/addGlob_too_long_add_path_option.phpt diff --git a/NEWS b/NEWS index a3f2990962d42..22ce2f45ecca0 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,8 @@ PHP NEWS - Zip: . Fix uouv when handling empty options in ZipArchive::addGlob(). (nielsdos) + . Fix memory leak when handling a too long path in ZipArchive::addGlob(). + (nielsdos) 10 Apr 2025, PHP 8.3.20 diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index be096ad56e29d..45b83aeae63bc 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1796,6 +1796,9 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* if (opts.add_path) { if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) { + if (basename) { + zend_string_release_ex(basename, 0); + } php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)", MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len)); zend_array_destroy(Z_ARR_P(return_value)); diff --git a/ext/zip/tests/addGlob_too_long_add_path_option.phpt b/ext/zip/tests/addGlob_too_long_add_path_option.phpt new file mode 100644 index 0000000000000..9598eeca40a89 --- /dev/null +++ b/ext/zip/tests/addGlob_too_long_add_path_option.phpt @@ -0,0 +1,21 @@ +--TEST-- +addGlob with too long add_path option +--EXTENSIONS-- +zip +--FILE-- +open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$zip->addGlob(__FILE__, 0, ['add_path' => str_repeat('A', PHP_MAXPATHLEN - 2)]); +$zip->close(); + +?> +--CLEAN-- + +--EXPECTF-- +Warning: ZipArchive::addGlob(): Entry name too long (max: %d, %d given) in %s on line %d From c905d5910645b6024faee6ce791ab884e739c767 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 16 Apr 2025 00:09:35 +0200 Subject: [PATCH 28/31] Fix NULL deref on high modification key We should re-index in the loop. Closes GH-18331. --- NEWS | 1 + ext/ldap/ldap.c | 8 +++++--- ext/ldap/tests/ldap_modify_batch_error.phpt | 13 +++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 22ce2f45ecca0..ac31131ea9d22 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ PHP NEWS - LDAP: . Fixed bug GH-17776 (LDAP_OPT_X_TLS_* options can't be overridden). (Remi) + . Fix NULL deref on high modification key. (nielsdos) - libxml: . Fixed custom external entity loader returning an invalid resource leading diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 1a878bfc58483..6c005337346b5 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -2785,12 +2785,12 @@ PHP_FUNCTION(ldap_modify_batch) ldap_mods = safe_emalloc((num_mods+1), sizeof(LDAPMod *), 0); /* for each modification */ - for (i = 0; i < num_mods; i++) { + i = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(mods), fetched) { /* allocate the modification struct */ ldap_mods[i] = safe_emalloc(1, sizeof(LDAPMod), 0); /* fetch the relevant data */ - fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i); mod = fetched; _ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_ATTRIB, &attrib); @@ -2855,7 +2855,9 @@ PHP_FUNCTION(ldap_modify_batch) /* NULL-terminate values */ ldap_mods[i]->mod_bvalues[num_modvals] = NULL; } - } + + i++; + } ZEND_HASH_FOREACH_END(); /* NULL-terminate modifications */ ldap_mods[num_mods] = NULL; diff --git a/ext/ldap/tests/ldap_modify_batch_error.phpt b/ext/ldap/tests/ldap_modify_batch_error.phpt index bce62cafb2791..0ac093b4a0341 100644 --- a/ext/ldap/tests/ldap_modify_batch_error.phpt +++ b/ext/ldap/tests/ldap_modify_batch_error.phpt @@ -59,6 +59,16 @@ $mods = array( ) ); +var_dump(ldap_modify_batch($link, "dc=my-domain,$base", $mods)); + +// high key with invalid attribute type +$mods = [ + 99999 => [ + "attrib" => "weirdAttribute", + "modtype" => LDAP_MODIFY_BATCH_ADD, + "values" => ["value1"], + ], +]; var_dump(ldap_modify_batch($link, "dc=my-domain,$base", $mods)); ?> --CLEAN-- @@ -81,3 +91,6 @@ bool(false) Warning: ldap_modify_batch(): Batch Modify: Undefined attribute type in %s on line %d bool(false) + +Warning: ldap_modify_batch(): Batch Modify: Undefined attribute type in %s on line %d +bool(false) From bf4b470098122953e47aed6b56ea8a96570e1680 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 20 Apr 2025 12:25:45 +0200 Subject: [PATCH 29/31] Fix reference support for intltz_get_offset() It should use the helper macros such that types are properly respected. Closes GH-18364. --- NEWS | 3 +++ .../tests/intltz_get_offset_references.phpt | 26 +++++++++++++++++++ ext/intl/timezone/timezone_methods.cpp | 8 +++--- 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 ext/intl/tests/intltz_get_offset_references.phpt diff --git a/NEWS b/NEWS index ac31131ea9d22..55a58a4d8e78f 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ PHP NEWS . Fixed GH-18243 imagettftext() overflow/underflow on font size value. (David Carlier) +- Intl: + . Fix reference support for intltz_get_offset(). (nielsdos) + - LDAP: . Fixed bug GH-17776 (LDAP_OPT_X_TLS_* options can't be overridden). (Remi) . Fix NULL deref on high modification key. (nielsdos) diff --git a/ext/intl/tests/intltz_get_offset_references.phpt b/ext/intl/tests/intltz_get_offset_references.phpt new file mode 100644 index 0000000000000..6f104863d2212 --- /dev/null +++ b/ext/intl/tests/intltz_get_offset_references.phpt @@ -0,0 +1,26 @@ +--TEST-- +intltz_get_offset references +--EXTENSIONS-- +intl +--FILE-- +a = $test->b = "hello"; + +$rawOffset =& $test->a; +$dstOffset =& $test->b; +intltz_get_offset($tz, 0.0, true, $rawOffset, $dstOffset); +var_dump($test); +?> +--EXPECT-- +object(Test)#2 (2) { + ["a"]=> + &string(7) "3600000" + ["b"]=> + &string(1) "0" +} diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index cae64026fa5db..580a721e79ec1 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -419,7 +419,7 @@ U_CFUNC PHP_FUNCTION(intltz_get_offset) TIMEZONE_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), - "Odbz/z/", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg, + "Odbzz", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg, &dstOffsetArg) == FAILURE) { RETURN_THROWS(); } @@ -431,10 +431,8 @@ U_CFUNC PHP_FUNCTION(intltz_get_offset) INTL_METHOD_CHECK_STATUS(to, "intltz_get_offset: error obtaining offset"); - zval_ptr_dtor(rawOffsetArg); - ZVAL_LONG(rawOffsetArg, rawOffset); - zval_ptr_dtor(dstOffsetArg); - ZVAL_LONG(dstOffsetArg, dstOffset); + ZEND_TRY_ASSIGN_REF_LONG(rawOffsetArg, rawOffset); + ZEND_TRY_ASSIGN_REF_LONG(dstOffsetArg, dstOffset); RETURN_TRUE; } From 81d9a27c47b12ad20e180afb09c6188c8d403f9f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 20 Apr 2025 23:59:12 +0200 Subject: [PATCH 30/31] Fix some leaks in php_scandir Closes GH-18371. --- NEWS | 1 + main/php_scandir.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 55a58a4d8e78f..c24fefcc8c6ed 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed bug GH-18304 (Changing the properties of a DateInterval through dynamic properties triggers a SegFault). (nielsdos) + . Fix some leaks in php_scandir. (nielsdos) - Filter: . Fixed bug GH-18309 (ipv6 filter integer overflow). (nielsdos) diff --git a/main/php_scandir.c b/main/php_scandir.c index 7d1eb36023665..7bf91bdf7f33d 100644 --- a/main/php_scandir.c +++ b/main/php_scandir.c @@ -83,7 +83,7 @@ PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*se newv = (struct dirent **) realloc (vector, vector_size * sizeof (struct dirent *)); if (!newv) { - return -1; + goto fail; } vector = newv; } @@ -113,6 +113,7 @@ PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*se free(vector[nfiles]); } free(vector); + closedir(dirp); return -1; } #endif From 2d2a21057fe357941652a2d1b5f296f527a0bee0 Mon Sep 17 00:00:00 2001 From: Eric Mann Date: Tue, 6 May 2025 06:58:10 -0700 Subject: [PATCH 31/31] Update versions for PHP 8.3.21 --- NEWS | 2 +- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index c24fefcc8c6ed..27bfefbfac4ab 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.21 +08 May 2025, PHP 8.3.21 - Core: . Fixed bug GH-18304 (Changing the properties of a DateInterval through diff --git a/Zend/zend.h b/Zend/zend.h index 139e6a70e15dd..f137a3bb4d765 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.21-dev" +#define ZEND_VERSION "4.3.21" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index d721458a73eb2..d2b4f9422068d 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.21-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.21],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index eb91f434188c6..335e319de4fee 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 #define PHP_RELEASE_VERSION 21 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.21-dev" +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.3.21" #define PHP_VERSION_ID 80321