From b2e3850d852fc34e3b45368d31148f940d2e6264 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Dec 2015 17:08:27 +0100 Subject: [PATCH] [DependencyInjection] Validate class names and factory methods --- .../DependencyInjection/Dumper/PhpDumper.php | 25 ++++++++++++++----- .../Tests/Dumper/PhpDumperTest.php | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index bb3df8bef158..d4010f1f1a19 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -759,6 +759,10 @@ private function addNewInstance($id, Definition $definition, $return, $instantia if (null !== $definition->getFactory()) { $callable = $definition->getFactory(); if (is_array($callable)) { + if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) { + throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a')); + } + if ($callable[0] instanceof Reference || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) { return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); @@ -1310,8 +1314,12 @@ private function dumpValue($value, $interpolate = true) } if (is_array($factory)) { + if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) { + throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a')); + } + if (is_string($factory[0])) { - return sprintf('\\%s::%s(%s)', $factory[0], $factory[1], implode(', ', $arguments)); + return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments)); } if ($factory[0] instanceof Definition) { @@ -1342,12 +1350,8 @@ private function dumpValue($value, $interpolate = true) if (null === $class) { throw new RuntimeException('Cannot dump definitions which have no class nor factory.'); } - $class = $this->dumpValue($class); - if (false !== strpos($class, '$')) { - throw new RuntimeException('Cannot dump definitions which have a variable class name.'); - } - return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); + return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)); } elseif ($value instanceof Variable) { return '$'.$value; } elseif ($value instanceof Reference) { @@ -1388,9 +1392,18 @@ private function dumpValue($value, $interpolate = true) * @param string $class * * @return string + * + * @throws RuntimeException */ private function dumpLiteralClass($class) { + if (false !== strpos($class, '$')) { + throw new RuntimeException('Cannot dump definitions which have a variable class name.'); + } + if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) { + throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a')); + } + return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 063007e5d34e..7207a143e6f6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -154,6 +154,31 @@ public function testAddServiceInvalidServiceId() $dumper->dump(); } + /** + * @dataProvider provideInvalidFactories + * @expectedException Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot dump definition + */ + public function testInvalidFactories($factory) + { + $container = new ContainerBuilder(); + $def = new Definition('stdClass'); + $def->setFactory($factory); + $container->setDefinition('bar', $def); + $dumper = new PhpDumper($container); + $dumper->dump(); + } + + public function provideInvalidFactories() + { + return array( + array(array('', 'method')), + array(array('class', '')), + array(array('...', 'method')), + array(array('class', '...')), + ); + } + public function testAliases() { $container = include self::$fixturesPath.'/containers/container9.php';