N°2154 - fix server crash in rare cases

Under undetermined circumstances, `exec('php -v')` called the current script triggering an infinite loop crashing the server
problem reported by @molkobain
see: https://stackoverflow.com/questions/43728378/running-php-files-through-shell-exec
This commit is contained in:
bruno DA SILVA
2020-02-19 15:42:59 +01:00
parent d76e54996c
commit 27a0de1da1
3 changed files with 17 additions and 83 deletions

View File

@@ -9,83 +9,13 @@ namespace Combodo\iTop\Config\Validator;
class iTopConfigSyntaxValidator
{
/**
* validate
*
* @param $sConfig
* @param $bAllowUnsecure
*/
public function Validate($sConfig, $bAllowUnsecure)
{
exec('php -v', $aOutput, $iReturnVar);
$bCanRunCli = ($iReturnVar == 0);
if (!isset($aOutput[0]))
{
$bCanRunCli = false;
}
if ($bCanRunCli)
{
if (!preg_match('/\s*PHP\s+(\d+\.\d+\.\d+)/', $aOutput[0], $aMatches))
{
$bCanRunCli = false;
}
else
{
require_once(APPROOT.'setup/setuputils.class.inc.php');
$sCliPhpVersion = $aMatches[1];
if (version_compare($sCliPhpVersion, \SetupUtils::PHP_MIN_VERSION, '<'))
{
$bCanRunCli = false;
}
}
}
if ($bCanRunCli)
{
$this->CheckSyntaxSecure($sConfig);
}
elseif($bAllowUnsecure)
{
$this->CheckSyntaxNotSecure($sConfig);
}
else
{
throw new \Exception('Cannot check configuration syntax: PHP CLI is not accessible.'."\n".implode("\n", $aOutput));
}
}
/**
* This will use the php cli linter in order to check the syntax,
*
* The php cli may not be based on the same php version, but since the cron run using the cli, we can assume that it is well configured anyway...
* Also, the config syntax is very limited so there should not be a problem with checking the validity against another php version
*
* @param $sConfig
* @param $iReturnVar
* @param $aOutput
*
* @return array
*/
private function CheckSyntaxSecure($sConfig)
{
$sTempFile = tempnam(sys_get_temp_dir(), 'syntax_check_me_').'.temp.txt';
file_put_contents($sTempFile, $sConfig);
exec("php -l $sTempFile 2>&1", $aOutput, $iReturnVar);
unlink($sTempFile);
if ($iReturnVar != 0)
{
throw new \Exception(implode("\n", $aOutput));
}
}
/**
* @param $sRawConfig
*
* @throws \Exception
*/
private function CheckSyntaxNotSecure($sRawConfig)
public function Validate($sRawConfig)
{
try
{
@@ -96,26 +26,30 @@ class iTopConfigSyntaxValidator
$sConfig = preg_replace(array('#^\s*<\?php#', '#\?>\s*$#'), '', $sRawConfig);
eval('if(0){'.trim($sConfig).'}');
$sNoise = trim(ob_get_contents());
ob_end_clean();
}
catch (Error $e)
catch (\Error $e)
{
// ParseError only thrown in PHP7
throw new Exception('Error in configuration: '.$e->getMessage().' at line '.$e->getLine());
throw new \Exception('Error in configuration: '.$e->getMessage().' at line '.$e->getLine());
}
finally
{
ob_end_clean();
}
if (strlen($sNoise) > 0)
{
if (preg_match("/(Error|Parse error|Notice|Warning): (.+) in \S+ : eval\(\)'d code on line (\d+)/i", strip_tags($sNoise), $aMatches))
{
$sMessage = $aMatches[2];
$sLine = $aMatches[3];
$sMessage = Dict::Format('config-parse-error', $sMessage, $sLine);
throw new Exception($sMessage);
$sMessage = \Dict::Format('config-parse-error', $sMessage, $sLine);
throw new \Exception($sMessage);
}
else
{
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
throw new Exception('Syntax error in configuration file: <tt>'.$sNoise.'</tt>');
throw new \Exception('Syntax error in configuration file: <tt>'.$sNoise.'</tt>');
}
}
}