summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2021-08-26 08:19:46 +0200
committerRemi Collet <remi@remirepo.net>2021-08-26 08:19:46 +0200
commitd54b5fe857400d08b4281923f8d41bf9c8685962 (patch)
tree785a3c385a656d2d926f94373cbe594ab125e3b0
parentb777fbb6b747b85dee578bdc950b815874e0b37d (diff)
Fix #81211 Symlinks are followed when creating PHAR archive
-rw-r--r--php-bug81211.patch164
-rw-r--r--php70.spec7
2 files changed, 170 insertions, 1 deletions
diff --git a/php-bug81211.patch b/php-bug81211.patch
new file mode 100644
index 0000000..2df28c6
--- /dev/null
+++ b/php-bug81211.patch
@@ -0,0 +1,164 @@
+From bc182403e00c9da5a51f52a443047946266ca5d8 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 1/3] 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`.
+
+(cherry picked from commit 2ff853aa113e52637c85e28d1a03df1aa2d747b5)
+---
+ 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 8a0d369287..c8898a4a9d 100644
+--- a/ext/phar/phar_object.c
++++ b/ext/phar/phar_object.c
+@@ -1452,6 +1452,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);
+
+@@ -1581,7 +1582,7 @@ phar_spl_fileinfo:
+ base = temp;
+ base_len = (int)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 2d4b47cd51..936a1e31e8 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.31.1
+
+From 3d93ceed09ce3e575676d349863c23f4d878cb0f Mon Sep 17 00:00:00 2001
+From: Stanislav Malyshev <stas@php.net>
+Date: Mon, 23 Aug 2021 23:43:32 -0700
+Subject: [PATCH 2/3] Fix test
+
+(cherry picked from commit b815645aac76b494dc119fa6b88de32fa9bcccf1)
+---
+ ext/phar/tests/bug81211.phpt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ext/phar/tests/bug81211.phpt b/ext/phar/tests/bug81211.phpt
+index 43d82143f2..96b1401b40 100644
+--- a/ext/phar/tests/bug81211.phpt
++++ b/ext/phar/tests/bug81211.phpt
+@@ -41,5 +41,5 @@ try {
+ @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"
++Iterator RecursiveIteratorIterator returned a path "%s%ebug81211%efoobar%efile" that is not in the base directory "%s%ebug81211%efoo"
++Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211%efoobar%efile" that is not in the base directory "%s%ebug81211%efoo"
+--
+2.31.1
+
+From 3acef06f1251525fe938606a00677c36ad18ff4f Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 25 Aug 2021 15:23:50 +0200
+Subject: [PATCH 3/3] NEWS
+
+(cherry picked from commit 5539cefcda6aca7af220e7be7760a682abb88200)
+---
+ NEWS | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 861dbd7dd5..8167eb8552 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,11 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 7.3.30
++
++- Phar:
++ . Fixed bug #81211: Symlinks are followed when creating PHAR archive (cmb)
++
+ Backported from 7.3.29
+
+ - Core:
+--
+2.31.1
+
diff --git a/php70.spec b/php70.spec
index 003fb41..8b8b9ed 100644
--- a/php70.spec
+++ b/php70.spec
@@ -109,7 +109,7 @@
Summary: PHP scripting language for creating dynamic web sites
Name: php
Version: %{upver}%{?rcver:~%{rcver}}
-Release: 28%{?dist}
+Release: 29%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -220,6 +220,7 @@ Patch248: php-bug80672.patch
Patch249: php-bug80710.patch
Patch250: php-bug81122.patch
Patch251: php-bug76450.patch
+Patch252: php-bug81211.patch
# Fixes for tests (300+)
# Factory is droped from system tzdata
@@ -1130,6 +1131,7 @@ echo CIBLE = %{name}-%{version}-%{release} oci8=%{with_oci8} libzip=%{with_libzi
%patch249 -p1 -b .bug80710
%patch250 -p1 -b .bug81122
%patch251 -p1 -b .bug76450
+%patch252 -p1 -b .bug81211
# Fixes for tests
%if 0%{?fedora} >= 21 || 0%{?rhel} >= 5
@@ -2167,6 +2169,9 @@ fi
%changelog
+* Thu Aug 26 2021 Remi Collet <remi@remirepo.net> - 7.0.33-29
+- Fix #81211 Symlinks are followed when creating PHAR archive
+
* Mon Jun 28 2021 Remi Collet <remi@remirepo.net> - 7.0.33-28
- Fix #81122 SSRF bypass in FILTER_VALIDATE_URL
CVE-2021-21705