Created
July 1, 2021 12:50
-
-
Save cmb69/46e4238e01a565603b4e25d1964547e9 to your computer and use it in GitHub Desktop.
Fix for PHP bug #81211 (does not cater relative paths)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From aa1e7dfecffc3e09cd36cb4d7fa7a7e04e2bb30a Mon Sep 17 00:00:00 2001 | |
From: "Christoph M. Becker" <cmbecker69@gmx.de> | |
Date: Thu, 1 Jul 2021 14:47:27 +0200 | |
Subject: [PATCH] Fix #81211: Symlinks are followed when creating PHAR archive | |
It is insufficient to check whether the `base` is contained in `fname`; | |
we also need to ensure that `fname` is properly separated. | |
--- | |
ext/phar/phar_object.c | 3 ++- | |
ext/phar/tests/bug81211.phpt | 45 ++++++++++++++++++++++++++++++++++++ | |
2 files changed, 47 insertions(+), 1 deletion(-) | |
create mode 100644 ext/phar/tests/bug81211.phpt | |
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c | |
index 34da571a89..41f78ff1fd 100644 | |
--- a/ext/phar/phar_object.c | |
+++ b/ext/phar/phar_object.c | |
@@ -1418,6 +1418,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ | |
zend_class_entry *ce = p_obj->c; | |
phar_archive_object *phar_obj = p_obj->p; | |
php_stream_statbuf ssb; | |
+ char ch; | |
value = iter->funcs->get_current_data(iter); | |
@@ -1541,7 +1542,7 @@ phar_spl_fileinfo: | |
base = temp; | |
base_len = strlen(base); | |
- if (strstr(fname, base)) { | |
+ if (strstr(fname, base) && ((ch = fname[base_len - IS_SLASH(base[base_len - 1])]) == '\0' || IS_SLASH(ch))) { | |
str_key_len = fname_len - base_len; | |
if (str_key_len <= 0) { | |
diff --git a/ext/phar/tests/bug81211.phpt b/ext/phar/tests/bug81211.phpt | |
new file mode 100644 | |
index 0000000000..43d82143f2 | |
--- /dev/null | |
+++ b/ext/phar/tests/bug81211.phpt | |
@@ -0,0 +1,45 @@ | |
+--TEST-- | |
+Bug #81211 (Symlinks are followed when creating PHAR archive) | |
+--SKIPIF-- | |
+<?php | |
+if (!extension_loaded('phar')) die('skip phar extension is not available'); | |
+if (PHP_OS_FAMILY === 'Windows') { | |
+ if (false === include __DIR__ . '/../../standard/tests/file/windows_links/common.inc') { | |
+ die('skip windows_links/common.inc is not available'); | |
+ } | |
+ skipIfSeCreateSymbolicLinkPrivilegeIsDisabled(__FILE__); | |
+} | |
+?> | |
+--FILE-- | |
+<?php | |
+mkdir(__DIR__ . '/bug81211'); | |
+mkdir(__DIR__ . '/bug81211/foobar'); | |
+mkdir(__DIR__ . '/bug81211/foo'); | |
+ | |
+file_put_contents(__DIR__ . '/bug81211/foobar/file', 'this file should NOT be included in the archive!'); | |
+symlink(__DIR__ . '/bug81211/foobar/file', __DIR__ . '/bug81211/foo/symlink'); | |
+ | |
+$archive = new PharData(__DIR__ . '/bug81211/archive.tar'); | |
+try { | |
+ $archive->buildFromDirectory(__DIR__ . '/bug81211/foo'); | |
+} catch (UnexpectedValueException $ex) { | |
+ echo $ex->getMessage(), PHP_EOL; | |
+} | |
+try { | |
+ $archive->buildFromIterator(new RecursiveDirectoryIterator(__DIR__ . '/bug81211/foo', FilesystemIterator::SKIP_DOTS), __DIR__ . '/bug81211/foo'); | |
+} catch (UnexpectedValueException $ex) { | |
+ echo $ex->getMessage(), PHP_EOL; | |
+} | |
+?> | |
+--CLEAN-- | |
+<?php | |
+@unlink(__DIR__ . '/bug81211/archive.tar'); | |
+@unlink(__DIR__ . '/bug81211/foo/symlink'); | |
+@unlink(__DIR__ . '/bug81211/foobar/file'); | |
+@rmdir(__DIR__ . '/bug81211/foo'); | |
+@rmdir(__DIR__ . '/bug81211/foobar'); | |
+@rmdir(__DIR__ . '/bug81211'); | |
+?> | |
+--EXPECTF-- | |
+Iterator RecursiveIteratorIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" | |
+Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" | |
-- | |
2.32.0.windows.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment