From ae4484363e3be9147649e7e644a9ddc42256cb78 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:21:45 +0100 Subject: [PATCH 1/2] Fix GH-20732: Phar::LoadPhar undefined behavior when loading directory The size of `got` was incorrect: it being unsigned means that the error return codes are converted from -1 to SIZE_MAX. We should use ssize_t instead. --- ext/phar/phar.c | 4 ++-- ext/phar/tests/gh20732.phpt | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 ext/phar/tests/gh20732.phpt diff --git a/ext/phar/phar.c b/ext/phar/phar.c index a63a8dd8eb6d6..4c2cab27dcea4 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1609,7 +1609,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char const zend_long readsize = sizeof(buffer) - sizeof(token); const zend_long tokenlen = sizeof(token) - 1; zend_long halt_offset; - size_t got; + ssize_t got; uint32_t compression = PHAR_FILE_COMPRESSED_NONE; if (error) { @@ -1627,7 +1627,7 @@ static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char /* Maybe it's better to compile the file instead of just searching, */ /* but we only want the offset. So we want a .re scanner to find it. */ while(!php_stream_eof(fp)) { - if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) { + if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < tokenlen) { MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") } diff --git a/ext/phar/tests/gh20732.phpt b/ext/phar/tests/gh20732.phpt new file mode 100644 index 0000000000000..2aaa89b5b2e8d --- /dev/null +++ b/ext/phar/tests/gh20732.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-20732 (Phar::LoadPhar undefined behavior when loading directory) +--EXTENSIONS-- +phar +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Notice: Phar::loadPhar(): Read of 8192 bytes failed with errno=21 Is a directory in %s on line %d +internal corruption of phar "/run/media/niels/MoreData/php-8.3" (truncated entry) From 45022012e3bb97f1002a67ea398f319178545d9a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 19 Dec 2025 19:01:18 +0100 Subject: [PATCH 2/2] Test fixes --- ext/phar/tests/gh20732.phpt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/phar/tests/gh20732.phpt b/ext/phar/tests/gh20732.phpt index 2aaa89b5b2e8d..b938d16d42caf 100644 --- a/ext/phar/tests/gh20732.phpt +++ b/ext/phar/tests/gh20732.phpt @@ -5,11 +5,10 @@ phar --FILE-- getMessage(), "\n"; } ?> --EXPECTF-- -Notice: Phar::loadPhar(): Read of 8192 bytes failed with errno=21 Is a directory in %s on line %d -internal corruption of phar "/run/media/niels/MoreData/php-8.3" (truncated entry) +%r(internal corruption of phar "%s" \(truncated entry\)|unable to open phar for reading ".")%r