From: Marcus Boerger Date: Sun, 4 Feb 2007 13:21:40 +0000 (+0000) Subject: - Add path sanitizer for new paths X-Git-Tag: RELEASE_1_0_0RC1~25 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c690cb9d4f509e5aa9a64960264daf4a6fb5d39;p=php - Add path sanitizer for new paths - Add test for a few things we check with the sanitizer # We might want to use the sanitizer for opening as well --- diff --git a/ext/phar/config.m4 b/ext/phar/config.m4 index 8a35fa779d..6b4b438310 100644 --- a/ext/phar/config.m4 +++ b/ext/phar/config.m4 @@ -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) diff --git a/ext/phar/config.w32 b/ext/phar/config.w32 index 3ad36b4d89..d2392aa483 100644 --- a/ext/phar/config.w32 +++ b/ext/phar/config.w32 @@ -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); diff --git a/ext/phar/package.xml b/ext/phar/package.xml index 19d80d1037..12d53e66c1 100644 --- a/ext/phar/package.xml +++ b/ext/phar/package.xml @@ -92,6 +92,7 @@ if the ini variable phar.require_hash is set to true. + @@ -150,6 +151,8 @@ if the ini variable phar.require_hash is set to true. + + diff --git a/ext/phar/phar.c b/ext/phar/phar.c index dabae5d832..ec248f9e6e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -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; diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 8ec79add34..86aafd5295 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -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 index 0000000000..e647df9647 --- /dev/null +++ b/ext/phar/phar_path_check.c @@ -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 | + +----------------------------------------------------------------------+ +*/ + +/* $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 index 0000000000..f7a0f60e62 --- /dev/null +++ b/ext/phar/phar_path_check.re @@ -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 | + +----------------------------------------------------------------------+ +*/ + +/* $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 index 0000000000..f19df183d6 --- /dev/null +++ b/ext/phar/tests/create_path_error.phpt @@ -0,0 +1,46 @@ +--TEST-- +Phar: create with illegal path +--SKIPIF-- + + +--INI-- +phar.readonly=0 +phar.require_hash=1 +--FILE-- + +===DONE=== +--CLEAN-- + +--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===