cellog Thu May 15 16:09:21 2008 UTC Modified files: /php-src/ext/phar dirstream.c phar_internal.h phar_object.c stream.c util.c /php-src/ext/phar/tests phar_extract2.phpt phar_offset_check.phpt 030.phpt addfuncs.phpt mkdir.phpt mounteddir.phpt phar_buildfromiterator4.phpt phar_copy.phpt phar_offset_get_error.phpt zf_test.phpt /php-src/ext/phar/tests/tar dir.phpt tar_003.phpt Log: MFB: plug security hole of unfettered creation access to .phar magic directory
http://cvs.php.net/viewvc.cgi/php-src/ext/phar/dirstream.c?r1=1.28&r2=1.29&diff_format=u Index: php-src/ext/phar/dirstream.c diff -u php-src/ext/phar/dirstream.c:1.28 php-src/ext/phar/dirstream.c:1.29 --- php-src/ext/phar/dirstream.c:1.28 Wed May 14 21:27:31 2008 +++ php-src/ext/phar/dirstream.c Thu May 15 16:09:21 2008 @@ -196,8 +196,9 @@ ALLOC_HASHTABLE(data); zend_hash_init(data, 64, zend_get_hash_value, NULL, 0); - if (*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) { + if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) { /* make empty root directory for empty phar */ + /* make empty directory for .phar magic directory */ efree(dir); return php_stream_alloc(&phar_dir_ops, data, NULL, "r"); } @@ -217,6 +218,13 @@ } if (*dir == '/') { /* root directory */ + if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) { + /* do not add any magic entries to this directory */ + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; + } + continue; + } if (NULL != (found = (char *) memchr(str_key, '/', keylen))) { /* the entry has a path separator and is a subdirectory */ entry = (char *) safe_emalloc(found - str_key, 1, 1); @@ -446,7 +454,7 @@ return FAILURE; } - if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error TSRMLS_CC))) { + if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1 TSRMLS_CC))) { /* directory exists, or is a subdirectory of an existing file */ if (e->is_temp_dir) { efree(e->filename); @@ -462,7 +470,7 @@ php_url_free(resource); return FAILURE; } - if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error TSRMLS_CC))) { + if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC))) { /* entry exists as a file */ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host); php_url_free(resource); @@ -565,7 +573,7 @@ return FAILURE; } - if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error TSRMLS_CC))) { + if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error, 1 TSRMLS_CC))) { if (error) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error); efree(error); http://cvs.php.net/viewvc.cgi/php-src/ext/phar/phar_internal.h?r1=1.110&r2=1.111&diff_format=u Index: php-src/ext/phar/phar_internal.h diff -u php-src/ext/phar/phar_internal.h:1.110 php-src/ext/phar/phar_internal.h:1.111 --- php-src/ext/phar/phar_internal.h:1.110 Wed May 14 21:27:31 2008 +++ php-src/ext/phar/phar_internal.h Thu May 15 16:09:21 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: phar_internal.h,v 1.110 2008/05/14 21:27:31 sfox Exp $ */ +/* $Id: phar_internal.h,v 1.111 2008/05/15 16:09:21 cellog Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -445,10 +445,10 @@ int phar_archive_delref(phar_archive_data *phar TSRMLS_DC); int phar_entry_delref(phar_entry_data *idata TSRMLS_DC); -phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC); -phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC); -phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC); -int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC); +phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC); +phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC); +phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC); +int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC); int phar_flush(phar_archive_data *archive, char *user_stub, long len, int convert, char **error TSRMLS_DC); int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC); int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC); http://cvs.php.net/viewvc.cgi/php-src/ext/phar/phar_object.c?r1=1.268&r2=1.269&diff_format=u Index: php-src/ext/phar/phar_object.c diff -u php-src/ext/phar/phar_object.c:1.268 php-src/ext/phar/phar_object.c:1.269 --- php-src/ext/phar/phar_object.c:1.268 Wed May 14 21:27:31 2008 +++ php-src/ext/phar/phar_object.c Thu May 15 16:09:21 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: phar_object.c,v 1.268 2008/05/14 21:27:31 sfox Exp $ */ +/* $Id: phar_object.c,v 1.269 2008/05/15 16:09:21 cellog Exp $ */ #include "phar_internal.h" #include "func_interceptors.h" @@ -327,7 +327,7 @@ phar_entry_data *phar; char *error; if (f404_len) { - if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, f404, f404_len, "r", 0, &error TSRMLS_CC)) { + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, f404, f404_len, "r", 0, &error, 1 TSRMLS_CC)) { if (error) { efree(error); } @@ -672,7 +672,7 @@ entry = estrndup("/index.php", sizeof("/index.php")); entry_len = sizeof("/index.php")-1; } - if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, NULL TSRMLS_CC)) { + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, NULL, 1 TSRMLS_CC)) { phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC); if (free_pathinfo) { efree(path_info); @@ -711,7 +711,7 @@ } } - if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, &error TSRMLS_CC)) { + if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, &error, 1 TSRMLS_CC)) { phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC); #ifdef PHP_WIN32 efree(fname); @@ -1503,12 +1503,31 @@ } after_open_fp: - if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error TSRMLS_CC))) { + if (str_key_len >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) { + /* silently skip any files that would be added to the magic .phar directory */ + if (save) { + efree(save); + } + if (temp) { + efree(temp); + } + if (opened) { + efree(opened); + } + if (close_fp) { + php_stream_close(fp); + } + return ZEND_HASH_APPLY_KEEP; + } + if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error, 1 TSRMLS_CC))) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error); efree(error); if (save) { efree(save); } + if (opened) { + efree(opened); + } if (temp) { efree(temp); } @@ -2992,6 +3011,20 @@ RETURN_FALSE; } + if (oldfile_len >= sizeof(".phar")-1 && !memcmp(oldfile, ".phar", sizeof(".phar")-1)) { + /* can't copy a meta file */ + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "file \"%s\" cannot be copied to file \"%s\", cannot copy Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + if (newfile_len >= sizeof(".phar")-1 && !memcmp(newfile, ".phar", sizeof(".phar")-1)) { + /* can't copy a meta file */ + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "file \"%s\" cannot be copied to file \"%s\", cannot copy to Phar meta-file in %s", oldfile, newfile, phar_obj->arc.archive->fname); + RETURN_FALSE; + } + if (!zend_hash_exists(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len) || SUCCESS != zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry) || oldentry->is_deleted) { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->arc.archive->fname); @@ -3077,6 +3110,11 @@ RETURN_FALSE; } } + + if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) { + /* none of these are real files, so they don't exist */ + RETURN_FALSE; + } RETURN_TRUE; } else { RETURN_FALSE; @@ -3098,10 +3136,26 @@ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) { return; } - - if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error TSRMLS_CC))) { + + /* security is 0 here so that we can get a better error message than "entry doesn't exist" */ + if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error, 0 TSRMLS_CC))) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:""); } else { + if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get stub \".phar/stub.php\" directly in phar \"%s\", use getStub", phar_obj->arc.archive->fname); + return; + } + + if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot get alias \".phar/alias.txt\" directly in phar \"%s\", use getAlias", phar_obj->arc.archive->fname); + return; + } + + if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot directly get any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname); + return; + } + if (entry->is_temp_dir) { efree(entry->filename); efree(entry); @@ -3125,7 +3179,12 @@ phar_entry_data *data; php_stream *contents_file; - if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, filename, filename_len, "w+b", 0, &error TSRMLS_CC))) { + if (filename_len >= sizeof(".phar")-1 && !memcmp(filename, ".phar", sizeof(".phar")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create any files in magic \".phar\" directory", phar->fname); + return; + } + + if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, filename, filename_len, "w+b", 0, &error, 1 TSRMLS_CC))) { if (error) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created: %s", filename, error); efree(error); @@ -3170,7 +3229,7 @@ char *error; phar_entry_data *data; - if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, dirname, dirname_len, "w+b", 2, &error TSRMLS_CC))) { + if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, dirname, dirname_len, "w+b", 2, &error, 1 TSRMLS_CC))) { if (error) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created: %s", dirname, error); efree(error); @@ -3213,15 +3272,20 @@ return; } - if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set stub \".phar/stub.php\" directly in phar \"%s\", use setStub", phar_obj->arc.archive->fname); return; } - if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set alias \".phar/alias.txt\" directly in phar \"%s\", use setAlias", phar_obj->arc.archive->fname); return; } + + if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set any files or directories in magic \".phar\" directory", phar_obj->arc.archive->fname); + return; + } phar_add_file(phar_obj->arc.archive, fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC); } /* }}} */ @@ -3280,6 +3344,10 @@ return; } + if (dirname_len >= sizeof(".phar")-1 && !memcmp(dirname, ".phar", sizeof(".phar")-1)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot create a directory in magic \".phar\" directory"); + return; + } phar_mkdir(phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC); } /* }}} */ @@ -3548,6 +3616,9 @@ /* silently ignore mounted entries */ return SUCCESS; } + if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) { + return SUCCESS; + } len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename); if (len >= MAXPATHLEN) { char *tmp; @@ -3834,7 +3905,7 @@ return; } - if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error TSRMLS_CC)) == NULL) { + if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error, 1 TSRMLS_CC)) == NULL) { zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error?", ":"", error?error:""); efree(arch); http://cvs.php.net/viewvc.cgi/php-src/ext/phar/stream.c?r1=1.29&r2=1.30&diff_format=u Index: php-src/ext/phar/stream.c diff -u php-src/ext/phar/stream.c:1.29 php-src/ext/phar/stream.c:1.30 --- php-src/ext/phar/stream.c:1.29 Wed May 14 21:27:31 2008 +++ php-src/ext/phar/stream.c Thu May 15 16:09:21 2008 @@ -178,7 +178,7 @@ /* strip leading "/" */ internal_file = estrdup(resource->path + 1); if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { - if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error TSRMLS_CC))) { + if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error, 1 TSRMLS_CC))) { if (error) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); efree(error); @@ -223,7 +223,8 @@ } return fpf; } else { - if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) || !idata) { + /* read-only access is allowed to magic files in .phar directory */ + if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error, 0 TSRMLS_CC)) || !idata) { if (error) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); efree(error); @@ -675,7 +676,7 @@ /* need to copy to strip leading "/", will get touched again */ internal_file = estrdup(resource->path + 1); - if (FAILURE == phar_get_entry_data(&idata, resource->host, strlen(resource->host), internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) { + if (FAILURE == phar_get_entry_data(&idata, resource->host, strlen(resource->host), internal_file, strlen(internal_file), "r", 0, &error, 1 TSRMLS_CC)) { /* constraints of fp refcount were not met */ if (error) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error); http://cvs.php.net/viewvc.cgi/php-src/ext/phar/util.c?r1=1.57&r2=1.58&diff_format=u Index: php-src/ext/phar/util.c diff -u php-src/ext/phar/util.c:1.57 php-src/ext/phar/util.c:1.58 --- php-src/ext/phar/util.c:1.57 Wed May 14 21:27:31 2008 +++ php-src/ext/phar/util.c Thu May 15 16:09:21 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: util.c,v 1.57 2008/05/14 21:27:31 sfox Exp $ */ +/* $Id: util.c,v 1.58 2008/05/15 16:09:21 cellog Exp $ */ #include "phar_internal.h" #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300 @@ -146,6 +146,11 @@ return FAILURE; } + if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) { + /* no creating magic phar files by mounting them */ + return FAILURE; + } + is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7)); entry.phar = phar; @@ -483,7 +488,7 @@ * appended, truncated, or read. For read, if the entry is marked unmodified, it is * assumed that the file pointer, if present, is opened for reading */ -int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC) /* {{{ */ +int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */ { phar_archive_data *phar; phar_entry_info *entry; @@ -515,14 +520,14 @@ return FAILURE; } if (allow_dir) { - if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) { + if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) { if (for_create && (!PHAR_G(readonly) || phar->is_data)) { return SUCCESS; } return FAILURE; } } else { - if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) { + if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) { if (for_create && (!PHAR_G(readonly) || phar->is_data)) { return SUCCESS; } @@ -608,7 +613,7 @@ /** * Create a new dummy file slot within a writeable phar for a newly created file */ -phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC) /* {{{ */ +phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */ { phar_archive_data *phar; phar_entry_info *entry, etemp; @@ -626,7 +631,7 @@ return NULL; } - if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error TSRMLS_CC)) { + if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) { return NULL; } else if (ret) { return ret; @@ -1118,9 +1123,9 @@ /** * retrieve information on a file contained within a phar, or null if it ain't there */ -phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC) /* {{{ */ +phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */ { - return phar_get_entry_info_dir(phar, path, path_len, 0, error TSRMLS_CC); + return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC); } /* }}} */ /** @@ -1128,7 +1133,7 @@ * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only * valid pre-existing empty directory entries */ -phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC) /* {{{ */ +phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC) /* {{{ */ { const char *pcr_error; phar_entry_info *entry; @@ -1144,6 +1149,12 @@ *error = NULL; } + if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) { + if (error) { + spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it"); + } + return NULL; + } if (!path_len && !dir) { if (error) { spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path); http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/phar_extract2.phpt?r1=1.1&r2=1.2&diff_format=u Index: php-src/ext/phar/tests/phar_extract2.phpt diff -u /dev/null php-src/ext/phar/tests/phar_extract2.phpt:1.2 --- /dev/null Thu May 15 16:09:21 2008 +++ php-src/ext/phar/tests/phar_extract2.phpt Thu May 15 16:09:21 2008 @@ -0,0 +1,60 @@ +--TEST-- +Phar: Phar::extractTo() - .phar safety +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--INI-- +phar.readonly=0 +--FILE-- +<?php + +$fname = dirname(__FILE__) . '/tempmanifest2.phar.php'; +$pname = 'phar://' . $fname; + +$phar = new Phar($fname); +$phar->setDefaultStub(); +$phar->setAlias('fred'); +$phar['file1.txt'] = 'hi'; +$phar['file2.txt'] = 'hi2'; +$phar['subdir/ectory/file.txt'] = 'hi3'; +$phar->mount($pname . '/mount', __FILE__); +$phar->addEmptyDir('one/level'); + +$phar->extractTo(dirname(__FILE__) . '/extract', 'mount'); +$phar->extractTo(dirname(__FILE__) . '/extract'); +$out = array(); + +foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(dirname(__FILE__) . '/extract'), RecursiveIteratorIterator::CHILD_FIRST) as $path => $file) { + $extracted[] = $path; +} + +sort($extracted); + +foreach ($extracted as $out) { + echo "$out\n"; +} + +?> +===DONE=== +--CLEAN-- +<?php [EMAIL PROTECTED](dirname(__FILE__) . '/tempmanifest2.phar.php'); +$dir = dirname(__FILE__) . '/extract/'; [EMAIL PROTECTED]($dir . 'file1.txt'); [EMAIL PROTECTED]($dir . 'file2.txt'); [EMAIL PROTECTED]($dir . 'subdir/ectory/file.txt'); [EMAIL PROTECTED]($dir . 'subdir/ectory'); [EMAIL PROTECTED]($dir . 'subdir'); [EMAIL PROTECTED]($dir . 'one/level'); [EMAIL PROTECTED]($dir . 'one'); [EMAIL PROTECTED]($dir); +$dir = dirname(__FILE__) . '/extract1/'; [EMAIL PROTECTED]($dir); +?> +--EXPECTF-- +%sextract%cfile1.txt +%sextract%cfile2.txt +%sextract%cone +%sextract%csubdir +%sextract%csubdir%cectory +%sextract%csubdir%cectory%cfile.txt +===DONE=== http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/phar_offset_check.phpt?r1=1.1&r2=1.2&diff_format=u Index: php-src/ext/phar/tests/phar_offset_check.phpt diff -u /dev/null php-src/ext/phar/tests/phar_offset_check.phpt:1.2 --- /dev/null Thu May 15 16:09:21 2008 +++ php-src/ext/phar/tests/phar_offset_check.phpt Thu May 15 16:09:21 2008 @@ -0,0 +1,78 @@ +--TEST-- +Phar: disallow stub and alias setting via offset*() methods +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +<?php if (!extension_loaded("spl")) die("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; + +$phar = new Phar($fname); +$phar->setDefaultStub(); +$phar->setAlias('susan'); +$phar['a.txt'] = "first file\n"; +$phar['b.txt'] = "second file\n"; + +try { + $phar->offsetGet('.phar/stub.php'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +try { + $phar->offsetGet('.phar/alias.txt'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +try { + $phar->offsetSet('.phar/stub.php', '<?php __HALT_COMPILER(); ?>'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +var_dump(strlen($phar->getStub())); + +try { + $phar->offsetUnset('.phar/stub.php'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +var_dump(strlen($phar->getStub())); + +try { + $phar->offsetSet('.phar/alias.txt', 'dolly'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +var_dump($phar->getAlias()); + +try { + $phar->offsetUnset('.phar/alias.txt'); +} catch (Exception $e) { + echo $e->getMessage()."\n"; +} + +var_dump($phar->getAlias()); + +?> +===DONE=== +--CLEAN-- +<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?> +--EXPECTF-- +Entry .phar/stub.php does not exist +Entry .phar/alias.txt does not exist +Cannot set stub ".phar/stub.php" directly in phar "%sphar_offset_check.phar.php", use setStub +int(6661) +int(6661) +Cannot set alias ".phar/alias.txt" directly in phar "%sphar_offset_check.phar.php", use setAlias +string(5) "susan" +string(5) "susan" +===DONE=== http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/030.phpt?r1=1.6&r2=1.7&diff_format=u Index: php-src/ext/phar/tests/030.phpt diff -u php-src/ext/phar/tests/030.phpt:1.6 php-src/ext/phar/tests/030.phpt:1.7 --- php-src/ext/phar/tests/030.phpt:1.6 Wed Feb 20 13:11:38 2008 +++ php-src/ext/phar/tests/030.phpt Thu May 15 16:09:21 2008 @@ -11,11 +11,12 @@ $file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>'; $files = array(); -$files['a.php'] = '<?php echo "This is a\n"; include \''.$pname.'/b.php\'; ?>'; -$files['b.php'] = '<?php echo "This is b\n"; include \''.$pname.'/b/c.php\'; ?>'; -$files['b/c.php'] = '<?php echo "This is b/c\n"; include \''.$pname.'/b/d.php\'; ?>'; -$files['b/d.php'] = '<?php echo "This is b/d\n"; include \''.$pname.'/e.php\'; ?>'; -$files['e.php'] = '<?php echo "This is e\n"; ?>'; +$files['a.php'] = '<?php echo "This is a\n"; include \''.$pname.'/b.php\'; ?>'; +$files['b.php'] = '<?php echo "This is b\n"; include \''.$pname.'/b/c.php\'; ?>'; +$files['b/c.php'] = '<?php echo "This is b/c\n"; include \''.$pname.'/b/d.php\'; ?>'; +$files['b/d.php'] = '<?php echo "This is b/d\n"; include \''.$pname.'/e.php\'; ?>'; +$files['e.php'] = '<?php echo "This is e\n"; ?>'; +$files['.phar/test'] = '<?php bad boy ?>'; include 'files/phar_test.inc'; @@ -23,6 +24,13 @@ require $pname . '/a.php'; +$p = new Phar($fname); +var_dump(isset($p['.phar/test'])); +try { +$p['.phar/test']; +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} ?> ===DONE=== --CLEAN-- @@ -35,4 +43,6 @@ This is b/c This is b/d This is e +bool(false) +Cannot directly get any files or directories in magic ".phar" directory ===DONE=== http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/addfuncs.phpt?r1=1.2&r2=1.3&diff_format=u Index: php-src/ext/phar/tests/addfuncs.phpt diff -u php-src/ext/phar/tests/addfuncs.phpt:1.2 php-src/ext/phar/tests/addfuncs.phpt:1.3 --- php-src/ext/phar/tests/addfuncs.phpt:1.2 Thu Apr 24 05:00:02 2008 +++ php-src/ext/phar/tests/addfuncs.phpt Thu May 15 16:09:21 2008 @@ -28,6 +28,16 @@ } catch (Exception $e) { echo $e->getMessage() . "\n"; } +try { +$phar->addFile($pname . '/a', '.phar/stub.php'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +try { +$phar->addFromString('.phar/stub.php', 'hi'); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} ?> ===DONE=== --CLEAN-- @@ -38,4 +48,6 @@ Entry phar://%saddfuncs.phar.php/a does not exist and cannot be created: phar error: invalid path "phar://%saddfuncs.phar.php/a" contains double slash Entry a does not exist and cannot be created: phar error: file "a" in phar "%saddfuncs.phar.php" cannot be opened for writing, readable file pointers are open phar error: unable to open file "%s/does/not/exist" to add to phar archive +Cannot create any files in magic ".phar" directory +Cannot create any files in magic ".phar" directory ===DONE=== \ No newline at end of file http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/mkdir.phpt?r1=1.4&r2=1.5&diff_format=u Index: php-src/ext/phar/tests/mkdir.phpt diff -u php-src/ext/phar/tests/mkdir.phpt:1.4 php-src/ext/phar/tests/mkdir.phpt:1.5 --- php-src/ext/phar/tests/mkdir.phpt:1.4 Mon May 12 00:43:10 2008 +++ php-src/ext/phar/tests/mkdir.phpt Thu May 15 16:09:21 2008 @@ -19,6 +19,11 @@ rmdir($pname . '/a'); $a->addEmptyDir('bb'); $a->addEmptyDir('bb'); +try { +$a->addEmptyDir('.phar'); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} ?> ===DONE=== --CLEAN-- @@ -38,4 +43,5 @@ Warning: rmdir(): phar error: cannot remove directory "" in phar "foo.phar", directory does not exist in %smkdir.php on line %d Warning: rmdir(): phar error: cannot remove directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d +Cannot create a directory in magic ".phar" directory ===DONE=== \ No newline at end of file http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/mounteddir.phpt?r1=1.5&r2=1.6&diff_format=u Index: php-src/ext/phar/tests/mounteddir.phpt diff -u php-src/ext/phar/tests/mounteddir.phpt:1.5 php-src/ext/phar/tests/mounteddir.phpt:1.6 --- php-src/ext/phar/tests/mounteddir.phpt:1.5 Sat Apr 26 05:28:55 2008 +++ php-src/ext/phar/tests/mounteddir.phpt Thu May 15 16:09:21 2008 @@ -17,6 +17,11 @@ echo file_get_contents(Phar::running(1) . "/testit/existing.txt"), "\n"; include "testit/extfile.php"; include "testit/extfile2.php"; +try { +Phar::mount(".phar/stub.php", dirname(Phar::running(0)) . "/testit/extfile.php"); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} ?>'; $a['testit/existing.txt'] = 'oops'; $a->setStub('<?php @@ -94,6 +99,7 @@ oops string(%d) "phar://%sextfile.php" string(%d) "phar://%sextfile2.php" +Mounting of .phar/stub.php to %sextfile.php within phar %stests/tempmanifest1.phar.php failed . .. directory http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/phar_buildfromiterator4.phpt?r1=1.4&r2=1.5&diff_format=u Index: php-src/ext/phar/tests/phar_buildfromiterator4.phpt diff -u php-src/ext/phar/tests/phar_buildfromiterator4.phpt:1.4 php-src/ext/phar/tests/phar_buildfromiterator4.phpt:1.5 --- php-src/ext/phar/tests/phar_buildfromiterator4.phpt:1.4 Fri Jan 4 16:26:43 2008 +++ php-src/ext/phar/tests/phar_buildfromiterator4.phpt Thu May 15 16:09:21 2008 @@ -38,7 +38,14 @@ try { chdir(dirname(__FILE__)); $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar'); - var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt')))); + var_dump($phar->buildFromIterator(new myIterator( + array( + 'a' => basename(__FILE__, 'php') . 'phpt', + // demonstrate that none of these are added + '.phar/stub.php' => basename(__FILE__, 'php') . 'phpt', + '.phar/alias.txt' => basename(__FILE__, 'php') . 'phpt', + '.phar/oops' => basename(__FILE__, 'php') . 'phpt', + )))); } catch (Exception $e) { var_dump(get_class($e)); echo $e->getMessage() . "\n"; @@ -57,6 +64,18 @@ key next valid +current +key +next +valid +current +key +next +valid +current +key +next +valid array(1) { ["a"]=> string(%d) "%sphar_buildfromiterator4.phpt" http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/phar_copy.phpt?r1=1.6&r2=1.7&diff_format=u Index: php-src/ext/phar/tests/phar_copy.phpt diff -u php-src/ext/phar/tests/phar_copy.phpt:1.6 php-src/ext/phar/tests/phar_copy.phpt:1.7 --- php-src/ext/phar/tests/phar_copy.phpt:1.6 Thu Apr 24 04:14:04 2008 +++ php-src/ext/phar/tests/phar_copy.phpt Thu May 15 16:09:21 2008 @@ -57,6 +57,16 @@ $p2['a']->compress(Phar::GZ); $p2->copy('a', 'd'); echo $p2['d']->getContent() . "\n"; +try { +$p2->copy('d', '.phar/stub.php'); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +try { +$p2->copy('.phar/stub.php', 'd'); +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} ?> ===DONE=== --CLEAN-- @@ -69,4 +79,6 @@ file "notexisting" cannot be copied to file "another", file does not exist in %sphar_copy2.phar.php file "a" cannot be copied to file "b", file must not already exist in phar %sphar_copy2.phar.php hi +file "d" cannot be copied to file ".phar/stub.php", cannot copy to Phar meta-file in %sphar_copy2.phar.php +file ".phar/stub.php" cannot be copied to file "d", cannot copy Phar meta-file in %sphar_copy2.phar.php ===DONE=== \ No newline at end of file http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/phar_offset_get_error.phpt?r1=1.4&r2=1.5&diff_format=u Index: php-src/ext/phar/tests/phar_offset_get_error.phpt diff -u php-src/ext/phar/tests/phar_offset_get_error.phpt:1.4 php-src/ext/phar/tests/phar_offset_get_error.phpt:1.5 --- php-src/ext/phar/tests/phar_offset_get_error.phpt:1.4 Wed Jan 9 00:58:36 2008 +++ php-src/ext/phar/tests/phar_offset_get_error.phpt Thu May 15 16:09:21 2008 @@ -27,6 +27,18 @@ } include($pname . $iname); + +// extra coverage +try { +$p['.phar/oops'] = 'hi'; +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} +try { +$a = $p['.phar/stub.php']; +} catch (Exception $e) { +echo $e->getMessage(),"\n"; +} ?> ===DONE=== --CLEAN-- @@ -34,4 +46,6 @@ --EXPECT-- Entry /error/.. does not exist and cannot be created: phar error: invalid path "/error/.." contains upper directory reference foobar +Cannot set any files or directories in magic ".phar" directory +Entry .phar/stub.php does not exist ===DONE=== http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/zf_test.phpt?r1=1.11&r2=1.12&diff_format=u Index: php-src/ext/phar/tests/zf_test.phpt diff -u php-src/ext/phar/tests/zf_test.phpt:1.11 php-src/ext/phar/tests/zf_test.phpt:1.12 --- php-src/ext/phar/tests/zf_test.phpt:1.11 Tue May 13 14:49:36 2008 +++ php-src/ext/phar/tests/zf_test.phpt Thu May 15 16:09:21 2008 @@ -40,7 +40,6 @@ unlink(dirname(__FILE__) . '/zfapp.phar.tar.gz'); ?> --EXPECTF-- -phar://%szfapp.phar.tar.gz/.phar/stub.php phar://%szfapp.phar.tar.gz/application/default/controllers/ErrorController.php phar://%szfapp.phar.tar.gz/application/default/controllers/IndexController.php phar://%szfapp.phar.tar.gz/application/default/views/scripts/error/error.phtml http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/tar/dir.phpt?r1=1.3&r2=1.4&diff_format=u Index: php-src/ext/phar/tests/tar/dir.phpt diff -u php-src/ext/phar/tests/tar/dir.phpt:1.3 php-src/ext/phar/tests/tar/dir.phpt:1.4 --- php-src/ext/phar/tests/tar/dir.phpt:1.3 Fri May 2 05:05:54 2008 +++ php-src/ext/phar/tests/tar/dir.phpt Thu May 15 16:09:21 2008 @@ -17,6 +17,7 @@ var_dump($phar->isFileFormat(Phar::TAR)); $phar->addEmptyDir('test'); +var_dump(isset($phar['.phar/stub.php'])); var_dump($phar['test']->isDir()); var_dump($phar['test/']->isDir()); copy($fname, $fname2); @@ -35,6 +36,7 @@ <?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?> --EXPECT-- bool(true) +bool(false) bool(true) bool(true) bool(true) http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/tar/tar_003.phpt?r1=1.5&r2=1.6&diff_format=u Index: php-src/ext/phar/tests/tar/tar_003.phpt diff -u php-src/ext/phar/tests/tar/tar_003.phpt:1.5 php-src/ext/phar/tests/tar/tar_003.phpt:1.6 --- php-src/ext/phar/tests/tar/tar_003.phpt:1.5 Mon Mar 3 08:41:14 2008 +++ php-src/ext/phar/tests/tar/tar_003.phpt Thu May 15 16:09:21 2008 @@ -55,8 +55,6 @@ --EXPECT-- hi there! dir -.phar -dir dir dir internal @@ -64,8 +62,6 @@ tar_003.phpt second round dir -.phar -dir dir dir internal
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php