Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix GH-17139: Fix zip_entry_name() crash on invalid entry. #17142

Closed
wants to merge 1 commit into from

Conversation

devnexen
Copy link
Member

Increasing the GC refcount when reading the zip entry before zip_entry_name() fetches the info, leading to a dangling pointer otherwise.

Increasing the GC refcount when reading the zip entry before
zip_entry_name() fetches the info, leading to a dangling pointer
otherwise.
@devnexen devnexen marked this pull request as ready for review December 13, 2024 09:57
@devnexen devnexen requested a review from Girgias December 13, 2024 09:57
@devnexen devnexen linked an issue Dec 13, 2024 that may be closed by this pull request
@@ -1257,6 +1257,7 @@ PHP_FUNCTION(zip_read)

zr_rsrc->zf = zip_fopen_index(rsrc_int->za, rsrc_int->index_current, 0);
if (zr_rsrc->zf) {
Z_ADDREF_P(zip_dp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might lead to a memory leak. Wouldn't the refcount increase for every zip_read()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASAN nor DEBUG build reported anything on this new test nor in zip_read.phpt

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh – resources! For a clean solution, the le_zip_entry resources would need to store a reference to their le_zip_dir resource; otherwise, as happens here, if the le_zip_dir resource is closed, there are dangling pointers. Increasing the refcount here (and possibly elsewhere) only shades the problem. Given that the procedural API is deprecated as of PHP 8.0.0, I'd opt for wontfix. @remicollet, what do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that s obsolete for that long, might be best remove it for 8.5/9.0 or so many people still using this api ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the plan is to remove for PHP 9 (removing in a minor is quite a BC break). And I guess most are using the OO-API already.

@nielsdos
Copy link
Member

nielsdos commented Dec 14, 2024

Yeah this patch will leak memory until the request end. The reason you don't see the leak in ASAN/Valgrind is because that memory is cleaned up anyway when the regular list is destroyed. So the practical effect is that this will delay destruction (and writes ig) of the zip and that for long running processes we will leak memory for a long time.

Why don't we just do this instead? Seems simple enough.

diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index 0c1dfaf5dd1..ca48a0c993f 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -1255,6 +1255,7 @@ PHP_FUNCTION(zip_read)
 			RETURN_FALSE;
 		}
 
+		zr_rsrc->zip_rsrc_handle = Z_RES_P(zip_dp)->handle;
 		zr_rsrc->zf = zip_fopen_index(rsrc_int->za, rsrc_int->index_current, 0);
 		if (zr_rsrc->zf) {
 			rsrc_int->index_current++;
@@ -1371,7 +1372,7 @@ static void php_zip_entry_get_info(INTERNAL_FUNCTION_PARAMETERS, int opt) /* {{{
 		RETURN_THROWS();
 	}
 
-	if (!zr_rsrc->zf) {
+	if (!zr_rsrc->zf || !zend_hash_index_exists(&EG(regular_list), zr_rsrc->zip_rsrc_handle)) {
 		RETURN_FALSE;
 	}
 
diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h
index 41392d1967d..13ea7fdc001 100644
--- a/ext/zip/php_zip.h
+++ b/ext/zip/php_zip.h
@@ -60,6 +60,7 @@ typedef zip_rsrc * zip_rsrc_ptr;
 typedef struct _ze_zip_read_rsrc {
 	struct zip_file *zf;
 	struct zip_stat sb;
+	zend_long zip_rsrc_handle;
 } zip_read_rsrc;
 
 /* Extends zend object */

@cmb69
Copy link
Member

cmb69 commented Dec 14, 2024

Oh, looks like we have a private header for once. :)

nielsdos added a commit to nielsdos/php-src that referenced this pull request Jan 10, 2025
Don't increment the refcount, but latter remember the ID to check
afterwards whether the resource still exists.
Replaces phpGH-17142.
nielsdos added a commit to nielsdos/php-src that referenced this pull request Jan 10, 2025
Don't increment the refcount, but latter remember the ID to check
afterwards whether the resource still exists.
Replaces phpGH-17142.
@nielsdos
Copy link
Member

I filed my fix as PR: #17435

@devnexen devnexen closed this Jan 10, 2025
nielsdos added a commit to nielsdos/php-src that referenced this pull request Jan 10, 2025
Don't increment the refcount, but latter remember the ID to check
afterwards whether the resource still exists.

Replaces phpGH-17142.
nielsdos added a commit that referenced this pull request Jan 12, 2025
Don't increment the refcount, but latter remember the ID to check
afterwards whether the resource still exists.

Replaces GH-17142.
Closes GH-17439.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UAF ext/zip/php_zip.c
3 participants