mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-13 08:48:25 +00:00
core: prevent remote controller from writing files outside files folder (#7352)
This commit is contained in:
@@ -65,10 +65,10 @@ import Simplex.Messaging.Util
|
||||
import Simplex.RemoteControl.Client
|
||||
import Simplex.RemoteControl.Invitation (RCInvitation (..), RCSignedInvitation (..), RCVerifiedInvitation (..), verifySignedInvitation)
|
||||
import Simplex.RemoteControl.Types
|
||||
import System.FilePath (takeFileName, (</>))
|
||||
import System.FilePath (takeDirectory, takeFileName, (</>))
|
||||
import UnliftIO
|
||||
import UnliftIO.Concurrent (forkIO)
|
||||
import UnliftIO.Directory (copyFile, createDirectoryIfMissing, doesDirectoryExist, removeDirectoryRecursive, renameFile)
|
||||
import UnliftIO.Directory (canonicalizePath, copyFile, createDirectoryIfMissing, doesDirectoryExist, removeDirectoryRecursive, renameFile)
|
||||
|
||||
remoteFilesFolder :: String
|
||||
remoteFilesFolder = "simplex_v1_files"
|
||||
@@ -574,10 +574,19 @@ handleStoreFile rfKN fileName fileSize fileDigest getChunk =
|
||||
Nothing -> storeFileTo =<< getDefaultFilesFolder
|
||||
storeFileTo :: FilePath -> CM' (Either RemoteProtocolError FilePath)
|
||||
storeFileTo dir = liftIO . tryAllErrors' $ do
|
||||
unless (validRemoteFileName fileName) $ throwError $ RPEInvalidBody "invalid file name"
|
||||
filePath <- liftIO $ dir `uniqueCombine` fileName
|
||||
-- resolves symlinks, so it also catches a final component linking outside the folder
|
||||
canonPath <- liftIO $ canonicalizePath filePath
|
||||
inDir <- liftIO $ (takeDirectory canonPath ==) <$> canonicalizePath dir
|
||||
unless inDir $ throwError $ RPEInvalidBody "file path outside of files folder"
|
||||
receiveEncryptedFile rfKN getChunk fileSize fileDigest filePath
|
||||
pure filePath
|
||||
|
||||
-- The controller only ever sends a bare file name (see storeRemoteFile), so a path is a protocol violation.
|
||||
validRemoteFileName :: FilePath -> Bool
|
||||
validRemoteFileName fName = fName == takeFileName fName && fName `notElem` (["", ".", ".."] :: [FilePath])
|
||||
|
||||
handleGetFile :: User -> RemoteFile -> Respond -> CM ()
|
||||
handleGetFile User {userId} RemoteFile {userId = commandUserId, fileId, sent, fileSource = cf'@CryptoFile {filePath}} reply = do
|
||||
logDebug $ "GetFile: " <> tshow filePath
|
||||
|
||||
Reference in New Issue
Block a user