Created
August 23, 2021 11:43
-
-
Save cmb69/404cbe40a77e2e18d3331db5e9cc5092 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 ad7b4c5a548b2f138900ce995c9891e225ce2580 Mon Sep 17 00:00:00 2001 | |
From: "Christoph M. Becker" <cmbecker69@gmx.de> | |
Date: Mon, 23 Aug 2021 13:42:17 +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. And of | |
course, `fname` has to start with `base`. | |
--- | |
ext/phar/phar_object.c | 3 +- | |
ext/phar/tests/bug81211.phpt | 45 +++++++++++++++++++ | |
.../tests/file/windows_links/common.inc | 9 +++- | |
3 files changed, 55 insertions(+), 2 deletions(-) | |
create mode 100644 ext/phar/tests/bug81211.phpt | |
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c | |
index 82c7c376ed..cba0ded88e 100644 | |
--- a/ext/phar/phar_object.c | |
+++ b/ext/phar/phar_object.c | |
@@ -1405,6 +1405,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); | |
@@ -1528,7 +1529,7 @@ phar_spl_fileinfo: | |
base = temp; | |
base_len = strlen(base); | |
- if (strstr(fname, base)) { | |
+ if (fname_len >= base_len && strncmp(fname, base, base_len) == 0 && ((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" | |
diff --git a/ext/standard/tests/file/windows_links/common.inc b/ext/standard/tests/file/windows_links/common.inc | |
index 505368b8b0..caa3758d44 100644 | |
--- a/ext/standard/tests/file/windows_links/common.inc | |
+++ b/ext/standard/tests/file/windows_links/common.inc | |
@@ -20,4 +20,11 @@ function get_mountvol() { | |
return "$sysroot\\System32\\mountvol.exe"; | |
} | |
-?> | |
+function skipIfSeCreateSymbolicLinkPrivilegeIsDisabled(string $filename) { | |
+ $ln = "$filename.lnk"; | |
+ $ret = exec("mklink $ln " . __FILE__ .' 2>&1', $out); | |
+ @unlink($ln); | |
+ if (strpos($ret, 'privilege') !== false) { | |
+ die('skip SeCreateSymbolicLinkPrivilege not enabled'); | |
+ } | |
+} | |
-- | |
2.33.0.windows.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment