diff options
Diffstat (limited to 'dom/filesystem/FileSystemRequestParent.cpp')
-rw-r--r-- | dom/filesystem/FileSystemRequestParent.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/dom/filesystem/FileSystemRequestParent.cpp b/dom/filesystem/FileSystemRequestParent.cpp new file mode 100644 index 0000000000..25211dbd23 --- /dev/null +++ b/dom/filesystem/FileSystemRequestParent.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/FileSystemRequestParent.h" +#include "mozilla/dom/PFileSystemParams.h" + +#include "GetDirectoryListingTask.h" +#include "GetFileOrDirectoryTask.h" +#include "GetFilesTask.h" + +#include "mozilla/dom/BlobImpl.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/FileSystemBase.h" +#include "mozilla/dom/FileSystemSecurity.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/dom/OSFileSystem.h" +#include "mozilla/Preferences.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Unused.h" +#include "nsProxyRelease.h" + +using namespace mozilla::ipc; + +namespace mozilla::dom { + +FileSystemRequestParent::FileSystemRequestParent() : mDestroyed(false) { + AssertIsOnBackgroundThread(); +} + +FileSystemRequestParent::~FileSystemRequestParent() { + AssertIsOnBackgroundThread(); +} + +#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \ + case FileSystemParams::TFileSystem##name##Params: { \ + const FileSystem##name##Params& p = aParams; \ + mFileSystem = new OSFileSystemParent(p.filesystem()); \ + MOZ_ASSERT(mFileSystem); \ + mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \ + if (NS_WARN_IF(rv.Failed())) { \ + rv.SuppressException(); \ + return false; \ + } \ + break; \ + } + +bool FileSystemRequestParent::Initialize(const FileSystemParams& aParams) { + AssertIsOnBackgroundThread(); + + ErrorResult rv; + + switch (aParams.type()) { + FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetDirectoryListing) + FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory) + FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFiles) + + default: { + MOZ_CRASH("not reached"); + break; + } + } + + if (NS_WARN_IF(!mTask || !mFileSystem)) { + // Should never reach here. + return false; + } + + return true; +} + +namespace { + +class CheckPermissionRunnable final : public Runnable { + public: + CheckPermissionRunnable( + already_AddRefed<ThreadsafeContentParentHandle> aParent, + FileSystemRequestParent* aActor, FileSystemTaskParentBase* aTask, + const nsAString& aPath) + : Runnable("dom::CheckPermissionRunnable"), + mContentHandle(aParent), + mActor(aActor), + mTask(aTask), + mPath(aPath), + mBackgroundEventTarget(GetCurrentSerialEventTarget()) { + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + MOZ_ASSERT(mContentHandle); + MOZ_ASSERT(mActor); + MOZ_ASSERT(mTask); + MOZ_ASSERT(mBackgroundEventTarget); + } + + NS_IMETHOD + Run() override { + if (NS_IsMainThread()) { + if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled", + false)) { + RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get(); + if (NS_WARN_IF(!fss || !fss->ContentProcessHasAccessTo( + mContentHandle->ChildID(), mPath))) { + AssertIsOnMainThread(); + if (RefPtr<ContentParent> contentParent = + mContentHandle->GetContentParent()) { + contentParent->KillHard("This path is not allowed."); + } + return NS_OK; + } + } + + return mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); + } + + AssertIsOnBackgroundThread(); + + // It can happen that this actor has been destroyed in the meantime we were + // on the main-thread. + if (!mActor->Destroyed()) { + mTask->Start(); + } + + return NS_OK; + } + + private: + ~CheckPermissionRunnable() { + NS_ProxyRelease("CheckPermissionRunnable::mActor", mBackgroundEventTarget, + mActor.forget()); + } + + RefPtr<ThreadsafeContentParentHandle> mContentHandle; + RefPtr<FileSystemRequestParent> mActor; + RefPtr<FileSystemTaskParentBase> mTask; + const nsString mPath; + + nsCOMPtr<nsIEventTarget> mBackgroundEventTarget; +}; + +} // namespace + +void FileSystemRequestParent::Start() { + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + MOZ_ASSERT(!mDestroyed); + MOZ_ASSERT(mFileSystem); + MOZ_ASSERT(mTask); + + nsAutoString path; + if (NS_WARN_IF(NS_FAILED(mTask->GetTargetPath(path)))) { + (void)Send__delete__(this, + FileSystemErrorResponse(NS_ERROR_DOM_SECURITY_ERR)); + return; + } + + RefPtr<ThreadsafeContentParentHandle> parent = + BackgroundParent::GetContentParentHandle(Manager()); + + // If the ThreadsafeContentParentHandle is null we are dealing with a + // same-process actor. + if (!parent) { + mTask->Start(); + return; + } + + RefPtr<Runnable> runnable = + new CheckPermissionRunnable(parent.forget(), this, mTask, path); + NS_DispatchToMainThread(runnable); +} + +void FileSystemRequestParent::ActorDestroy(ActorDestroyReason aWhy) { + AssertIsOnBackgroundThread(); + MOZ_ASSERT(!mDestroyed); + + if (!mFileSystem) { + return; + } + + mFileSystem->Shutdown(); + mFileSystem = nullptr; + mTask = nullptr; + mDestroyed = true; +} + +} // namespace mozilla::dom |