Skip to content

Commit

Permalink
Fix recursion when arrays contain self-references in sandboxed mode
Browse files Browse the repository at this point in the history
  • Loading branch information
larowlan authored and nicolas-grekas committed Nov 7, 2024
1 parent 5b580ec commit a0f7756
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 5 deletions.
11 changes: 10 additions & 1 deletion src/Extension/SandboxExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ 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 @@ -120,10 +123,16 @@ 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]);
return $obj;
}

Expand Down
12 changes: 8 additions & 4 deletions tests/Extension/SandboxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ protected function setUp(): void
'some_array' => [5, 6, 7, new FooObject()],
'array_like' => new ArrayLikeObject(),
'magic' => new MagicObject(),
'recursion' => [4],
];
self::$params['recursion'][] = &self::$params['recursion'];
self::$params['recursion'][] = new FooObject();

self::$templates = [
'1_basic1' => '{{ obj.foo }}',
Expand Down Expand Up @@ -240,6 +243,7 @@ public function getSandboxUnallowedToStringTests()
'context' => ['{{ _context|join(", ") }}'],
'spread_array_operator' => ['{{ [1, 2, ...[5, 6, 7, obj]]|join(",") }}'],
'spread_array_operator_var' => ['{{ [1, 2, ...some_array]|join(",") }}'],
'recursion' => ['{{ recursion|join(", ") }}'],
];
}

Expand Down Expand Up @@ -573,13 +577,13 @@ class ArrayLikeObject extends \ArrayObject
{
public function offsetExists($offset): bool
{
throw new \BadMethodCallException('Should not be called');
throw new \BadMethodCallException('Should not be called.');
}

#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
throw new \BadMethodCallException('Should not be called');
throw new \BadMethodCallException('Should not be called.');
}

public function offsetSet($offset, $value): void
Expand All @@ -596,11 +600,11 @@ class MagicObject
#[\ReturnTypeWillChange]
public function __get($name)
{
throw new \BadMethodCallException('Should not be called');
throw new \BadMethodCallException('Should not be called.');
}

public function __isset($name): bool
{
throw new \BadMethodCallException('Should not be called');
throw new \BadMethodCallException('Should not be called.');
}
}

0 comments on commit a0f7756

Please sign in to comment.