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 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
|