tony2001                Tue Apr 10 22:30:07 2007 UTC

  Modified files:              (Branch: PHP_5_2)
    /php-src    NEWS 
    /php-src/main       fopen_wrappers.c 
  Log:
  fix #40931 (open_basedir bypass via symlink and move_uploaded_file())
  
  
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.634&r2=1.2027.2.547.2.635&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.634 php-src/NEWS:1.2027.2.547.2.635
--- php-src/NEWS:1.2027.2.547.2.634     Tue Apr 10 20:28:48 2007
+++ php-src/NEWS        Tue Apr 10 22:30:07 2007
@@ -57,6 +57,8 @@
 - 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)
http://cvs.php.net/viewvc.cgi/php-src/main/fopen_wrappers.c?r1=1.175.2.3.2.9&r2=1.175.2.3.2.10&diff_format=u
Index: php-src/main/fopen_wrappers.c
diff -u php-src/main/fopen_wrappers.c:1.175.2.3.2.9 
php-src/main/fopen_wrappers.c:1.175.2.3.2.10
--- php-src/main/fopen_wrappers.c:1.175.2.3.2.9 Sat Feb 24 02:17:28 2007
+++ php-src/main/fopen_wrappers.c       Tue Apr 10 22:30:07 2007
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: fopen_wrappers.c,v 1.175.2.3.2.9 2007/02/24 02:17:28 helly Exp $ */
+/* $Id: fopen_wrappers.c,v 1.175.2.3.2.10 2007/04/10 22:30:07 tony2001 Exp $ */
 
 /* {{{ includes
  */
@@ -90,8 +90,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)) {
@@ -99,8 +103,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) {
@@ -110,7 +170,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