summaryrefslogtreecommitdiffstats
path: root/php-bug81211.patch
blob: c2ab931c06d21ffb9aee39952a3f808c30a6b438 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
From ac8faf81d2f142edae91c81f17530a6bf01114dd 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 5722828c37..55ac24728e 100644
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -1428,6 +1428,7 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{
 	phar_archive_object *phar_obj = p_obj->p;
 	char *str = "[stream]";
 	php_stream_statbuf ssb;
+	char ch;
 
 	iter->funcs->get_current_data(iter, &value TSRMLS_CC);
 
@@ -1551,7 +1552,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 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 f55897fd84f4ba99dd635fbeabef884f170d2bef 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 caaa673e4ca008b7fa3f91538ec553c71d2fc97d 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 03d8a03ec1..c9cdc3a328 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