diff --git a/NEWS b/NEWS index 5607f31081b8..7dcfcbd2d3cb 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,10 @@ PHP NEWS . Fixed a leak when a persistent connection failed a liveness check with no other live PDO handle. (iliaal) +- Phar: + . Fixed bug GH-23418 (Use-after-free when looking up mounted directories). + (Weilin Du) + - Standard: . Fixed a memory leak in array_merge_recursive() when the recursive merge of an object converted to an array fails. (David Carlier) diff --git a/ext/phar/tests/gh23418.phpt b/ext/phar/tests/gh23418.phpt new file mode 100644 index 000000000000..d7ebebcb9ecb --- /dev/null +++ b/ext/phar/tests/gh23418.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-23418: Access a subdirectory of a mounted directory with a trailing slash +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +addFromString('x.txt', 'x'); +$p->setStub(''); +unset($p); + +$p = new Phar($phar); +Phar::mount('phar://' . $phar . '/m', $mount); +$info = $p['m/s2/']; + +echo get_class($info), ', isDir=', $info->isDir() ? 'true' : 'false', PHP_EOL; +?> +--CLEAN-- + +--EXPECT-- +PharFileInfo, isDir=true diff --git a/ext/phar/util.c b/ext/phar/util.c index d3bdf3d52a78..f4de9922f899 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -1382,7 +1382,7 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, si if (ZSTR_LEN(str_key) >= path_len || strncmp(ZSTR_VAL(str_key), path, ZSTR_LEN(str_key))) { continue; } else { - char *test; + char *test, *mount_path; size_t test_len; php_stream_statbuf ssb; @@ -1425,22 +1425,25 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, si } /* mount the file just in time */ - if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len)) { - efree(test); + mount_path = estrndup(path, path_len); + if (SUCCESS != phar_mount_entry(phar, test, test_len, mount_path, path_len)) { if (error) { spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test); } + efree(mount_path); + efree(test); return NULL; } - - efree(test); + efree(mount_path); if (NULL == (entry = zend_hash_str_find_ptr(&phar->manifest, path, path_len))) { if (error) { spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test); } + efree(test); return NULL; } + efree(test); return entry; } } ZEND_HASH_FOREACH_END();