mirror of
https://github.com/php/php-src.git
synced 2024-11-24 02:15:04 +08:00
Fix #65069: GlobIterator incorrect handling of open_basedir check
This PR changes the glob stream wrapper so it impacts "glob://" streamsas well. The idea is to do a check for each found path instead of the pattern which was not working correctly.
This commit is contained in:
parent
520bb2ec6c
commit
1a9e6895f1
2
NEWS
2
NEWS
@ -42,6 +42,8 @@ PHP NEWS
|
||||
- SPL:
|
||||
. Fixed bug #69181 (READ_CSV|DROP_NEW_LINE drops newlines within fields).
|
||||
(cmb)
|
||||
. Fixed bug #65069 (GlobIterator incorrect handling of open_basedir check).
|
||||
(Jakub Zelenka)
|
||||
|
||||
21 Jul 2022, PHP 8.2.0beta1
|
||||
|
||||
|
@ -61,6 +61,9 @@ PHP 8.2 UPGRADE NOTES
|
||||
previously it was bool
|
||||
. SplFileObject::getChildren() now has a tentative return type of null,
|
||||
previously it was ?RecursiveIterator
|
||||
. GlogIterator returns empty array if all paths are restricted by
|
||||
open_basedir. Previously the error was returned but that behavior was not
|
||||
consistent and did not work correctly.
|
||||
|
||||
========================================
|
||||
2. New Features
|
||||
|
57
ext/spl/tests/bug65069.phpt
Normal file
57
ext/spl/tests/bug65069.phpt
Normal file
@ -0,0 +1,57 @@
|
||||
--TEST--
|
||||
Bug #65069: GlobIterator fails to access files inside an open_basedir restricted dir
|
||||
--FILE--
|
||||
<?php
|
||||
$file_path = __DIR__;
|
||||
// temp dirname used here
|
||||
$dirname = "$file_path/bug65069";
|
||||
// temp dir created
|
||||
mkdir($dirname);
|
||||
|
||||
ini_set('open_basedir', $dirname);
|
||||
|
||||
// temp files created
|
||||
touch("$dirname/wonder12345");
|
||||
touch("$dirname/wonder.txt");
|
||||
touch("$dirname/file.text");
|
||||
|
||||
$spl_glob_it = new \GlobIterator("$dirname/*.txt");
|
||||
foreach ($spl_glob_it as $file_info) {
|
||||
echo $file_info->getFilename() . "\n";
|
||||
}
|
||||
|
||||
$spl_glob_it = new \GlobIterator(dirname(dirname($dirname)) . "/*/*/*");
|
||||
foreach ($spl_glob_it as $file_info) {
|
||||
echo $file_info->getFilename() . "\n";
|
||||
}
|
||||
|
||||
$spl_glob_empty = new \GlobIterator("$dirname/*.php");
|
||||
var_dump($spl_glob_empty->count());
|
||||
|
||||
// top directory
|
||||
var_dump(iterator_to_array(new \GlobIterator(dirname(dirname($dirname)))));
|
||||
|
||||
// not existing file
|
||||
var_dump(iterator_to_array(new \GlobIterator("$file_path/bug65069-this-will-never-exists")));
|
||||
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$file_path = dirname(__FILE__);
|
||||
$dirname = "$file_path/bug65069";
|
||||
unlink("$dirname/wonder12345");
|
||||
unlink("$dirname/wonder.txt");
|
||||
unlink("$dirname/file.text");
|
||||
rmdir($dirname);
|
||||
?>
|
||||
--EXPECT--
|
||||
wonder.txt
|
||||
file.text
|
||||
wonder.txt
|
||||
wonder12345
|
||||
int(0)
|
||||
array(0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
@ -5,6 +5,7 @@ open_basedir=/does_not_exist
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!in_array("glob", stream_get_wrappers())) echo "skip";
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@ -29,8 +30,4 @@ Warning: opendir(): open_basedir restriction in effect. File(%s) is not within t
|
||||
Warning: opendir(%s): Failed to open directory: Operation not permitted in %s%eglob-wrapper.php on line 5
|
||||
Failed to open %s
|
||||
** Opening glob://%s
|
||||
|
||||
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
|
||||
|
||||
Warning: opendir(glob://%s): Failed to open directory: operation failed in %s%eglob-wrapper.php on line 5
|
||||
Failed to open glob://%s
|
||||
No files in glob://%s
|
||||
|
@ -41,6 +41,9 @@ typedef struct {
|
||||
size_t path_len;
|
||||
char *pattern;
|
||||
size_t pattern_len;
|
||||
size_t *open_basedir_indexmap;
|
||||
size_t open_basedir_indexmap_size;
|
||||
bool open_basedir_used;
|
||||
} glob_s_t;
|
||||
|
||||
PHPAPI char* _php_glob_stream_get_path(php_stream *stream, size_t *plen STREAMS_DC) /* {{{ */
|
||||
@ -79,6 +82,11 @@ PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, size_t *plen STREA
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static inline int php_glob_stream_get_result_count(glob_s_t *pglob)
|
||||
{
|
||||
return pglob->open_basedir_used ? (int) pglob->open_basedir_indexmap_size : pglob->glob.gl_pathc;
|
||||
}
|
||||
|
||||
PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC) /* {{{ */
|
||||
{
|
||||
glob_s_t *pglob = (glob_s_t *)stream->abstract;
|
||||
@ -87,7 +95,7 @@ PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC
|
||||
if (pflags) {
|
||||
*pflags = pglob->flags;
|
||||
}
|
||||
return pglob->glob.gl_pathc;
|
||||
return php_glob_stream_get_result_count(pglob);
|
||||
} else {
|
||||
if (pflags) {
|
||||
*pflags = 0;
|
||||
@ -130,15 +138,21 @@ static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count)
|
||||
glob_s_t *pglob = (glob_s_t *)stream->abstract;
|
||||
php_stream_dirent *ent = (php_stream_dirent*)buf;
|
||||
const char *path;
|
||||
int glob_result_count;
|
||||
size_t index;
|
||||
|
||||
/* avoid problems if someone mis-uses the stream */
|
||||
if (count == sizeof(php_stream_dirent) && pglob) {
|
||||
if (pglob->index < (size_t)pglob->glob.gl_pathc) {
|
||||
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path);
|
||||
glob_result_count = php_glob_stream_get_result_count(pglob);
|
||||
if (pglob->index < (size_t) glob_result_count) {
|
||||
index = pglob->open_basedir_used && pglob->open_basedir_indexmap ?
|
||||
pglob->open_basedir_indexmap[pglob->index] : pglob->index;
|
||||
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[index], pglob->flags & GLOB_APPEND, &path);
|
||||
++pglob->index;
|
||||
PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
|
||||
return sizeof(php_stream_dirent);
|
||||
}
|
||||
pglob->index = pglob->glob.gl_pathc;
|
||||
pglob->index = glob_result_count;
|
||||
if (pglob->path) {
|
||||
efree(pglob->path);
|
||||
pglob->path = NULL;
|
||||
@ -162,6 +176,9 @@ static int php_glob_stream_close(php_stream *stream, int close_handle) /* {{{ *
|
||||
if (pglob->pattern) {
|
||||
efree(pglob->pattern);
|
||||
}
|
||||
if (pglob->open_basedir_indexmap) {
|
||||
efree(pglob->open_basedir_indexmap);
|
||||
}
|
||||
}
|
||||
efree(stream->abstract);
|
||||
return 0;
|
||||
@ -198,7 +215,7 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
|
||||
int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
|
||||
{
|
||||
glob_s_t *pglob;
|
||||
int ret;
|
||||
int ret, i;
|
||||
const char *tmp, *pos;
|
||||
|
||||
if (!strncmp(path, "glob://", sizeof("glob://")-1)) {
|
||||
@ -208,10 +225,6 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
|
||||
}
|
||||
}
|
||||
|
||||
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pglob = ecalloc(sizeof(*pglob), 1);
|
||||
|
||||
if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
|
||||
@ -224,6 +237,20 @@ static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const cha
|
||||
}
|
||||
}
|
||||
|
||||
/* if open_basedir in use, check and filter restricted paths */
|
||||
if ((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) {
|
||||
pglob->open_basedir_used = true;
|
||||
for (i = 0; i < pglob->glob.gl_pathc; i++) {
|
||||
if (!php_check_open_basedir_ex(pglob->glob.gl_pathv[i], 0)) {
|
||||
if (!pglob->open_basedir_indexmap) {
|
||||
pglob->open_basedir_indexmap = (size_t *) safe_emalloc(
|
||||
pglob->glob.gl_pathc, sizeof(size_t), 0);
|
||||
}
|
||||
pglob->open_basedir_indexmap[pglob->open_basedir_indexmap_size++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos = path;
|
||||
if ((tmp = strrchr(pos, '/')) != NULL) {
|
||||
pos = tmp+1;
|
||||
|
Loading…
Reference in New Issue
Block a user