Skip to content

Commit 5b4ceb0

Browse files
icewind1991AndyScherzinger
authored andcommitted
fix: improve checks for moving shares/storages into other mounts
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 1d7ade4 commit 5b4ceb0

File tree

2 files changed

+93
-24
lines changed

2 files changed

+93
-24
lines changed

lib/private/Files/View.php

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
use OCP\Files\InvalidCharacterInPathException;
6464
use OCP\Files\InvalidDirectoryException;
6565
use OCP\Files\InvalidPathException;
66+
use OCP\Files\Mount\IMountManager;
6667
use OCP\Files\Mount\IMountPoint;
6768
use OCP\Files\NotFoundException;
6869
use OCP\Files\ReservedWordException;
@@ -739,6 +740,9 @@ public function rename($source, $target) {
739740
throw new ForbiddenException("Moving a folder into a child folder is forbidden", false);
740741
}
741742

743+
/** @var IMountManager $mountManager */
744+
$mountManager = \OC::$server->get(IMountManager::class);
745+
742746
$targetParts = explode('/', $absolutePath2);
743747
$targetUser = $targetParts[1] ?? null;
744748
$result = false;
@@ -792,31 +796,35 @@ public function rename($source, $target) {
792796
try {
793797
$this->changeLock($target, ILockingProvider::LOCK_EXCLUSIVE, true);
794798

799+
$movedMounts = $mountManager->findIn($this->getAbsolutePath($source));
800+
795801
if ($internalPath1 === '') {
796-
if ($mount1 instanceof MoveableMount) {
797-
$sourceParentMount = $this->getMount(dirname($source));
798-
if ($sourceParentMount === $mount2 && $this->targetIsNotShared($targetUser, $absolutePath2)) {
799-
/**
800-
* @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
801-
*/
802-
$sourceMountPoint = $mount1->getMountPoint();
803-
$result = $mount1->moveMount($absolutePath2);
804-
$manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
805-
} else {
806-
$result = false;
807-
}
808-
} else {
809-
$result = false;
810-
}
802+
$sourceParentMount = $this->getMount(dirname($source));
803+
$movedMounts[] = $mount1;
804+
$this->validateMountMove($movedMounts, $sourceParentMount, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
805+
806+
/**
807+
* @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
808+
*/
809+
$sourceMountPoint = $mount1->getMountPoint();
810+
$result = $mount1->moveMount($absolutePath2);
811+
$manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
812+
811813
// moving a file/folder within the same mount point
812814
} elseif ($storage1 === $storage2) {
815+
if (count($movedMounts) > 0) {
816+
$this->validateMountMove($movedMounts, $mount1, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
817+
}
813818
if ($storage1) {
814819
$result = $storage1->rename($internalPath1, $internalPath2);
815820
} else {
816821
$result = false;
817822
}
818823
// moving a file/folder between storages (from $storage1 to $storage2)
819824
} else {
825+
if (count($movedMounts) > 0) {
826+
$this->validateMountMove($movedMounts, $mount1, $mount2, !$this->targetIsNotShared($targetUser, $absolutePath2));
827+
}
820828
$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
821829
}
822830

@@ -866,6 +874,34 @@ public function rename($source, $target) {
866874
return $result;
867875
}
868876

877+
private function validateMountMove(array $mounts, IMountPoint $sourceMount, IMountPoint $targetMount, bool $targetIsShared): void {
878+
$targetType = 'storage';
879+
if ($targetMount instanceof SharedMount) {
880+
$targetType = 'share';
881+
}
882+
$targetPath = rtrim($targetMount->getMountPoint(), '/');
883+
884+
foreach ($mounts as $mount) {
885+
$sourcePath = rtrim($mount->getMountPoint(), '/');
886+
$sourceType = 'storage';
887+
if ($mount instanceof SharedMount) {
888+
$sourceType = 'share';
889+
}
890+
891+
if (!$mount instanceof MoveableMount) {
892+
throw new ForbiddenException("Storage {$sourcePath} cannot be moved", false);
893+
}
894+
895+
if ($targetIsShared) {
896+
throw new ForbiddenException("Moving a $sourceType ($sourcePath) into shared folder is not allowed", false);
897+
}
898+
899+
if ($sourceMount !== $targetMount) {
900+
throw new ForbiddenException("Moving a $sourceType ($sourcePath) into another $targetType ($targetPath) is not allowed", false);
901+
}
902+
}
903+
}
904+
869905
/**
870906
* Copy a file/folder from the source path to target path
871907
*

tests/lib/Files/ViewTest.php

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use OCP\Constants;
2121
use OCP\Files\Config\IMountProvider;
2222
use OCP\Files\FileInfo;
23+
use OCP\Files\ForbiddenException;
2324
use OCP\Files\GenericFileException;
2425
use OCP\Files\Mount\IMountManager;
2526
use OCP\Files\Storage\IStorage;
@@ -1639,10 +1640,27 @@ public function testMountPointMove() {
16391640
$this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory');
16401641
}
16411642

1642-
/**
1643-
* Test that moving a mount point into another is forbidden
1644-
*/
1645-
public function testMoveMountPointIntoAnother() {
1643+
public function testMoveMountPointOverwrite(): void {
1644+
self::loginAsUser($this->user);
1645+
1646+
[$mount1, $mount2] = $this->createTestMovableMountPoints([
1647+
$this->user . '/files/mount1',
1648+
$this->user . '/files/mount2',
1649+
]);
1650+
1651+
$mount1->expects($this->never())
1652+
->method('moveMount');
1653+
1654+
$mount2->expects($this->never())
1655+
->method('moveMount');
1656+
1657+
$view = new View('/' . $this->user . '/files/');
1658+
1659+
$this->expectException(ForbiddenException::class);
1660+
$view->rename('mount1', 'mount2');
1661+
}
1662+
1663+
public function testMoveMountPointIntoMount(): void {
16461664
self::loginAsUser($this->user);
16471665

16481666
[$mount1, $mount2] = $this->createTestMovableMountPoints([
@@ -1658,8 +1676,8 @@ public function testMoveMountPointIntoAnother() {
16581676

16591677
$view = new View('/' . $this->user . '/files/');
16601678

1661-
$this->assertFalse($view->rename('mount1', 'mount2'), 'Cannot overwrite another mount point');
1662-
$this->assertFalse($view->rename('mount1', 'mount2/sub'), 'Cannot move a mount point into another');
1679+
$this->expectException(ForbiddenException::class);
1680+
$view->rename('mount1', 'mount2/sub');
16631681
}
16641682

16651683
/**
@@ -1701,9 +1719,24 @@ public function testMoveMountPointIntoSharedFolder() {
17011719
->setNode($shareDir);
17021720
$shareManager->createShare($share);
17031721

1704-
$this->assertFalse($view->rename('mount1', 'shareddir'), 'Cannot overwrite shared folder');
1705-
$this->assertFalse($view->rename('mount1', 'shareddir/sub'), 'Cannot move mount point into shared folder');
1706-
$this->assertFalse($view->rename('mount1', 'shareddir/sub/sub2'), 'Cannot move mount point into shared subfolder');
1722+
try {
1723+
$view->rename('mount1', 'shareddir');
1724+
$this->fail('Cannot overwrite shared folder');
1725+
} catch (ForbiddenException $e) {
1726+
1727+
}
1728+
try {
1729+
$view->rename('mount1', 'shareddir/sub');
1730+
$this->fail('Cannot move mount point into shared folder');
1731+
} catch (ForbiddenException $e) {
1732+
1733+
}
1734+
try {
1735+
$view->rename('mount1', 'shareddir/sub/sub2');
1736+
$this->fail('Cannot move mount point into shared subfolder');
1737+
} catch (ForbiddenException $e) {
1738+
1739+
}
17071740
$this->assertTrue($view->rename('mount2', 'shareddir notshared/sub'), 'Can move mount point into a similarly named but non-shared folder');
17081741

17091742
$shareManager->deleteShare($share);

0 commit comments

Comments
 (0)