diff --git a/NEWS b/NEWS index 0f5c5a72d94..40102a8613a 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,8 @@ PHP NEWS - Phar: . Fixed memory leaks when verifying OpenSSL signature. (Girgias) . Fix memory leak in phar tar temporary file error handling code. (nielsdos) + . Fix metadata leak when phar convert logic fails. (nielsdos) + . Fix memory leak on failure in phar_convert_to_other(). (nielsdos) - Standard: . Fixed bug GH-16649 (UAF during array_splice). (alexandre-daubois) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index bfefdeaf61e..5b7f7512bf3 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2237,6 +2237,12 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert PHAR_G(last_phar) = NULL; PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL; + php_stream *tmp_fp = php_stream_fopen_tmpfile(); + if (tmp_fp == NULL) { + zend_throw_exception_ex(phar_ce_PharException, 0, "unable to create temporary file"); + return NULL; + } + phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data)); /* set whole-archive compression and type from parameter */ phar->flags = flags; @@ -2261,11 +2267,7 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert zend_hash_init(&phar->virtual_dirs, sizeof(char *), zend_get_hash_value, NULL, 0); - phar->fp = php_stream_fopen_tmpfile(); - if (phar->fp == NULL) { - zend_throw_exception_ex(phar_ce_PharException, 0, "unable to create temporary file"); - return NULL; - } + phar->fp = tmp_fp; phar->fname = source->fname; phar->fname_len = source->fname_len; phar->is_temporary_alias = source->is_temporary_alias; @@ -2289,6 +2291,7 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert } if (FAILURE == phar_copy_file_contents(&newentry, phar->fp)) { + phar_metadata_tracker_free(&phar->metadata_tracker, phar->is_persistent); zend_hash_destroy(&(phar->manifest)); php_stream_close(phar->fp); efree(phar); @@ -2326,6 +2329,7 @@ no_copy: return ret; } else { if(phar != NULL) { + phar_metadata_tracker_free(&phar->metadata_tracker, phar->is_persistent); zend_hash_destroy(&(phar->manifest)); zend_hash_destroy(&(phar->mounted_dirs)); zend_hash_destroy(&(phar->virtual_dirs)); diff --git a/ext/phar/tests/phar_convert_metadata_leak.phpt b/ext/phar/tests/phar_convert_metadata_leak.phpt new file mode 100644 index 00000000000..61a240c8888 --- /dev/null +++ b/ext/phar/tests/phar_convert_metadata_leak.phpt @@ -0,0 +1,24 @@ +--TEST-- +Phar convert logic leaks metadata +--EXTENSIONS-- +phar +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +setMetadata("foobar"); +$phar['x'] = 'hi'; +try { + $phar->convertToData(Phar::ZIP, Phar::NONE, 'phar.zip'); +} catch (BadMethodCallException $e) { + echo $e->getMessage(),"\n"; +} +?> +--CLEAN-- + +--EXPECTF-- +data phar "%s" has invalid extension phar.zip