MFB: fix #40931 (open_basedir bypass via symlink and move_uploaded_file())

This commit is contained in:
Antony Dovgal 2007-04-10 22:31:27 +00:00
parent 210389ab21
commit a8e133eafa

View File

@ -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;