Skip to content

Commit

Permalink
Improve detection of recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Nov 7, 2024
1 parent a0f7756 commit d3fc074
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 14 deletions.
2 changes: 1 addition & 1 deletion doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ won't be allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.

.. note::

As of Twig 1.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
As of Twig 3.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
the ``ArrayAccess`` interface, the templates will only be able to access
the ``title`` and ``body`` attributes.

Expand Down
56 changes: 43 additions & 13 deletions src/Extension/SandboxExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,11 @@ final class SandboxExtension extends AbstractExtension
private $policy;
private $sourcePolicy;

static array $recursionProjection = [];

public function __construct(SecurityPolicyInterface $policy, $sandboxed = false, ?SourcePolicyInterface $sourcePolicy = null)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
$this->sourcePolicy = $sourcePolicy;
static::$recursionProjection = [];
}

public function getTokenParsers(): array
Expand Down Expand Up @@ -123,16 +120,8 @@ public function checkPropertyAllowed($obj, $property, int $lineno = -1, ?Source
public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null)
{
if (\is_array($obj)) {
$hash = \hash('sha256', \serialize($obj));
if (\array_key_exists($hash, static::$recursionProjection)) {
unset(static::$recursionProjection[$hash]);
return $obj;
}
static::$recursionProjection[$hash] = TRUE;
foreach ($obj as $v) {
$this->ensureToStringAllowed($v, $lineno, $source);
}
unset(static::$recursionProjection[$hash]);
$this->ensureToStringAllowedForArray($obj, $lineno, $source);

return $obj;
}

Expand All @@ -149,4 +138,45 @@ public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source =

return $obj;
}

private function ensureToStringAllowedForArray(array $obj, int $lineno, ?Source $source, array &$stack = []): void
{
foreach ($obj as $k => $v) {
if (!$v) {
continue;
}

if (!\is_array($v)) {
$this->ensureToStringAllowed($v, $lineno, $source);
continue;
}

if (\PHP_VERSION_ID < 70400) {
static $cookie;

if ($v === $cookie ?? $cookie = new \stdClass()) {
continue;
}

$obj[$k] = $cookie;
try {
$this->ensureToStringAllowedForArray($v, $lineno, $source, $stack);
} finally {
$obj[$k] = $v;
}

continue;
}

if ($r = \ReflectionReference::fromArrayElement($obj, $k)) {
if (isset($stack[$r->getId()])) {
continue;
}

$stack[$r->getId()] = true;
}

$this->ensureToStringAllowedForArray($v, $lineno, $source, $stack);
}
}
}

0 comments on commit d3fc074

Please sign in to comment.