From 97b506fd8c7a6e338fbfdef536c44ffef3e777fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CLamentXU123=E2=80=9D?= <108666168+LamentXU123@users.noreply.github.com> Date: Mon, 11 May 2026 21:32:58 +0800 Subject: [PATCH] ext/phar: improve .phar madic directory preservation logic in phar::addEmptyDir() --- NEWS | 4 ++++ UPGRADING | 5 +++++ ext/phar/phar_object.c | 13 ++++++++++--- ext/phar/tests/mkdir.phpt | 9 +++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 8974665955f8..5abbbf676e68 100644 --- a/NEWS +++ b/NEWS @@ -126,6 +126,10 @@ PHP NEWS . Support reference values in Phar::mungServer(). (ndossche) . Invalid values now throw in Phar::mungServer() instead of being silently ignored. (ndossche) + . Fixed a bypass of the magic ".phar" directory protection in + Phar::addEmptyDir() for paths starting with "/.phar". (Weilin Du) + . Phar::addEmptyDir() now allows non-magic directory names that merely + share the ".phar" prefix. (Weilin Du) . Support overridden methods in SplFileInfo for getMTime() and getPathname() when building a phar. (ndossche) . Mark Phar::buildFromIterator() base directory argument as a path. diff --git a/UPGRADING b/UPGRADING index 5837f7ac62fc..a827bd8f85cb 100644 --- a/UPGRADING +++ b/UPGRADING @@ -52,6 +52,11 @@ PHP 8.6 UPGRADE NOTES - Phar: . Phar::mungServer() now raises a ValueError when an invalid argument value is passed instead of being silently ignored. + . Phar::addEmptyDir() now rejects `/.phar` paths in addition to `.phar` + paths, and raises the same BadMethodCallException for attempts to create + the reserved magic ".phar" directory through that form. + . Phar::addEmptyDir() now treats non-magic names that merely share the + `.phar` prefix as ordinary directories. - PGSQL: . pg_fetch_object() now reports the ValueError for a non-empty diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 81c4fd14f7b3..46db925cfd50 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -3789,9 +3789,16 @@ PHP_METHOD(Phar, addEmptyDir) PHAR_ARCHIVE_OBJECT(); - 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(); + if ( + zend_string_starts_with_literal(dir_name, ".phar") + || zend_string_starts_with_literal(dir_name, "/.phar") + ) { + size_t prefix_len = (ZSTR_VAL(dir_name)[0] == '/') + sizeof(".phar") - 1; + char next_char = ZSTR_VAL(dir_name)[prefix_len]; + if (next_char == '/' || next_char == '\\' || next_char == '\0') { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory"); + RETURN_THROWS(); + } } phar_mkdir(&phar_obj->archive, dir_name); diff --git a/ext/phar/tests/mkdir.phpt b/ext/phar/tests/mkdir.phpt index 1ffdc7fe252d..2c1586b0de5c 100644 --- a/ext/phar/tests/mkdir.phpt +++ b/ext/phar/tests/mkdir.phpt @@ -24,6 +24,13 @@ $a->addEmptyDir('.phar'); } catch (Exception $e) { echo $e->getMessage(),"\n"; } +try { +$a->addEmptyDir('/.phar'); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +$a->addEmptyDir('/.pharx'); +var_dump(is_dir($pname . '/.pharx')); ?> --CLEAN--