diff options
author | Robin Appelman <icewind@owncloud.com> | 2016-05-30 15:44:19 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2016-06-07 14:01:53 +0200 |
commit | 7b1b723e5b04173409117aca1f7e76bed5762d9f (patch) | |
tree | 22e09226a7f4853c3a7d936a33a29d8115af8bcf /lib/private/Files | |
parent | 46fe2ddf2e7a4413586095143521684a0377daad (diff) | |
download | nextcloud-server-7b1b723e5b04173409117aca1f7e76bed5762d9f.tar.gz nextcloud-server-7b1b723e5b04173409117aca1f7e76bed5762d9f.zip |
dissalow symlinks in local storages that point outside the datadir
Diffstat (limited to 'lib/private/Files')
-rw-r--r-- | lib/private/Files/Storage/Local.php | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index acd4c3b4838..005b5f9ab91 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -33,20 +33,31 @@ */ namespace OC\Files\Storage; + +use OCP\Files\ForbiddenException; + /** * for local filestore, we only have to map the paths */ class Local extends \OC\Files\Storage\Common { protected $datadir; + protected $dataDirLength; + + protected $allowSymlinks = false; + + protected $realDataDir; + public function __construct($arguments) { if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) { throw new \InvalidArgumentException('No data directory set for local storage'); } $this->datadir = $arguments['datadir']; + $this->realDataDir = rtrim(realpath($this->datadir), '/') . '/'; if (substr($this->datadir, -1) !== '/') { $this->datadir .= '/'; } + $this->dataDirLength = strlen($this->realDataDir); } public function __destruct() { @@ -337,10 +348,27 @@ class Local extends \OC\Files\Storage\Common { * * @param string $path * @return string + * @throws ForbiddenException */ public function getSourcePath($path) { $fullPath = $this->datadir . $path; - return $fullPath; + if ($this->allowSymlinks || $path === '') { + return $fullPath; + } + $pathToResolve = $fullPath; + $realPath = realpath($pathToResolve); + while ($realPath === false) { // for non existing files check the parent directory + $pathToResolve = dirname($pathToResolve); + $realPath = realpath($pathToResolve); + } + if ($realPath) { + $realPath = $realPath . '/'; + } + if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) { + return $fullPath; + } else { + throw new ForbiddenException("Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", false); + } } /** |