hi again,

On Fri, Jan 23, 2009 at 08:23:59AM +0100, sean finney wrote:
> it's unfortunate that there isn't a more surgical fix (301 insertions!),
> but i'll take your word for it that it would be too complicated/dangerous
> to try and modify virtual_file_ex() directly.

actually, i think i've found a slightly more graceful workaround :)

since virtual_file_ex is to fragile to be changed, here's a patch that
does the following as a workaround:

- take a temporary copy of the filename
- replace all instances of "^../", "/../", and "/..$" with "///".
- pass this mangled filename to virtual_file_ex for normalization

it seems virtual_file_ex can handle such a filename without problem, and 
with proper formatting the current patch only inserts 22 lines to php_zip.c.
someone should probably double check this code for early-morning coding
errors though :)

what do you think?


        sean
--- ext/zip/php_zip.c.orig      2009-01-23 08:29:32.000000000 +0100
+++ ext/zip/php_zip.c   2009-01-23 08:56:42.000000000 +0100
@@ -142,6 +142,9 @@
        char *path_cleaned;
        size_t path_cleaned_len;
        cwd_state new_state;
+  char *tmp_file = NULL;
+  char *tmp_needle = NULL;
+  int virtual_ret = 0;
 
        new_state.cwd = (char*)malloc(1);
        new_state.cwd[0] = '\0';
@@ -150,7 +153,25 @@
        /* Clean/normlize the path and then transform any path (absolute or 
relative)
                 to a path relative to cwd (../../mydir/foo.txt > mydir/foo.txt)
         */
-       virtual_file_ex(&new_state, file, NULL, CWD_EXPAND);
+  tmp_file = strdup(file); 
+  while (tmp_needle=strstr(tmp_file, "/../"))
+  {
+    *(tmp_needle+1)=*(tmp_needle+2)='/';
+  }
+  if (strncmp(tmp_file, "..", 2) == 0 && (file_len == 2 || tmp_file[2] == '/'))
+  {
+    tmp_file[0]=tmp_file[1]='/';
+  }
+  if (file_len > 3 && strncmp(&tmp_file[file_len-2], "..", 2) == 0) 
+  {
+    tmp_file[file_len-1]=tmp_file[file_len-2]='/';
+  }
+       virtual_ret = virtual_file_ex(&new_state, tmp_file, NULL, CWD_EXPAND);
+  free(tmp_file);
+  if (virtual_ret == 1) 
+  {
+    return 0;
+  }
        path_cleaned =  php_zip_make_relative_path(new_state.cwd, 
new_state.cwd_length);
        path_cleaned_len = strlen(path_cleaned);
 

Attachment: signature.asc
Description: Digital signature

Reply via email to