Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
32 changes: 32 additions & 0 deletions ext/phar/tests/gh23418.phpt
Original file line number Diff line number Diff line change
@@ -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--
<?php
$phar = __DIR__ . '/gh23418.phar';
$mount = __DIR__ . '/gh23418';

@mkdir($mount . '/s2', 0777, true);

$p = new Phar($phar);
$p->addFromString('x.txt', 'x');
$p->setStub('<?php __HALT_COMPILER(); ?>');
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--
<?php
@unlink(__DIR__ . '/gh23418.phar');
@rmdir(__DIR__ . '/gh23418/s2');
@rmdir(__DIR__ . '/gh23418');
?>
--EXPECT--
PharFileInfo, isDir=true
13 changes: 8 additions & 5 deletions ext/phar/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down
Loading