diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 88b89e01ea8..954a87ff4d8 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -4912,7 +4912,7 @@ function dol_user_country() */ function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '') { - global $conf, $user, $langs, $hookmanager; + global $hookmanager; $out = ''; @@ -10846,6 +10846,29 @@ function verifCond($strToEvaluate, $onlysimplestring = '1') * This function is called by verifCond() or trans() and transnoentitiesnoconv(). * * @param string $s String to evaluate + * @param int<0,1> $returnvalue 0=No return (deprecated, used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). + * @param int<0,1> $hideerrors 1=Hide errors + * @param string $onlysimplestring '0' (deprecated, do not use it anymore)=Accept all chars, + * '1' (most common use)=Accept only simple string with char 'a-z0-9\s^$_+-.*>&|=!?():"\',/@';', + * '2' (used for example for the compute property of extrafields)=Accept also '<[]' + * @return void|string Nothing or return result of eval (even if type can be int, it is safer to assume string and find all potential typing issues as abs(dol_eval(...)). + * @see verifCond(), checkPHPCode() to see sanitizing rules that should be very close. + * @phan-suppress PhanPluginUnsafeEval + */ +function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1') +{ + if (getDolGlobalString("MAIN_USE_DOL_EVAL_NEW")) { + return dol_eval_new($s); + } else { + return dol_eval_old($s, $returnvalue, $hideerrors, $onlysimplestring); + } +} + +/** + * Replace eval function to add more security. + * This function is called by dol_eval(), itself called by verifCond() or trans() and transnoentitiesnoconv(). + * + * @param string $s String to evaluate * @return void|string Nothing or return result of eval (even if type can be int, it is safer to assume string and find all potential typing issues as abs(dol_eval(...)). * @see verifCond(), checkPHPCode() to see sanitizing rules that should be very close. * @phan-suppress PhanPluginUnsafeEval @@ -11022,13 +11045,13 @@ function dol_eval_new($s) try { return @eval("return {$s};") ?? ''; } catch (Throwable $ex) { - return "Evaluation Error: {$ex->getMessage()} in {$s}"; + return "Exception during evaluation: ".$s." - ".$ex->getMessage(); } } /** * Replace eval function to add more security. - * This function is called by verifCond() or trans() and transnoentitiesnoconv(). + * This function is called by dol_eval(), itself called by verifCond() or trans() and transnoentitiesnoconv(). * * @param string $s String to evaluate * @param int<0,1> $returnvalue 0=No return (deprecated, used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)). @@ -11040,7 +11063,7 @@ function dol_eval_new($s) * @see verifCond(), checkPHPCode() to see sanitizing rules that should be very close. * @phan-suppress PhanPluginUnsafeEval */ -function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1') +function dol_eval_old($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1') { // Only this global variables can be read by eval function and returned to caller global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 3716f702fc0..d0addf4f6cd 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -604,9 +604,8 @@ class SecurityTest extends CommonClassTest include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - $result = dol_eval('1==\x01', 1, 0); // Check that we can't make dol_eval on string containing \ char. - print "result0 = ".$result."\n"; - $this->assertStringContainsString('Bad string syntax to evaluate', $result); + $conf->global->MAIN_USE_DOL_EVAL_NEW = 0; + //$conf->global->MAIN_USE_DOL_EVAL_NEW = 1; $result = dol_eval('1==1', 1, 0); print "result1 = ".$result."\n"; @@ -619,7 +618,7 @@ class SecurityTest extends CommonClassTest $s = '((($reloadedobj = new ClassThatDoesNotExists($db)) && ($reloadedobj->fetchNoCompute($objectoffield->fk_product) > 0)) ? \'1\' : \'0\')'; $result3a = dol_eval($s, 1, 1, '2'); print "result3a = ".$result3a."\n"; - $this->assertEquals('Exception during evaluation: '.$s, $result3a); + $this->assertStringContainsString('Exception during evaluation: '.$s, $result3a); $s = '((($reloadedobj = new Project($db)) && ($reloadedobj->fetchNoCompute($objectoffield->fk_product) > 0)) ? \'1\' : \'0\')'; $result3b = dol_eval($s, 1, 1, '2'); @@ -636,6 +635,10 @@ class SecurityTest extends CommonClassTest print "result4 = ".$result."\n"; $this->assertEquals('Parent project not found', $result, 'Test 4'); + $result = dol_eval('1==\x01', 1, 0); // Check that we can't make dol_eval on string containing \ char. + print "result0 = ".$result."\n"; + $this->assertStringContainsString('Bad string syntax to evaluate', $result); + $s = '4 < 5'; $result = (string) dol_eval($s, 1, 1, '2'); print "result5 = ".$result."\n";