From db445cbf1b81a1fc239c5d8711bec0f0e8b9e119 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 23 Sep 2025 19:02:14 +0100 Subject: [PATCH 1/4] Fix GH-19932: Zip::setEncryptionName()/setEncryptionIndex() memory leak. On successive usage, the password is copied as much but the older address is never freed. Thus, we are hinting a password reset to address it. --- ext/zip/php_zip.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 3613fb0f7ca7..ac48ee8f3ca0 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -2380,6 +2380,11 @@ PHP_METHOD(ZipArchive, setEncryptionName) RETURN_FALSE; } + if (UNEXPECTED(zip_file_set_encryption(intern, idx, ZIP_EM_NONE, NULL) < 0)) { + zend_throw_error(NULL, "password reset failed"); + RETURN_THROWS(); + } + if (zip_file_set_encryption(intern, idx, (zip_uint16_t)method, password)) { RETURN_FALSE; } @@ -2403,6 +2408,11 @@ PHP_METHOD(ZipArchive, setEncryptionIndex) ZIP_FROM_OBJECT(intern, self); + if (UNEXPECTED(zip_file_set_encryption(intern, index, ZIP_EM_NONE, NULL) < 0)) { + zend_throw_error(NULL, "password reset failed"); + RETURN_THROWS(); + } + if (zip_file_set_encryption(intern, index, (zip_uint16_t)method, password)) { RETURN_FALSE; } From f352d6ddc7896284e85bca4b0651f7bf9cc23a60 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 23 Sep 2025 19:45:04 +0100 Subject: [PATCH 2/4] add test --- ext/zip/tests/gh19932.phpt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 ext/zip/tests/gh19932.phpt diff --git a/ext/zip/tests/gh19932.phpt b/ext/zip/tests/gh19932.phpt new file mode 100644 index 000000000000..ca3f8c6edaaf --- /dev/null +++ b/ext/zip/tests/gh19932.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-19932 (ZipArchive::setEncryptionName()/setEncryptionIndex() memory leak) +--EXTENSIONS-- +zip +--SKIPIF-- + +--FILE-- +open(__DIR__ . "/gh19932.zip", ZipArchive::CREATE); +$zip->addFromString("test.txt", "test"); +$zip->setEncryptionName("test.txt", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionName("test.txt", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionIndex("0", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionIndex("0", ZipArchive::EM_AES_256, "password"); +$zip->close(); +echo "OK"; +?> +--CLEAN-- + +--EXPECT-- +OK + From dce8ceb8241374cc9d4a150f78d68a2b56374735 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 23 Sep 2025 20:06:13 +0100 Subject: [PATCH 3/4] raise warning instead --- ext/zip/php_zip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index ac48ee8f3ca0..552d3a7571de 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -2381,8 +2381,8 @@ PHP_METHOD(ZipArchive, setEncryptionName) } if (UNEXPECTED(zip_file_set_encryption(intern, idx, ZIP_EM_NONE, NULL) < 0)) { - zend_throw_error(NULL, "password reset failed"); - RETURN_THROWS(); + php_error_docref(NULL, E_WARNING, "password reset failed"); + RETURN_FALSE; } if (zip_file_set_encryption(intern, idx, (zip_uint16_t)method, password)) { @@ -2409,8 +2409,8 @@ PHP_METHOD(ZipArchive, setEncryptionIndex) ZIP_FROM_OBJECT(intern, self); if (UNEXPECTED(zip_file_set_encryption(intern, index, ZIP_EM_NONE, NULL) < 0)) { - zend_throw_error(NULL, "password reset failed"); - RETURN_THROWS(); + php_error_docref(NULL, E_WARNING, "password reset failed"); + RETURN_FALSE; } if (zip_file_set_encryption(intern, index, (zip_uint16_t)method, password)) { From afc653cf05a5ffe258a7840a0bd816e3f1fbecae Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 23 Sep 2025 20:46:36 +0100 Subject: [PATCH 4/4] clean this up --- ext/zip/tests/gh19932.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/zip/tests/gh19932.phpt b/ext/zip/tests/gh19932.phpt index ca3f8c6edaaf..760fa1c9e766 100644 --- a/ext/zip/tests/gh19932.phpt +++ b/ext/zip/tests/gh19932.phpt @@ -18,7 +18,7 @@ echo "OK"; ?> --CLEAN-- --EXPECT-- OK