phar_find_in_include_path. We were allowing data-based phars to be executed, and actually marking phar-based phar archives
without '.phar' in the name as data-based phars, which would allow modifying them even if phar.readonly=0. Add test for this sinister case
export PATH_TRANSLATED=/home/cellog/workspace/php5/ext/phar/tests/frontcontroller34.php
export REDIRECT_STATUS=1
export REQUEST_METHOD=GET
-export REQUEST_URI=/frontcontroller29.php/fatalerror.phps
+export REQUEST_URI=/frontcontroller34.php/start/index.php
cd /home/cellog/workspace/php5/
ddd sapi/cgi/php-cgi &
cd /home/cellog/workspace/php5/ext/phar
if (!is_data) {
/* prevent any ".phar" without a stub getting through */
- if (!phar->halt_offset && !phar->is_brandnew) {
+ if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
if (error) {
spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
}
}
}
- phar->is_data = is_data;
+ phar->is_data = is_data && (phar->is_tar || phar->is_zip);
if (pphar) {
*pphar = phar;
}
{
const char *ext_str, *z;
int ext_len;
+ phar_archive_data **test, *unused = NULL;
+ test = &unused;
if (error) {
*error = NULL;
}
}
check_file:
- if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, pphar, 0 TSRMLS_CC) == SUCCESS) {
- if (is_data && !((*pphar)->is_tar || (*pphar)->is_zip)) {
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, test, 0 TSRMLS_CC) == SUCCESS) {
+ if (pphar) {
+ *pphar = *test;
+ }
+ if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
if (error) {
spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
}
+ return FAILURE;
}
- if (PHAR_G(readonly) && !is_data && ((*pphar)->is_tar || (*pphar)->is_zip)) {
+ if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
phar_entry_info *stub;
- if (FAILURE == zend_hash_find(&((*pphar)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
+ if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
return FAILURE;
}
}
- if (pphar && (!PHAR_G(readonly) || is_data)) {
- (*pphar)->is_writeable = 1;
+ if (!PHAR_G(readonly) || (*test)->is_data) {
+ (*test)->is_writeable = 1;
}
return SUCCESS;
}
if (fp) {
if (phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) {
- if (is_data || !PHAR_G(readonly)) {
+ if ((*pphar)->is_data || !PHAR_G(readonly)) {
(*pphar)->is_writeable = 1;
}
if (actual) {
phar_request_initialize(TSRMLS_C);
/* first check for alias in first segment */
pos = strchr(filename, '/');
- if (pos) {
+ if (pos && pos != filename) {
if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
*ext_str = pos;
*ext_len = -1;
long halt_offset;
zval *halt_constant;
php_stream *fp;
- int fname_len, is_data = 0;
+ int fname_len;
if (error) {
*error = NULL;
fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname);
- if (!strstr(fname, ".phar")) {
- is_data = 1;
- }
-
- if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
return SUCCESS;
}
--- /dev/null
+--TEST--
+Phar: test to ensure phar.readonly cannot be circumvented
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.php';
+$a = new Phar($fname);
+$a->setStub('<?php
+Phar::mapPhar();
+$phar = new Phar(__FILE__);
+var_dump($phar->isWritable());
+try {
+$phar["b"] = "should not work!";
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+__HALT_COMPILER();
+?>');
+$a['hi'] = 'hi';
+unset($a);
+copy($fname, $fname2);
+Phar::unlinkArchive($fname);
+ini_set('phar.readonly', 1);
+include $fname2;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.php'); ?>
+--EXPECT--
+bool(false)
+Write operations disabled by INI setting
+===DONE===
\ No newline at end of file
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
fname = zend_get_executed_filename(TSRMLS_C);
- if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
+ if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
if (*filename == '.') {
ret_len = strlen(ret);
/* found phar:// */
- if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
+ if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return ret;
}
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
goto doit;
}
fname = zend_get_executed_filename(TSRMLS_C);
- if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
+ if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
goto doit;
}
ret_len = strlen(trypath);
/* found phar:// */
- if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 0, 0 TSRMLS_CC)) {
+ if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
return estrndup(trypath, ret_len);
}
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);