mirror of
https://github.com/smarty-php/smarty.git
synced 2026-08-10 07:21:31 +02:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e05dabf369 | ||
|
|
1eb2851c03 | ||
|
|
a832410ef3 | ||
|
|
e27da524f7 | ||
|
|
a21f59663c | ||
|
|
3148d406a0 | ||
|
|
4f634c0097 | ||
|
|
c9272058d9 | ||
|
|
e66e293a8a | ||
|
|
74cab5a56b | ||
|
|
8fc66e27a7 | ||
|
|
2543174460 | ||
|
|
288a54f6b0 | ||
|
|
165f1bd4d2 | ||
|
|
6463519a6c |
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [3.1.39] - 2021-02-17
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Prevent access to `$smarty.template_object` in sandbox mode
|
||||||
|
- Fixed code injection vulnerability by using illegal function names in `{function name='blah'}{/function}`
|
||||||
|
|
||||||
## [3.1.38] - 2021-01-08
|
## [3.1.38] - 2021-01-08
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
/**
|
/**
|
||||||
* smarty version
|
* smarty version
|
||||||
*/
|
*/
|
||||||
const SMARTY_VERSION = '3.1.38';
|
const SMARTY_VERSION = '3.1.39';
|
||||||
/**
|
/**
|
||||||
* define variable scopes
|
* define variable scopes
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase
|
|||||||
}
|
}
|
||||||
unset($_attr[ 'nocache' ]);
|
unset($_attr[ 'nocache' ]);
|
||||||
$_name = trim($_attr[ 'name' ], '\'"');
|
$_name = trim($_attr[ 'name' ], '\'"');
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_\x80-\xff]+$/', $_name)) {
|
||||||
|
$compiler->trigger_template_error("Function name contains invalid characters: {$_name}", null, true);
|
||||||
|
}
|
||||||
|
|
||||||
$compiler->parent_compiler->tpl_function[ $_name ] = array();
|
$compiler->parent_compiler->tpl_function[ $_name ] = array();
|
||||||
$save = array(
|
$save = array(
|
||||||
$_attr, $compiler->parser->current_buffer, $compiler->template->compiled->has_nocache_code,
|
$_attr, $compiler->parser->current_buffer, $compiler->template->compiled->has_nocache_code,
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
|
|||||||
case 'template':
|
case 'template':
|
||||||
return 'basename($_smarty_tpl->source->filepath)';
|
return 'basename($_smarty_tpl->source->filepath)';
|
||||||
case 'template_object':
|
case 'template_object':
|
||||||
|
if (isset($compiler->smarty->security_policy)) {
|
||||||
|
$compiler->trigger_template_error("(secure mode) template_object not permitted");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return '$_smarty_tpl';
|
return '$_smarty_tpl';
|
||||||
case 'current_dir':
|
case 'current_dir':
|
||||||
return 'dirname($_smarty_tpl->source->filepath)';
|
return 'dirname($_smarty_tpl->source->filepath)';
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
$source->filepath . ($source->isConfig ? $source->smarty->_joined_config_dir :
|
$source->filepath . ($source->isConfig ? $source->smarty->_joined_config_dir :
|
||||||
$source->smarty->_joined_template_dir)
|
$source->smarty->_joined_template_dir)
|
||||||
);
|
);
|
||||||
$source->timestamp = filemtime($source->filepath);
|
// When not doing compile_check, set timestamp to true
|
||||||
|
$source->timestamp = $source->smarty->compile_check ? filemtime($source->filepath) : true;
|
||||||
} else {
|
} else {
|
||||||
$source->timestamp = $source->exists = false;
|
$source->timestamp = $source->exists = false;
|
||||||
}
|
}
|
||||||
@@ -50,6 +51,10 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
*/
|
*/
|
||||||
public function populateTimestamp(Smarty_Template_Source $source)
|
public function populateTimestamp(Smarty_Template_Source $source)
|
||||||
{
|
{
|
||||||
|
if (!$source->smarty->compile_check) {
|
||||||
|
$source->timestamp = $source->exists = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!$source->exists) {
|
if (!$source->exists) {
|
||||||
$source->timestamp = $source->exists = is_file($source->filepath);
|
$source->timestamp = $source->exists = is_file($source->filepath);
|
||||||
}
|
}
|
||||||
@@ -68,13 +73,15 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
*/
|
*/
|
||||||
public function getContent(Smarty_Template_Source $source)
|
public function getContent(Smarty_Template_Source $source)
|
||||||
{
|
{
|
||||||
if ($source->exists) {
|
if (($source->smarty->compile_check && !$source->exists)
|
||||||
return file_get_contents($source->filepath);
|
|| false === ($content = file_get_contents($source->filepath))
|
||||||
|
) {
|
||||||
|
throw new SmartyException(
|
||||||
|
'Unable to read ' . ($source->isConfig ? 'config' : 'template') .
|
||||||
|
" {$source->type} '{$source->name}'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
throw new SmartyException(
|
return $content;
|
||||||
'Unable to read ' . ($source->isConfig ? 'config' : 'template') .
|
|
||||||
" {$source->type} '{$source->name}'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,6 +133,17 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
$file = str_replace(DIRECTORY_SEPARATOR === '/' ? '\\' : '/', DIRECTORY_SEPARATOR, $file);
|
$file = str_replace(DIRECTORY_SEPARATOR === '/' ? '\\' : '/', DIRECTORY_SEPARATOR, $file);
|
||||||
}
|
}
|
||||||
$_directories = $source->smarty->getTemplateDir(null, $source->isConfig);
|
$_directories = $source->smarty->getTemplateDir(null, $source->isConfig);
|
||||||
|
|
||||||
|
// If possible, assume the file exists when compile_check = false;
|
||||||
|
if (!$source->smarty->compile_check
|
||||||
|
&& count($_directories) == 1 // if there are multiple directories, we'll have to scan them
|
||||||
|
&& $file[ 0 ] !== '[' // template_dir index
|
||||||
|
&& !$source->smarty->use_include_path // cannot optimize when we need to use include path
|
||||||
|
) {
|
||||||
|
$path = reset($_directories) . $file;
|
||||||
|
return (strpos($path, '.' . DIRECTORY_SEPARATOR) !== false) ? $source->smarty->_realpath($path) : $path;
|
||||||
|
}
|
||||||
|
|
||||||
// template_dir index?
|
// template_dir index?
|
||||||
if ($file[ 0 ] === '[' && preg_match('#^\[([^\]]+)\](.+)$#', $file, $fileMatch)) {
|
if ($file[ 0 ] === '[' && preg_match('#^\[([^\]]+)\](.+)$#', $file, $fileMatch)) {
|
||||||
$file = $fileMatch[ 2 ];
|
$file = $fileMatch[ 2 ];
|
||||||
@@ -157,6 +175,7 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
$_directories = $_index_dirs;
|
$_directories = $_index_dirs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// relative file name?
|
// relative file name?
|
||||||
foreach ($_directories as $_directory) {
|
foreach ($_directories as $_directory) {
|
||||||
$path = $_directory . $file;
|
$path = $_directory . $file;
|
||||||
|
|||||||
@@ -74,9 +74,14 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
|
|||||||
$this->filepath .= '.cache';
|
$this->filepath .= '.cache';
|
||||||
}
|
}
|
||||||
$this->filepath .= '.php';
|
$this->filepath .= '.php';
|
||||||
$this->timestamp = $this->exists = is_file($this->filepath);
|
|
||||||
if ($this->exists) {
|
if ($smarty->compile_check) {
|
||||||
$this->timestamp = filemtime($this->filepath);
|
$this->timestamp = $this->exists = is_file($this->filepath);
|
||||||
|
if ($this->exists) {
|
||||||
|
$this->timestamp = filemtime($this->filepath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->timestamp = $this->exists = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,8 +140,9 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
|
|||||||
if ($source->handler->recompiled) {
|
if ($source->handler->recompiled) {
|
||||||
$source->handler->process($_smarty_tpl);
|
$source->handler->process($_smarty_tpl);
|
||||||
} elseif (!$source->handler->uncompiled) {
|
} elseif (!$source->handler->uncompiled) {
|
||||||
if (!$this->exists || $smarty->force_compile
|
if (
|
||||||
|| ($_smarty_tpl->compile_check && $source->getTimeStamp() > $this->getTimeStamp())
|
$smarty->force_compile ||
|
||||||
|
($_smarty_tpl->compile_check && (!$this->exists || ($source->getTimeStamp() > $this->getTimeStamp())))
|
||||||
) {
|
) {
|
||||||
$this->compileTemplateSource($_smarty_tpl);
|
$this->compileTemplateSource($_smarty_tpl);
|
||||||
$compileCheck = $_smarty_tpl->compile_check;
|
$compileCheck = $_smarty_tpl->compile_check;
|
||||||
|
|||||||
+1
-1
@@ -14,6 +14,6 @@ git pull
|
|||||||
git merge --no-ff "release/$1"
|
git merge --no-ff "release/$1"
|
||||||
git branch -d "release/$1"
|
git branch -d "release/$1"
|
||||||
git tag -a "v$1" -m "Release $1"
|
git tag -a "v$1" -m "Release $1"
|
||||||
git push --follow-tags
|
|
||||||
|
|
||||||
printf 'Done creating release %s\n' "$1"
|
printf 'Done creating release %s\n' "$1"
|
||||||
|
printf 'Run `git push --follow-tags origin` to publish it.\n'
|
||||||
|
|||||||
@@ -382,6 +382,15 @@ class SecurityTest extends PHPUnit_Smarty
|
|||||||
$this->smarty->security_policy->trusted_uri = array();
|
$this->smarty->security_policy->trusted_uri = array();
|
||||||
$this->assertContains('<title>Preface | Smarty</title>', $this->smarty->fetch('string:{fetch file="https://www.smarty.net/docs/en/preface.tpl"}'));
|
$this->assertContains('<title>Preface | Smarty</title>', $this->smarty->fetch('string:{fetch file="https://www.smarty.net/docs/en/preface.tpl"}'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In security mode, accessing $smarty.template_object should be illegal.
|
||||||
|
* @expectedException SmartyCompilerException
|
||||||
|
*/
|
||||||
|
public function testSmartyTemplateObject() {
|
||||||
|
$this->smarty->display('string:{$smarty.template_object}');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class mysecuritystaticclass
|
class mysecuritystaticclass
|
||||||
|
|||||||
@@ -431,5 +431,14 @@ class CompileFunctionTest extends PHPUnit_Smarty
|
|||||||
array("{function name=simple}A{\$foo}\nC{/function}{call name='simple'}", "Abar\nC", 'T14', $i++),
|
array("{function name=simple}A{\$foo}\nC{/function}{call name='simple'}", "Abar\nC", 'T14', $i++),
|
||||||
array("{function name=simple}A\n{\$foo}\nC{/function}{call name='simple'}", "A\nbar\nC", 'T15', $i++),
|
array("{function name=simple}A\n{\$foo}\nC{/function}{call name='simple'}", "A\nbar\nC", 'T15', $i++),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test handling of function names that are a security risk
|
||||||
|
* @expectedException SmartyCompilerException
|
||||||
|
*/
|
||||||
|
public function testIllegalFunctionName() {
|
||||||
|
$this->smarty->fetch('string:{function name=\'rce(){};echo "hi";function \'}{/function}');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user