Skip to content

Commit 3064540

Browse files
committed
ext/phar: improve .phar madic directory preservation logic in phar::addEmptyDir()
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 Closes GH-22146.
1 parent cb8f7bd commit 3064540

3 files changed

Lines changed: 24 additions & 3 deletions

File tree

NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ PHP NEWS
1717
IntlCalendar::equals(), ::before(), ::after(), and ::isEquivalentTo().
1818
(Weilin Du)
1919

20+
- Phar:
21+
. Fixed a bypass of the magic ".phar" directory protection in
22+
Phar::addEmptyDir() for paths starting with "/.phar", while allowing
23+
non-magic directory names that merely share the ".phar" prefix. (Weilin Du)
24+
2025
- Zlib:
2126
. Fixed memory leak if deflate initialization fails and there is a dict.
2227
(ndossche)

ext/phar/phar_object.c

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

38643864
PHAR_ARCHIVE_OBJECT();
38653865

3866-
if (zend_string_starts_with_literal(dir_name, ".phar")) {
3867-
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory");
3868-
RETURN_THROWS();
3866+
if (
3867+
zend_string_starts_with_literal(dir_name, ".phar")
3868+
|| zend_string_starts_with_literal(dir_name, "/.phar")
3869+
) {
3870+
size_t prefix_len = (ZSTR_VAL(dir_name)[0] == '/') + sizeof(".phar")-1;
3871+
char next_char = ZSTR_VAL(dir_name)[prefix_len];
3872+
if (next_char == '/' || next_char == '\\' || next_char == '\0') {
3873+
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory");
3874+
RETURN_THROWS();
3875+
}
38693876
}
38703877

38713878
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)