Skip to content

Commit

Permalink
fix #40931 (open_basedir bypass via symlink and move_uploaded_file())
Browse files Browse the repository at this point in the history
  • Loading branch information
tony2001 committed Apr 10, 2007
1 parent e145f1a commit 19aa4a9
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -57,6 +57,8 @@ PHP NEWS
- Fixed bug #40998 (long session array keys are truncated). (Tony)
- Implement feature request #40947, allow a single filter as argument
for filter_var_array (Pierre)
- Fixed bug #40931 (open_basedir bypass via symlink and move_uploaded_file()).
(Tony)
- Fixed bug #40921 (php_default_post_reader crashes when post_max_size is
exceeded). (trickie at gmail dot com, Ilia)
- Fixed bug #40915 (addcslashes unexpected behavior with binary input). (Tony)
Expand Down
66 changes: 63 additions & 3 deletions main/fopen_wrappers.c
Expand Up @@ -90,17 +90,77 @@ 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)) {
/* Else use the unmodified 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) {
Expand All @@ -110,7 +170,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;
Expand Down

0 comments on commit 19aa4a9

Please sign in to comment.