Skip to content

Commit f03676c

Browse files
committed
Fix #65069: GlobIterator incorrect handling of open_basedir check
1 parent a05a6c5 commit f03676c

File tree

3 files changed

+95
-14
lines changed

3 files changed

+95
-14
lines changed

ext/spl/tests/bug65069.phpt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
Bug #65069: GlobIterator fails to access files inside an open_basedir restricted dir
3+
--FILE--
4+
<?php
5+
$file_path = dirname(__FILE__);
6+
// temp dirname used here
7+
$dirname = "$file_path/bug65069";
8+
// temp dir created
9+
mkdir($dirname);
10+
11+
ini_set('open_basedir', $dirname);
12+
13+
// temp files created
14+
$fp = fopen("$dirname/wonder12345", "w");
15+
fclose($fp);
16+
$fp = fopen("$dirname/wonder.txt", "w");
17+
fclose($fp);
18+
$fp = fopen("$dirname/file.text", "w");
19+
fclose($fp);
20+
21+
$spl_glob_it = new \GlobIterator("$dirname/*.txt");
22+
foreach ($spl_glob_it as $file_info) {
23+
echo $file_info->getFilename() . "\n";
24+
}
25+
26+
$spl_glob_it = new \GlobIterator(dirname(dirname($dirname)) . "/*/*/*");
27+
foreach ($spl_glob_it as $file_info) {
28+
echo $file_info->getFilename() . "\n";
29+
}
30+
31+
$spl_glob_empty = new \GlobIterator("$dirname/*.php");
32+
var_dump($spl_glob_empty->count());
33+
34+
// top directory
35+
var_dump(iterator_to_array(new \GlobIterator(dirname(dirname($dirname)))));
36+
37+
// not existing file
38+
var_dump(iterator_to_array(new \GlobIterator("$file_path/bug65069-this-will-never-exists")));
39+
40+
41+
?>
42+
--CLEAN--
43+
<?php
44+
$file_path = dirname(__FILE__);
45+
$dirname = "$file_path/bug65069";
46+
unlink("$dirname/wonder12345");
47+
unlink("$dirname/wonder.txt");
48+
unlink("$dirname/file.text");
49+
rmdir($dirname);
50+
?>
51+
--EXPECT--
52+
wonder.txt
53+
file.text
54+
wonder.txt
55+
wonder12345
56+
int(0)
57+
array(0) {
58+
}
59+
array(0) {
60+
}

ext/standard/tests/streams/glob-wrapper.phpt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ open_basedir=/does_not_exist
55
--SKIPIF--
66
<?php
77
if (!in_array("glob", stream_get_wrappers())) echo "skip";
8+
?>
89
--FILE--
910
<?php
1011

@@ -29,8 +30,4 @@ Warning: opendir(): open_basedir restriction in effect. File(%s) is not within t
2930
Warning: opendir(%s): Failed to open directory: Operation not permitted in %s%eglob-wrapper.php on line 5
3031
Failed to open %s
3132
** Opening glob://%s
32-
33-
Warning: opendir(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (/does_not_exist) in %s%eglob-wrapper.php on line 5
34-
35-
Warning: opendir(glob://%s): Failed to open directory: operation failed in %s%eglob-wrapper.php on line 5
36-
Failed to open glob://%s
33+
No files in glob://%s

main/streams/glob_wrapper.c

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ typedef struct {
4141
size_t path_len;
4242
char *pattern;
4343
size_t pattern_len;
44+
size_t *open_basedir_indexmap;
45+
size_t open_basedir_indexmap_size;
46+
bool open_basedir_indexmap_used;
4447
} glob_s_t;
4548

4649
PHPAPI char* _php_glob_stream_get_path(php_stream *stream, size_t *plen STREAMS_DC) /* {{{ */
@@ -79,6 +82,9 @@ PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, size_t *plen STREA
7982
}
8083
/* }}} */
8184

85+
#define _php_glob_stream_get_result_count(pglob) \
86+
pglob->open_basedir_indexmap_used ? (int) pglob->open_basedir_indexmap_size : pglob->glob.gl_pathc
87+
8288
PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC) /* {{{ */
8389
{
8490
glob_s_t *pglob = (glob_s_t *)stream->abstract;
@@ -87,7 +93,7 @@ PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC
8793
if (pflags) {
8894
*pflags = pglob->flags;
8995
}
90-
return pglob->glob.gl_pathc;
96+
return _php_glob_stream_get_result_count(pglob);
9197
} else {
9298
if (pflags) {
9399
*pflags = 0;
@@ -130,15 +136,21 @@ static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count)
130136
glob_s_t *pglob = (glob_s_t *)stream->abstract;
131137
php_stream_dirent *ent = (php_stream_dirent*)buf;
132138
const char *path;
139+
int glob_result_count;
140+
size_t index;
133141

134142
/* avoid problems if someone mis-uses the stream */
135143
if (count == sizeof(php_stream_dirent) && pglob) {
136-
if (pglob->index < (size_t)pglob->glob.gl_pathc) {
137-
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path);
144+
glob_result_count = _php_glob_stream_get_result_count(pglob);
145+
if (pglob->index < (size_t) glob_result_count) {
146+
index = pglob->open_basedir_indexmap_used && pglob->open_basedir_indexmap ?
147+
pglob->open_basedir_indexmap[pglob->index] : pglob->index;
148+
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & GLOB_APPEND, &path);
149+
++pglob->index;
138150
PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
139151
return sizeof(php_stream_dirent);
140152
}
141-
pglob->index = pglob->glob.gl_pathc;
153+
pglob->index = glob_result_count;
142154
if (pglob->path) {
143155
efree(pglob->path);
144156
pglob->path = NULL;
@@ -162,6 +174,9 @@ static int php_glob_stream_close(php_stream *stream, int close_handle) /* {{{ *
162174
if (pglob->pattern) {
163175
efree(pglob->pattern);
164176
}
177+
if (pglob->open_basedir_indexmap) {
178+
efree(pglob->open_basedir_indexmap);
179+
}
165180
}
166181
efree(stream->abstract);
167182
return 0;
@@ -198,7 +213,7 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
198213
int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
199214
{
200215
glob_s_t *pglob;
201-
int ret;
216+
int ret, i;
202217
const char *tmp, *pos;
203218

204219
if (!strncmp(path, "glob://", sizeof("glob://")-1)) {
@@ -208,10 +223,6 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
208223
}
209224
}
210225

211-
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
212-
return NULL;
213-
}
214-
215226
pglob = ecalloc(sizeof(*pglob), 1);
216227

217228
if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
@@ -224,6 +235,19 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
224235
}
225236
}
226237

238+
/* if open_basedir in use, check and filter restricted paths */
239+
if ((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) {
240+
pglob->open_basedir_indexmap_used = true;
241+
for (i = 0; i < pglob->glob.gl_pathc; i++) {
242+
if (!php_check_open_basedir_ex(pglob->glob.gl_pathv[i], 0)) {
243+
if (!pglob->open_basedir_indexmap) {
244+
pglob->open_basedir_indexmap = (size_t *) emalloc(sizeof(size_t) * pglob->glob.gl_pathc);
245+
}
246+
pglob->open_basedir_indexmap[pglob->open_basedir_indexmap_size++] = i;
247+
}
248+
}
249+
}
250+
227251
pos = path;
228252
if ((tmp = strrchr(pos, '/')) != NULL) {
229253
pos = tmp+1;

0 commit comments

Comments
 (0)