summaryrefslogtreecommitdiff
path: root/main/fopen_wrappers.c
diff options
context:
space:
mode:
authorAntony Dovgal <tony2001@php.net>2007-04-10 22:30:07 +0000
committerAntony Dovgal <tony2001@php.net>2007-04-10 22:30:07 +0000
commit19aa4a932f6d5cc10c98ffa3f3bd91a4b5673c96 (patch)
tree62496dc2fbd97c31cf4c045afdee935e07951bcc /main/fopen_wrappers.c
parente145f1aa2a3406dd24dd83a495074460976a6772 (diff)
downloadphp-git-19aa4a932f6d5cc10c98ffa3f3bd91a4b5673c96.tar.gz
fix #40931 (open_basedir bypass via symlink and move_uploaded_file())
Diffstat (limited to 'main/fopen_wrappers.c')
-rw-r--r--main/fopen_wrappers.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
index ebcdb711fa..0b476cf5e4 100644
--- a/main/fopen_wrappers.c
+++ b/main/fopen_wrappers.c
@@ -90,8 +90,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)) {
@@ -99,8 +103,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) {
@@ -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;