Skip to content

Commit c1072dc

Browse files
committed
Fix GH-13204: glob() fails if square bracket is in current directory
The problem is not limited to square brackets, but to every meta character. The solution is to override the glob functions for handling paths with the VCWD ones in PHP. If that is not available, use the old but limited workaround.
1 parent b27d919 commit c1072dc

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

ext/standard/dir.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,34 @@ PHP_FUNCTION(getcwd)
400400
/* }}} */
401401

402402
/* {{{ Find pathnames matching a pattern */
403+
#if defined(ZTS) && defined(PHP_GLOB_ALTDIRFUNC)
404+
static void *php_glob_opendir_wrapper(const char *path)
405+
{
406+
return VCWD_OPENDIR(path);
407+
}
408+
409+
static void php_glob_closedir_wrapper(void *dir)
410+
{
411+
(void) closedir(dir);
412+
}
413+
414+
static int php_glob_lstat_wrapper(const char *buf, zend_stat_t *sb)
415+
{
416+
return VCWD_LSTAT(buf, sb);
417+
}
418+
419+
static int php_glob_stat_wrapper(const char *buf, zend_stat_t *sb)
420+
{
421+
return VCWD_STAT(buf, sb);
422+
}
423+
#endif
424+
403425
PHP_FUNCTION(glob)
404426
{
405427
size_t cwd_skip = 0;
406-
#ifdef ZTS
428+
#if defined(ZTS) && !defined(PHP_GLOB_ALTDIRFUNC)
407429
char cwd[MAXPATHLEN];
408430
char work_pattern[MAXPATHLEN];
409-
char *result;
410431
#endif
411432
char *pattern = NULL;
412433
size_t pattern_len;
@@ -433,9 +454,28 @@ PHP_FUNCTION(glob)
433454
RETURN_FALSE;
434455
}
435456

457+
memset(&globbuf, 0, sizeof(globbuf));
458+
459+
int passed_glob_flags = flags & PHP_GLOB_FLAGMASK;
460+
436461
#ifdef ZTS
437462
if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
438-
result = VCWD_GETCWD(cwd, MAXPATHLEN);
463+
/* System glob uses the current work directory which is not thread safe.
464+
* The first fix is to override the functions used to open/read/... paths
465+
* with the VCWD ones used in PHP.
466+
* If that functionality is unavailable for whatever reason, fall back
467+
* to prepending the current working directory to the passed path.
468+
* However, that comes with limitations regarding meta characters
469+
* that is not solvable in general (GH-13204). */
470+
#ifdef PHP_GLOB_ALTDIRFUNC
471+
globbuf.gl_opendir = php_glob_opendir_wrapper;
472+
globbuf.gl_readdir = (struct dirent *(*)(void *)) readdir;
473+
globbuf.gl_closedir = php_glob_closedir_wrapper;
474+
globbuf.gl_lstat = php_glob_lstat_wrapper;
475+
globbuf.gl_stat = php_glob_stat_wrapper;
476+
passed_glob_flags |= PHP_GLOB_ALTDIRFUNC;
477+
#else
478+
char *result = VCWD_GETCWD(cwd, MAXPATHLEN);
439479
if (!result) {
440480
cwd[0] = '\0';
441481
}
@@ -448,13 +488,13 @@ PHP_FUNCTION(glob)
448488

449489
snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
450490
pattern = work_pattern;
491+
#endif
451492
}
452493
#endif
453494

454495

455-
memset(&globbuf, 0, sizeof(globbuf));
456496
globbuf.gl_offs = 0;
457-
if (0 != (ret = php_glob(pattern, flags & PHP_GLOB_FLAGMASK, NULL, &globbuf))) {
497+
if (0 != (ret = php_glob(pattern, passed_glob_flags, NULL, &globbuf))) {
458498
#ifdef PHP_GLOB_NOMATCH
459499
if (PHP_GLOB_NOMATCH == ret) {
460500
/* Some glob implementation simply return no data if no matches

ext/standard/tests/file/gh13204.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
GH-13204 (glob() fails if square bracket is in current directory)
3+
--FILE--
4+
<?php
5+
chdir(__DIR__ . '/gh13204[brackets]/');
6+
var_dump(glob('./*'));
7+
?>
8+
--EXPECT--
9+
array(1) {
10+
[0]=>
11+
string(11) "./empty.txt"
12+
}

ext/standard/tests/file/gh13204[brackets]/empty.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)