Skip to content

Commit

Permalink
Open basedir (#4407)
Browse files Browse the repository at this point in the history
* fix bug #4327

* fix bug #4327

* fix bug #4327

* unit test

* 代码格式

* 单元测试

* 修复无符号和有符号之间的比较

* unit test

* unit test

* open_basedir

* support open_basedir

* support open_basedir

* (void *)buf

* (char *) memchr(buf, DEFAULT_SLASH, dir_len))

* clang-format
  • Loading branch information
NathanFreeman authored Sep 15, 2021
1 parent 6345fe8 commit 1c02a87
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 66 deletions.
28 changes: 28 additions & 0 deletions tests/swoole_runtime/file_hook/open_basedir.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
support open_basedir config
--SKIPIF--
<?php
require __DIR__ . '/../../include/skipif.inc';
?>
--FILE--
<?php
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
ini_set("open_basedir","/tmp/:/tmp/tes");
mkdir("/home/test/",0755);
var_dump(mkdir("/tmp/test/",0755));
var_dump(mkdir("/tmp/test1/",0755));
var_dump(mkdir("/tmp/test/test",0755, true));
rmdir("/tmp/test/test");
rmdir("/tmp/test/");
rmdir("/tmp/test1/");
});
?>
--EXPECTF--

Warning: mkdir(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s) in %s on line 7
bool(true)
bool(true)
bool(true)
149 changes: 83 additions & 66 deletions thirdparty/php/streams/plain_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static int sw_php_stdiop_cast(php_stream *stream, int castas, void **ret);
static void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *result);
static php_stream *_sw_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC);
static php_stream *_sw_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC);
static int sw_php_mkdir(const char *dir, zend_long mode);

static inline zend_bool file_can_poll(zend_stat_t *_stat) {
return S_ISCHR(_stat->st_mode) || S_ISSOCK(_stat->st_mode) || S_ISFIFO(_stat->st_mode);
Expand Down Expand Up @@ -1030,90 +1031,92 @@ static int php_plain_files_rename(

static int php_plain_files_mkdir(
php_stream_wrapper *wrapper, const char *dir, int mode, int options, php_stream_context *context) {
int ret, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
char *p;

if (strncasecmp(dir, "file://", sizeof("file://") - 1) == 0) {
dir += sizeof("file://") - 1;
}

if (!recursive) {
ret = mkdir(dir, mode);
} else {
/* we look for directory separator from the end of string, thus hopefuly reducing our work load */
char *e;
zend_stat_t sb;
int dir_len = (int) strlen(dir);
int offset = 0;
char buf[MAXPATHLEN];

if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND)) {
php_error_docref(NULL, E_WARNING, "Invalid path");
return 0;
}
if (!(options & PHP_STREAM_MKDIR_RECURSIVE)) {
return sw_php_mkdir(dir, mode) == 0;
}

e = buf + strlen(buf);
char buf[MAXPATHLEN];
if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND)) {
php_error_docref(NULL, E_WARNING, "Invalid path");
return 0;
}

if ((p = (char *) memchr(buf, DEFAULT_SLASH, dir_len))) {
offset = p - buf + 1;
}
if (php_check_open_basedir(buf)) {
return 0;
}

if (p && dir_len == 1) {
/* buf == "DEFAULT_SLASH" */
} else {
/* find a top level directory we need to create */
while ((p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH)))) {
int n = 0;
/* we look for directory separator from the end of string, thus hopefully reducing our work load */
char *p;
zend_stat_t sb;
size_t dir_len = strlen(dir), offset = 0;
char *e = buf + strlen(buf);

if ((p = (char *) memchr(buf, DEFAULT_SLASH, dir_len))) {
offset = p - buf + 1;
}

if (p && dir_len == 1) {
/* buf == "DEFAULT_SLASH" */
} else {
/* find a top level directory we need to create */
while ((p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH)))) {
int n = 0;

*p = '\0';
while (p > buf && *(p - 1) == DEFAULT_SLASH) {
++n;
--p;
*p = '\0';
while (p > buf && *(p - 1) == DEFAULT_SLASH) {
++n;
--p;
*p = '\0';
}
if (stat(buf, &sb) == 0) {
while (1) {
*p = DEFAULT_SLASH;
if (!n) break;
--n;
++p;
}
break;
}
if (stat(buf, &sb) == 0) {
while (1) {
*p = DEFAULT_SLASH;
if (!n) break;
--n;
++p;
}
break;
}
}
}

if (p == buf) {
ret = mkdir(dir, mode);
} else if (!(ret = mkdir(buf, mode)) || EEXIST == errno) {
if (!p) {
p = buf;
if (!p) {
p = buf;
}
while (true) {
int ret = mkdir(buf, (mode_t) mode);
if (ret < 0 && errno != EEXIST) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
/* create any needed directories if the creation of the 1st directory worked */
while (++p != e) {
if (*p == '\0') {
*p = DEFAULT_SLASH;
if ((*(p + 1) != '\0') && (ret = mkdir(buf, (mode_t) mode)) < 0) {
// parent directory already exists and try to create child directories.
if (EEXIST == errno && (int) strlen(buf) < dir_len) {
continue;
}
return 0;
}

if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
break;
}
bool replaced_slash = false;
while (++p != e) {
if (*p == '\0') {
replaced_slash = true;
*p = DEFAULT_SLASH;
if (*(p + 1) != '\0') {
break;
}
}
}
}
if (ret < 0) {
/* Failure */
return 0;
} else {
/* Success */
return 1;
if (p == e || !replaced_slash) {
/* No more directories to create */
/* issue a warning to client when the last directory was created failed */
if (ret < 0) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
return 0;
}
return 1;
}
}
}

Expand Down Expand Up @@ -1259,6 +1262,20 @@ static php_stream *_sw_php_stream_fopen_from_fd(int fd, const char *mode, const
return stream;
}

static int sw_php_mkdir(const char *dir, zend_long mode) {
int ret;

if (php_check_open_basedir(dir)) {
return -1;
}

if ((ret = mkdir(dir, (mode_t) mode)) < 0) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}

return ret;
}

static void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *result) {
/* replace modes not supported by fdopen and fopencookie, but supported
* by PHP's fread(), so that their calls won't fail */
Expand Down

0 comments on commit 1c02a87

Please sign in to comment.