Skip to content

Commit f99989f

Browse files
authored
ext/phar: improve .phar madic directory preservation logic in phar::addEmptyDir() (#22011)
Now, the .phar directory is a magic dir for phar files, and in phar::addEmptyDir(), users couldn't create a dir naming .phar The implementation is: ```c if (zend_string_starts_with_literal(dir_name, ".phar")) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory"); RETURN_THROWS(); ``` This has two bugs. Firstly, people can use /.phar to create the .phar dir. The leading / will be ignored. (no need to concern about ../ though, it will be ignored.) ```php <?php $phar = new Phar(__DIR__ . '/test.phar', 0, 'test.phar'); $phar->addEmptyDir('/.phar'); var_dump(is_dir('phar://' . __DIR__ . '/test.phar/.phar')); ``` Will return true with the .phar dir created, while if the dir is .phar it will raise an error. Secondly, it only matches the prefix. That means, /.pharxxx will not be allowed to create, which is not a magic dir. ```php <?php $phar = new Phar(__DIR__ . '/test.phar', 0, 'test.phar'); $phar->addEmptyDir('.pharx'); ``` This will raise an error. ``` PHP Fatal error: Uncaught BadMethodCallException: Cannot create a directory in magic ".phar" directory in C:\Users\admin\Desktop\bench.php:3 ``` This PR fix both by 1. adding a trailing check of the path to make .pharx valid 2. adding a check to /.phar
1 parent a791534 commit f99989f

4 files changed

Lines changed: 28 additions & 3 deletions

File tree

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ PHP NEWS
129129
. Support reference values in Phar::mungServer(). (ndossche)
130130
. Invalid values now throw in Phar::mungServer() instead of being silently
131131
ignored. (ndossche)
132+
. Fixed a bypass of the magic ".phar" directory protection in
133+
Phar::addEmptyDir() for paths starting with "/.phar". (Weilin Du)
134+
. Phar::addEmptyDir() now allows non-magic directory names that merely
135+
share the ".phar" prefix. (Weilin Du)
132136
. Support overridden methods in SplFileInfo for getMTime() and getPathname()
133137
when building a phar. (ndossche)
134138
. Mark Phar::buildFromIterator() base directory argument as a path.

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ PHP 8.6 UPGRADE NOTES
5555
- Phar:
5656
. Phar::mungServer() now raises a ValueError when an invalid
5757
argument value is passed instead of being silently ignored.
58+
. Phar::addEmptyDir() now rejects `/.phar` paths in addition to `.phar`
59+
paths, and raises the same BadMethodCallException for attempts to create
60+
the reserved magic ".phar" directory through that form.
61+
. Phar::addEmptyDir() now treats non-magic names that merely share the
62+
`.phar` prefix as ordinary directories.
5863

5964
- PGSQL:
6065
. pg_fetch_object() now reports the ValueError for a non-empty

ext/phar/phar_object.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3789,9 +3789,16 @@ PHP_METHOD(Phar, addEmptyDir)
37893789

37903790
PHAR_ARCHIVE_OBJECT();
37913791

3792-
if (zend_string_starts_with_literal(dir_name, ".phar")) {
3793-
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory");
3794-
RETURN_THROWS();
3792+
if (
3793+
zend_string_starts_with_literal(dir_name, ".phar")
3794+
|| zend_string_starts_with_literal(dir_name, "/.phar")
3795+
) {
3796+
size_t prefix_len = (ZSTR_VAL(dir_name)[0] == '/') + sizeof(".phar") - 1;
3797+
char next_char = ZSTR_VAL(dir_name)[prefix_len];
3798+
if (next_char == '/' || next_char == '\\' || next_char == '\0') {
3799+
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory");
3800+
RETURN_THROWS();
3801+
}
37953802
}
37963803

37973804
phar_mkdir(&phar_obj->archive, dir_name);

ext/phar/tests/mkdir.phpt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ $a->addEmptyDir('.phar');
2424
} catch (Exception $e) {
2525
echo $e->getMessage(),"\n";
2626
}
27+
try {
28+
$a->addEmptyDir('/.phar');
29+
} catch (Exception $e) {
30+
echo $e->getMessage(),"\n";
31+
}
32+
$a->addEmptyDir('/.pharx');
33+
var_dump(is_dir($pname . '/.pharx'));
2734
?>
2835
--CLEAN--
2936
<?php
@@ -43,3 +50,5 @@ Warning: rmdir(): phar error: cannot remove directory "" in phar "foo.phar", dir
4350

4451
Warning: rmdir(): phar error: cannot remove directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d
4552
Cannot create a directory in magic ".phar" directory
53+
Cannot create a directory in magic ".phar" directory
54+
bool(true)

0 commit comments

Comments
 (0)