]> granicus.if.org Git - php/commitdiff
- Add path sanitizer for new paths
authorMarcus Boerger <helly@php.net>
Sun, 4 Feb 2007 13:21:40 +0000 (13:21 +0000)
committerMarcus Boerger <helly@php.net>
Sun, 4 Feb 2007 13:21:40 +0000 (13:21 +0000)
- Add test for a few things we check with the sanitizer
# We might want to use the sanitizer for opening as well

ext/phar/config.m4
ext/phar/config.w32
ext/phar/package.xml
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/phar_path_check.c [new file with mode: 0755]
ext/phar/phar_path_check.re [new file with mode: 0755]
ext/phar/tests/create_path_error.phpt [new file with mode: 0755]

index 8a35fa779ddd1d9d34d20dbfffa89bd5078c3ed9..6b4b438310624587f1540e63d0e904fe81b6c8d9 100644 (file)
@@ -5,7 +5,7 @@ PHP_ARG_ENABLE(phar, for phar support/phar zlib support,
 [  --enable-phar           Enable phar support, use --with-zlib-dir if zlib detection fails])
 
 if test "$PHP_PHAR" != "no"; then
-  PHP_NEW_EXTENSION(phar, phar.c phar_object.c, $ext_shared)
+  PHP_NEW_EXTENSION(phar, phar.c phar_object.c phar_path_check.c, $ext_shared)
   PHP_ADD_EXTENSION_DEP(phar, zlib, true)
   PHP_ADD_EXTENSION_DEP(phar, bz2, true)
   PHP_ADD_EXTENSION_DEP(phar, spl, false)
index 3ad36b4d897e211aefecb68c8821621fdd683a2c..d2392aa4833b507d9d414e4e650a48f79dbe3b13 100644 (file)
@@ -4,7 +4,7 @@
 ARG_ENABLE("phar", "enable phar support", "no");
 
 if (PHP_PHAR != "no") {
-       EXTENSION("phar", "phar.c phar_object.c");
+       EXTENSION("phar", "phar.c phar_object.c phar_path_check.c");
        ADD_EXTENSION_DEP('phar', 'zlib', true);
        ADD_EXTENSION_DEP('phar', 'bz2', true);
        ADD_EXTENSION_DEP('phar', 'spl', false);
index 19d80d103748fdea428cf2115e2f32abde645b76..12d53e66c1469a57af158f00320183dfb1ee2056 100644 (file)
@@ -92,6 +92,7 @@ if the ini variable phar.require_hash is set to true.
     <file name="create_new_phar.phpt" role="test"/>
     <file name="create_new_phar_b.phpt" role="test"/>
     <file name="create_new_phar_c.phpt" role="test"/>
+    <file name="create_path_error.phpt" role="test"/>
     <file name="delete_in_phar.phpt" role="test"/>
     <file name="delete_in_phar_b.phpt" role="test"/>
     <file name="delete_in_phar_confirm.phpt" role="test"/>
@@ -150,6 +151,8 @@ if the ini variable phar.require_hash is set to true.
    <file name="phar_object.c" role="src"/>
    <file name="php_phar.h" role="src"/>
    <file name="phar_internal.h" role="src"/>
+   <file name="phar_path_check.c" role="src"/>
+   <file name="phar_path_check.re" role="src"/>
   </dir> <!-- / -->
  </contents>
  <dependencies>
index dabae5d83289506656f6bfa7265eb24d0f63bf5f..ec248f9e6e0b5e2aa6b7de9f94cbae0b43508e07 100644 (file)
@@ -434,6 +434,15 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char
        phar_archive_data *phar;
        phar_entry_info *entry, etemp;
        phar_entry_data *ret;
+       phar_path_check_result res;
+       const char *pcr_error;
+
+       if ((res = phar_path_check(path, &path_len, &pcr_error)) > pcr_is_ok) {
+               if (error) {
+                       spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
+               }
+               return NULL;
+       }
 
        if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
                return NULL;
@@ -441,8 +450,7 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char
 
        if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, error TSRMLS_CC)) {
                return NULL;
-       }
-       if (ret) {
+       } else if (ret) {
                return ret;
        }
 
@@ -1453,8 +1461,9 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
                        if (error) {
                                php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
                                efree(error);
+                       } else {
+                               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
                        }
-                       php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
                        efree(internal_file);
                        php_url_free(resource);
                        return NULL;
index 8ec79add344100fe1316f8b238538b4005940a54..86aafd5295ab9ecb9378e73b1d76b927a66f4416 100755 (executable)
@@ -257,6 +257,18 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char
 int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC);
 int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC);
 
+typedef enum {
+       pcr_use_query,
+       pcr_is_ok,
+       pcr_err_double_slash,
+       pcr_err_up_dir,
+       pcr_err_curr_dir,
+       pcr_err_back_slash,
+       pcr_err_empty_entry
+} phar_path_check_result;
+
+phar_path_check_result phar_path_check(const char *p, int *len, const char **error);
+
 END_EXTERN_C()
 
 /*
diff --git a/ext/phar/phar_path_check.c b/ext/phar/phar_path_check.c
new file mode 100755 (executable)
index 0000000..e647df9
--- /dev/null
@@ -0,0 +1,159 @@
+/* Generated by re2c 0.11.0 on Sun Feb  4 07:53:57 2007 */
+#line 1 "ext/phar/phar_path_check.re"
+/*
+  +----------------------------------------------------------------------+
+  | phar php single-file executable PHP extension                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2005-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt.                                 |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Marcus Boerger <helly@php.net>                              |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(const char *s, int *len, const char **error)
+{
+       const unsigned char *p = (const unsigned char*)s;
+       const unsigned char *m;
+#define YYCTYPE         unsigned char
+#define YYCURSOR        p
+#define YYLIMIT         p+*len
+#define YYMARKER        m
+#define YYFILL(n)
+
+loop:
+{
+
+#line 39 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+       {
+               YYCTYPE yych;
+
+               if((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+               yych = *YYCURSOR;
+               if(yych <= '/') {
+                       if(yych <= 0x09) {
+                               if(yych <= 0x00) goto yy9;
+                               goto yy11;
+                       } else {
+                               if(yych <= 0x0A) goto yy2;
+                               if(yych <= '.') goto yy11;
+                               goto yy3;
+                       }
+               } else {
+                       if(yych <= '?') {
+                               if(yych <= '>') goto yy11;
+                               goto yy7;
+                       } else {
+                               if(yych == '\\') goto yy5;
+                               goto yy11;
+                       }
+               }
+yy2:
+               YYCURSOR = YYMARKER;
+               goto yy4;
+yy3:
+               yych = *(YYMARKER = ++YYCURSOR);
+               if(yych <= 0x00) goto yy12;
+               if(yych <= '-') goto yy4;
+               if(yych <= '.') goto yy14;
+               if(yych <= '/') goto yy15;
+yy4:
+#line 73 "ext/phar/phar_path_check.re"
+               {
+                       goto loop;
+               }
+#line 77 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy5:
+               ++YYCURSOR;
+#line 50 "ext/phar/phar_path_check.re"
+               {
+                       *error = "back-slash";
+                       return pcr_err_back_slash;
+               }
+#line 85 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy7:
+               ++YYCURSOR;
+#line 58 "ext/phar/phar_path_check.re"
+               {
+                       if (*s == '/') {
+                               s++;
+                       }
+                       *len = (p - (const unsigned char*)s) -1;
+                       *error = NULL;
+                       return pcr_use_query;
+               }
+#line 97 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy9:
+               ++YYCURSOR;
+#line 66 "ext/phar/phar_path_check.re"
+               {
+                       if (*s == '/') {
+                               s++;
+                       }
+                       *error = NULL;
+                       return pcr_is_ok;
+               }
+#line 108 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy11:
+               yych = *++YYCURSOR;
+               goto yy4;
+yy12:
+               ++YYCURSOR;
+#line 54 "ext/phar/phar_path_check.re"
+               {
+                       *error = "empty entry";
+                       return pcr_err_empty_entry;
+               }
+#line 119 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy14:
+               yych = *++YYCURSOR;
+               if(yych <= 0x00) goto yy18;
+               if(yych <= '-') goto yy2;
+               if(yych <= '.') goto yy17;
+               if(yych <= '/') goto yy18;
+               goto yy2;
+yy15:
+               ++YYCURSOR;
+#line 38 "ext/phar/phar_path_check.re"
+               {
+                       *error = "double slash";
+                       return pcr_err_double_slash;
+               }
+#line 134 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy17:
+               yych = *++YYCURSOR;
+               if(yych <= 0x00) goto yy20;
+               if(yych == '/') goto yy20;
+               goto yy2;
+yy18:
+               ++YYCURSOR;
+#line 46 "ext/phar/phar_path_check.re"
+               {
+                       *error = "current directory reference";
+                       return pcr_err_curr_dir;
+               }
+#line 147 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy20:
+               ++YYCURSOR;
+#line 42 "ext/phar/phar_path_check.re"
+               {
+                       *error = "upper directory reference";
+                       return pcr_err_up_dir;
+               }
+#line 155 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+       }
+}
+#line 76 "ext/phar/phar_path_check.re"
+
+}
diff --git a/ext/phar/phar_path_check.re b/ext/phar/phar_path_check.re
new file mode 100755 (executable)
index 0000000..f7a0f60
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  +----------------------------------------------------------------------+
+  | phar php single-file executable PHP extension                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2005-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt.                                 |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Marcus Boerger <helly@php.net>                              |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(const char *s, int *len, const char **error)
+{
+       const unsigned char *p = (const unsigned char*)s;
+       const unsigned char *m;
+#define YYCTYPE         unsigned char
+#define YYCURSOR        p
+#define YYLIMIT         p+*len
+#define YYMARKER        m
+#define YYFILL(n)
+
+loop:
+/*!re2c
+END = "\x00";
+EOS = "/" | END;
+ANY = .;
+"//"   {
+                       *error = "double slash";
+                       return pcr_err_double_slash;
+               }
+"/.." EOS {
+                       *error = "upper directory reference";
+                       return pcr_err_up_dir;
+               }
+"/." EOS {
+                       *error = "current directory reference";
+                       return pcr_err_curr_dir;
+               }
+"\\" {
+                       *error = "back-slash";
+                       return pcr_err_back_slash;
+               }
+"/" END {
+                       *error = "empty entry";
+                       return pcr_err_empty_entry;
+               }
+"?"    {
+                       if (*s == '/') {
+                               s++;
+                       }
+                       *len = (p - (const unsigned char*)s) -1;
+                       *error = NULL;
+                       return pcr_use_query;
+               }
+END {
+                       if (*s == '/') {
+                               s++;
+                       }
+                       *error = NULL;
+                       return pcr_is_ok;
+               }
+ANY {
+                       goto loop;
+               }
+*/
+}
diff --git a/ext/phar/tests/create_path_error.phpt b/ext/phar/tests/create_path_error.phpt
new file mode 100755 (executable)
index 0000000..f19df18
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+Phar: create with illegal path
+--SKIPIF--
+<?php if (!extension_loaded("phar")) print "skip"; ?>
+<?php if (!extension_loaded("spl")) print "skip SPL not available"; ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php?', "query");
+file_put_contents($pname . '/b.php?bla', "query");
+
+var_dump(file_get_contents($pname . '/a.php'));
+var_dump(file_get_contents($pname . '/b.php'));
+
+function error_handler($errno, $errmsg)
+{
+       echo "Error: $errmsg\n";
+}
+
+set_error_handler('error_handler');
+
+$checks = array('//', '/.', '/../', '/a/..');
+foreach($checks as $check)
+{
+       file_put_contents($pname . $check, "error");
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+string(5) "query"
+string(5) "query"
+Error: file_put_contents(phar://%s//): failed to open stream: phar error: invalid path "/" contains empty entry
+Error: file_put_contents(phar://%s/../): failed to open stream: phar error: invalid path "../" contains empty entry
+Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: invalid path "a/.." contains upper directory reference
+===DONE===