[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5
Weilin Du <[email protected]>
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: Weilin Du (LamentXU123)
Date: 2026-07-10T16:50:49+08:00
Commit: https://github.com/php/php-src/commit/b686856390149cce73dd90f57840c17df0d61913
Raw diff: https://github.com/php/php-src/commit/b686856390149cce73dd90f57840c17df0d61913.diff
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
Fix GH-22649: avoid ZipArchive comment reset crash (#22652)
Changed paths:
A ext/zip/tests/gh22649.phpt
M NEWS
M ext/zip/php_zip.c
Diff:
diff --git a/NEWS b/NEWS
index f337403fbebe..d28381c3902b 100644
--- a/NEWS
+++ b/NEWS
@@ -102,6 +102,9 @@ PHP NEWS
opaque hosts. (kocsismate)
- Zip:
+ . Fixed bug GH-22649 (ZipArchive::setCommentName() and setCommentIndex()
+ could crash after overwriting an entry and resetting its inherited
+ unchanged comment). (Weilin Du)
. Fixed bug GH-21705 (ZipArchive::getFromIndex() ignores
ZipArchive::FL_UNCHANGED for deleted entries). (Weilin Du)
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index fd339e4fe745..fbb8594013a4 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -58,17 +58,26 @@ static int le_zip_entry;
}
/* }}} */
-/* {{{ PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) */
-#define PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) \
- if (comment_len == 0) { \
- /* Passing NULL remove the existing comment */ \
- if (zip_file_set_comment(za, index, NULL, 0, 0) < 0) { \
- RETURN_FALSE; \
- } \
- } else if (zip_file_set_comment(za, index, comment, comment_len, 0) < 0) { \
- RETURN_FALSE; \
- } \
- RETURN_TRUE;
+/* {{{ php_zip_set_file_comment */
+static bool php_zip_set_file_comment(struct zip *za, zip_uint64_t index, const char *comment, size_t comment_len)
+{
+ zip_uint32_t current_comment_len;
+ const char *current_comment = zip_file_get_comment(za, index, ¤t_comment_len, ZIP_FL_ENC_RAW);
+
+ /* Avoid a libzip use-after-free when resetting an unchanged inherited comment. */
+ if (current_comment && current_comment_len == comment_len
+ && memcmp(current_comment, comment, comment_len) == 0) {
+ return true;
+ }
+
+ if (comment_len == 0) {
+ /* Passing NULL removes the existing comment. */
+ return zip_file_set_comment(za, index, NULL, 0, 0) == 0;
+ }
+
+ ZEND_ASSERT(comment_len <= 0xffff);
+ return zip_file_set_comment(za, index, comment, (zip_uint16_t) comment_len, 0) == 0;
+}
/* }}} */
# define add_ascii_assoc_string add_assoc_string
@@ -2137,7 +2146,7 @@ PHP_METHOD(ZipArchive, setCommentName)
zval *self = ZEND_THIS;
size_t comment_len, name_len;
char * comment, *name;
- int idx;
+ zip_int64_t idx;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
&name, &name_len, &comment, &comment_len) == FAILURE) {
@@ -2160,7 +2169,7 @@ PHP_METHOD(ZipArchive, setCommentName)
if (idx < 0) {
RETURN_FALSE;
}
- PHP_ZIP_SET_FILE_COMMENT(intern, idx, comment, comment_len);
+ RETURN_BOOL(php_zip_set_file_comment(intern, (zip_uint64_t) idx, comment, comment_len));
}
/* }}} */
@@ -2173,6 +2182,7 @@ PHP_METHOD(ZipArchive, setCommentIndex)
size_t comment_len;
char * comment;
struct zip_stat sb;
+ zip_uint64_t idx;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls",
&index, &comment, &comment_len) == FAILURE) {
@@ -2187,7 +2197,9 @@ PHP_METHOD(ZipArchive, setCommentIndex)
}
PHP_ZIP_STAT_INDEX(intern, index, 0, sb);
- PHP_ZIP_SET_FILE_COMMENT(intern, index, comment, comment_len);
+ idx = (zip_uint64_t) index;
+
+ RETURN_BOOL(php_zip_set_file_comment(intern, idx, comment, comment_len));
}
/* }}} */
diff --git a/ext/zip/tests/gh22649.phpt b/ext/zip/tests/gh22649.phpt
new file mode 100644
index 000000000000..d6d0a0928184
--- /dev/null
+++ b/ext/zip/tests/gh22649.phpt
@@ -0,0 +1,55 @@
+--TEST--
+GH-22649 (setCommentName/Index after addFromString should not segfault)
+--EXTENSIONS--
+zip
+--FILE--
+<?php
+$file = __DIR__ . '/gh22649.zip';
+
+@unlink($file);
+
+$zip = new ZipArchive;
+if (!$zip->open($file, ZipArchive::CREATE)) {
+ exit('failed');
+}
+
+$zip->addFromString('dir/entry2d.txt', 'entry #2');
+var_dump($zip->setCommentName('dir/entry2d.txt', 'dir/entry2d.txt'));
+
+$zip->addFromString('dir/entry3d.txt', 'entry #3');
+var_dump($zip->setCommentIndex($zip->lastId, 'dir/entry3d.txt'));
+
+$zip->close();
+
+if (!$zip->open($file, ZipArchive::CREATE)) {
+ exit('failed');
+}
+
+$zip->addFromString('dir/entry2d.txt', 'updated entry #2');
+var_dump($zip->setCommentName('dir/entry2d.txt', 'dir/entry2d.txt'));
+
+$zip->addFromString('dir/entry3d.txt', 'updated entry #3');
+var_dump($zip->setCommentIndex($zip->lastId, 'dir/entry3d.txt'));
+
+$zip->close();
+
+if (!$zip->open($file)) {
+ exit('failed');
+}
+
+var_dump($zip->getCommentName('dir/entry2d.txt'));
+var_dump($zip->getCommentName('dir/entry3d.txt'));
+
+$zip->close();
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+string(15) "dir/entry2d.txt"
+string(15) "dir/entry3d.txt"
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/gh22649.zip');
+?>