diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 1fe4661236e..c0ecd6acefc 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -9641,18 +9641,23 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' return ''; } } - $scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $s); // accept parenthesis in '...->method(...' - $scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions - $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions - $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function(' - $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function(' - $scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)') + $savescheck = ''; + $scheck = $s; + while ($scheck && $savescheck != $scheck) { + $savescheck = $scheck; + $scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...' + $scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions + $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions + $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function(' + $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function(' + $scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)') + } //print 'scheck='.$scheck." : ".strpos($scheck, '(')."
\n"; if (strpos($scheck, '(') !== false) { if ($returnvalue) { - return 'Bad string syntax to evaluate (found call of a function or method without using direct name): '.$s; + return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s; } else { - dol_syslog('Bad string syntax to evaluate (found call of a function or method without using direct name): '.$s); + dol_syslog('Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s); return ''; } } @@ -9672,18 +9677,23 @@ function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1' return ''; } } - $scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $s); // accept parenthesis in '...->method(...' - $scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions - $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions - $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function(' - $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function(' - $scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)') + $savescheck = ''; + $scheck = $s; + while ($scheck && $savescheck != $scheck) { + $savescheck = $scheck; + $scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...' + $scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions + $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions + $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function(' + $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function(' + $scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)') + } //print 'scheck='.$scheck." : ".strpos($scheck, '(')."
\n"; if (strpos($scheck, '(') !== false) { if ($returnvalue) { - return 'Bad string syntax to evaluate (found call of a function or method without using direct name): '.$s; + return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s; } else { - dol_syslog('Bad string syntax to evaluate (found call of a function or method without using direct name): '.$s); + dol_syslog('Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s); return ''; } } diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 4615efe8c22..66a40206bb3 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -1061,6 +1061,10 @@ class SecurityTest extends PHPUnit\Framework\TestCase $langs=$this->savlangs; $db=$this->savdb; + // Declare classes found into string to evaluate + include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; + $result=dol_eval('1==1', 1, 0); print "result1 = ".$result."\n"; $this->assertTrue($result); @@ -1069,8 +1073,15 @@ class SecurityTest extends PHPUnit\Framework\TestCase print "result2 = ".$result."\n"; $this->assertFalse($result); - include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; - include_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; + $s = '((($reloadedobj = new ClassThatDoesNotExists($db)) && ($reloadedobj->fetchNoCompute($objectoffield->fk_product) > 0)) ? \'1\' : \'0\')'; + $result3a = dol_eval($s, 1, 1, '2'); + print "result3a = ".$result."\n"; + $this->assertTrue(is_null($result3a)); + + $s = '((($reloadedobj = new Project($db)) && ($reloadedobj->fetchNoCompute($objectoffield->fk_product) > 0)) ? \'1\' : \'0\')'; + $result3b = dol_eval($s, 1, 1, '2'); + print "result3b = ".$result."\n"; + $this->assertEquals('0', $result3b); $s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"'; $result=dol_eval($s, 1, 1, '2');