tony2001                Tue Apr 10 22:31:27 2007 UTC

  Modified files:              
    /php-src/main       fopen_wrappers.c 
  Log:
  MFB: fix #40931 (open_basedir bypass via symlink and move_uploaded_file())
  
  
http://cvs.php.net/viewvc.cgi/php-src/main/fopen_wrappers.c?r1=1.191&r2=1.192&diff_format=u
Index: php-src/main/fopen_wrappers.c
diff -u php-src/main/fopen_wrappers.c:1.191 php-src/main/fopen_wrappers.c:1.192
--- php-src/main/fopen_wrappers.c:1.191 Sat Feb 24 16:25:55 2007
+++ php-src/main/fopen_wrappers.c       Tue Apr 10 22:31:27 2007
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: fopen_wrappers.c,v 1.191 2007/02/24 16:25:55 helly Exp $ */
+/* $Id: fopen_wrappers.c,v 1.192 2007/04/10 22:31:27 tony2001 Exp $ */
 
 /* {{{ includes
  */
@@ -147,8 +147,12 @@
        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 @@
                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 @@
                        }
                }
 
-               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;

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to