mirror of
https://github.com/php/php-src.git
synced 2024-09-24 03:17:26 +00:00
MFB: fix #40931 (open_basedir bypass via symlink and move_uploaded_file())
This commit is contained in:
parent
210389ab21
commit
a8e133eafa
@ -147,8 +147,12 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
|
||||
char resolved_name[MAXPATHLEN];
|
||||
char resolved_basedir[MAXPATHLEN];
|
||||
char local_open_basedir[MAXPATHLEN];
|
||||
char path_tmp[MAXPATHLEN];
|
||||
char *path_file;
|
||||
int resolved_basedir_len;
|
||||
int resolved_name_len;
|
||||
int path_len;
|
||||
int nesting_level = 0;
|
||||
|
||||
/* Special case basedir==".": Use script-directory */
|
||||
if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
|
||||
@ -156,8 +160,64 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
|
||||
strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
|
||||
}
|
||||
|
||||
/* Resolve the real path into resolved_name */
|
||||
if ((expand_filepath(path, resolved_name TSRMLS_CC) != NULL) && (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL)) {
|
||||
path_len = strlen(path);
|
||||
if (path_len > (MAXPATHLEN - 1)) {
|
||||
/* empty and too long paths are invalid */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* normalize and expand path */
|
||||
if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
path_len = strlen(resolved_name);
|
||||
memcpy(path_tmp, resolved_name, path_len + 1); /* safe */
|
||||
|
||||
while (VCWD_REALPATH(path_tmp, resolved_name) == NULL) {
|
||||
#ifdef HAVE_SYMLINK
|
||||
if (nesting_level == 0) {
|
||||
int ret;
|
||||
char buf[MAXPATHLEN];
|
||||
|
||||
ret = readlink(path_tmp, buf, MAXPATHLEN - 1);
|
||||
if (ret < 0) {
|
||||
/* not a broken symlink, move along.. */
|
||||
} else {
|
||||
/* put the real path into the path buffer */
|
||||
memcpy(path_tmp, buf, ret);
|
||||
path_tmp[ret] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PHP_WIN32) || defined(NETWARE)
|
||||
path_file = strrchr(path_tmp, DEFAULT_SLASH);
|
||||
if (!path_file) {
|
||||
path_file = strrchr(path_tmp, '/');
|
||||
}
|
||||
#else
|
||||
path_file = strrchr(path_tmp, DEFAULT_SLASH);
|
||||
#endif
|
||||
if (!path_file) {
|
||||
/* none of the path components exist. definitely not in open_basedir.. */
|
||||
return -1;
|
||||
} else {
|
||||
path_len = path_file - path_tmp + 1;
|
||||
#if defined(PHP_WIN32) || defined(NETWARE)
|
||||
if (path_len > 1 && path_tmp[path_len - 2] == ':') {
|
||||
/* this is c:\, */
|
||||
path_tmp[path_len] = '\0';
|
||||
}
|
||||
#else
|
||||
path_tmp[path_len - 1] = '\0';
|
||||
#endif
|
||||
}
|
||||
nesting_level++;
|
||||
}
|
||||
|
||||
/* Resolve open_basedir to resolved_basedir */
|
||||
if (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL) {
|
||||
/* Handler for basedirs that end with a / */
|
||||
resolved_basedir_len = strlen(resolved_basedir);
|
||||
if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR) {
|
||||
@ -167,7 +227,7 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
|
||||
}
|
||||
}
|
||||
|
||||
if (path[strlen(path)-1] == PHP_DIR_SEPARATOR) {
|
||||
if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
|
||||
resolved_name_len = strlen(resolved_name);
|
||||
if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
|
||||
resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
|
||||
|
Loading…
Reference in New Issue
Block a user