mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
fix: reject dangling symlinks in validate_relative_path_within (#8389)
* fix: reject dangling symlinks in validate_relative_path_within Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: add changelog entry for dangling symlink fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
This commit is contained in:
1 parent
37a44d793e
commit
0f06608175
3 files changed
+20
-2
No files matched your search
@@ -0,0 +1 @@
|
||||
Reject dangling symlinks in validate_relative_path_within
|
||||
+1
-1
@@ -10787,7 +10787,7 @@ function validate_relative_path_within(mixed $path, string $base_dir) : mixed {
|
||||
foreach ($parts as $part) {
|
||||
$walk .= '/' . $part;
|
||||
|
||||
if (file_exists($walk) && is_link($walk)) {
|
||||
if (is_link($walk)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,12 @@ beforeEach(function () : void {
|
||||
$this->base = sys_get_temp_dir() . '/cacti_containment_' . bin2hex(random_bytes(6));
|
||||
mkdir($this->base . '/nested', 0755, true);
|
||||
file_put_contents($this->base . '/nested/present.txt', 'x');
|
||||
|
||||
$this->outside = $this->base . '_outside/pwned.txt';
|
||||
});
|
||||
|
||||
afterEach(function () : void {
|
||||
foreach (['/nested/present.txt', '/nested/link', '/link', '/nested', ''] as $leaf) {
|
||||
foreach (['/nested/present.txt', '/nested/link', '/nested/dangling.php', '/link', '/dangling', '/nested', ''] as $leaf) {
|
||||
$path = $this->base . $leaf;
|
||||
|
||||
if (is_link($path)) {
|
||||
@@ -84,6 +86,21 @@ test('a symlinked segment under the base is rejected', function () : void {
|
||||
expect(validate_relative_path_within('link/anything.txt', $this->base))->toBeFalse();
|
||||
});
|
||||
|
||||
test('a dangling symlink is rejected as the final or an intermediate segment', function () : void {
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
$this->markTestSkipped('Symlink creation is not consistently available on Windows.');
|
||||
}
|
||||
|
||||
if (!@symlink($this->outside, $this->base . '/nested/dangling.php') || !@symlink($this->outside, $this->base . '/dangling')) {
|
||||
$this->markTestSkipped('Symlink creation is not permitted in this environment.');
|
||||
}
|
||||
|
||||
expect(validate_relative_path_within('nested/dangling.php', $this->base))->toBeFalse()
|
||||
->and(validate_relative_path_within('dangling/child.php', $this->base))->toBeFalse()
|
||||
->and(validate_relative_path_within('nested/present.txt', $this->base))
|
||||
->toBe(realpath($this->base) . '/nested/present.txt');
|
||||
});
|
||||
|
||||
test('a path whose parent cannot be resolved is rejected', function () : void {
|
||||
expect(validate_relative_path_within('missing_dir/child/file.txt', $this->base))->toBeFalse();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user