From d53c9c61e3accd858c956aa91c964f25d8427121 Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Mon, 26 Aug 2019 18:10:06 +0200 Subject: [PATCH] [BUGFIX] Prevent infinite loops caused by symlinks --- Classes/Utility/ComponentLoader.php | 21 +++++++++++++------ .../Atom/ComponentLoaderSymlink | 1 + .../ComponentLoader/Molecule/Circular | 1 + .../Fixtures/ComponentLoader/Molecule/Example | 1 + .../ComponentLoaderSymlink.html | 0 Tests/Unit/ComponentLoaderTest.php | 3 ++- 6 files changed, 20 insertions(+), 7 deletions(-) create mode 120000 Tests/Fixtures/ComponentLoader/Atom/ComponentLoaderSymlink create mode 120000 Tests/Fixtures/ComponentLoader/Molecule/Circular create mode 120000 Tests/Fixtures/ComponentLoader/Molecule/Example create mode 100644 Tests/Fixtures/ComponentLoaderSymlink/ComponentLoaderSymlink.html diff --git a/Classes/Utility/ComponentLoader.php b/Classes/Utility/ComponentLoader.php index 7598800..e556120 100644 --- a/Classes/Utility/ComponentLoader.php +++ b/Classes/Utility/ComponentLoader.php @@ -139,10 +139,12 @@ public function findComponentsInNamespace(string $namespace, string $ext = '.htm return []; } + $scannedPaths = []; return $this->scanForComponents( $this->namespaces[$namespace], $ext, - $namespace + $namespace, + $scannedPaths ); } @@ -152,20 +154,27 @@ public function findComponentsInNamespace(string $namespace, string $ext = '.htm * @param string $path * @param string $ext * @param string $namespace + * @param array $scannedPaths Collection of paths that have already been scanned for components; + * this prevents infinite loops caused by circular symlinks * @return array */ - protected function scanForComponents(string $path, string $ext, string $namespace): array + protected function scanForComponents(string $path, string $ext, string $namespace, array &$scannedPaths): array { $components = []; $componentCandidates = scandir($path); foreach ($componentCandidates as $componentName) { - $componentPath = $path . DIRECTORY_SEPARATOR . $componentName; + // Skip relative links + if ($componentName === '.' || $componentName === '..') { + continue; + } - // Only search for directories - if ($componentName === '.' || $componentName === '..' || !is_dir($componentPath)) { + // Only search for directories and prevent infinite loops + $componentPath = realpath($path . DIRECTORY_SEPARATOR . $componentName); + if (!is_dir($componentPath) || isset($scannedPaths[$componentPath])) { continue; } + $scannedPaths[$componentPath] = true; $componentNamespace = $namespace . '\\' . $componentName; $componentFile = $componentPath . DIRECTORY_SEPARATOR . $componentName . $ext; @@ -178,7 +187,7 @@ protected function scanForComponents(string $path, string $ext, string $namespac // Continue recursively $components = array_merge( $components, - $this->scanForComponents($componentPath, $ext, $componentNamespace) + $this->scanForComponents($componentPath, $ext, $componentNamespace, $scannedPaths) ); } diff --git a/Tests/Fixtures/ComponentLoader/Atom/ComponentLoaderSymlink b/Tests/Fixtures/ComponentLoader/Atom/ComponentLoaderSymlink new file mode 120000 index 0000000..93df1d4 --- /dev/null +++ b/Tests/Fixtures/ComponentLoader/Atom/ComponentLoaderSymlink @@ -0,0 +1 @@ +../../ComponentLoaderSymlink/ \ No newline at end of file diff --git a/Tests/Fixtures/ComponentLoader/Molecule/Circular b/Tests/Fixtures/ComponentLoader/Molecule/Circular new file mode 120000 index 0000000..b870225 --- /dev/null +++ b/Tests/Fixtures/ComponentLoader/Molecule/Circular @@ -0,0 +1 @@ +../ \ No newline at end of file diff --git a/Tests/Fixtures/ComponentLoader/Molecule/Example b/Tests/Fixtures/ComponentLoader/Molecule/Example new file mode 120000 index 0000000..6b784d7 --- /dev/null +++ b/Tests/Fixtures/ComponentLoader/Molecule/Example @@ -0,0 +1 @@ +../Example/ \ No newline at end of file diff --git a/Tests/Fixtures/ComponentLoaderSymlink/ComponentLoaderSymlink.html b/Tests/Fixtures/ComponentLoaderSymlink/ComponentLoaderSymlink.html new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Unit/ComponentLoaderTest.php b/Tests/Unit/ComponentLoaderTest.php index 1090345..2ee8604 100644 --- a/Tests/Unit/ComponentLoaderTest.php +++ b/Tests/Unit/ComponentLoaderTest.php @@ -15,7 +15,7 @@ protected function setUp() protected function getFixturePath($fixtureName) { - return dirname(__FILE__) . '/../Fixtures/' . $fixtureName; + return realpath(dirname(__FILE__) . '/../Fixtures/' . $fixtureName); } public function addNamespaceProvider() @@ -177,6 +177,7 @@ public function findComponentsInNamespaceProvider() '.html', [ 'Sitegeist\\Fixtures\\ComponentLoader\\Atom\\Button' => $this->getFixturePath('ComponentLoader/Atom/Button/Button.html'), + 'Sitegeist\\Fixtures\\ComponentLoader\\Atom\\ComponentLoaderSymlink' => $this->getFixturePath('ComponentLoader/Atom/ComponentLoaderSymlink/ComponentLoaderSymlink.html'), 'Sitegeist\\Fixtures\\ComponentLoader\\Atom\\Link' => $this->getFixturePath('ComponentLoader/Atom/Link/Link.html'), 'Sitegeist\\Fixtures\\ComponentLoader\\Example' => $this->getFixturePath('ComponentLoader/Example/Example.html'), 'Sitegeist\\Fixtures\\ComponentLoader\\Molecule\\Teaser' => $this->getFixturePath('ComponentLoader/Molecule/Teaser/Teaser.html'),