diff options
Diffstat (limited to 'dom/filesystem/FileSystemRequestParent.cpp')
-rw-r--r-- | dom/filesystem/FileSystemRequestParent.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/dom/filesystem/FileSystemRequestParent.cpp b/dom/filesystem/FileSystemRequestParent.cpp new file mode 100644 index 000000000..0b9d6c18a --- /dev/null +++ b/dom/filesystem/FileSystemRequestParent.cpp @@ -0,0 +1,194 @@ +/* -*- 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 "mozilla/AppProcessChecker.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/FileSystemBase.h" +#include "mozilla/dom/FileSystemSecurity.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/Unused.h" +#include "nsProxyRelease.h" + +using namespace mozilla::ipc; + +namespace mozilla { +namespace 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: { + NS_RUNTIMEABORT("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<ContentParent> aParent, + FileSystemRequestParent* aActor, + FileSystemTaskParentBase* aTask, + const nsAString& aPath) + : mContentParent(aParent) + , mActor(aActor) + , mTask(aTask) + , mPath(aPath) + , mBackgroundEventTarget(NS_GetCurrentThread()) + { + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + MOZ_ASSERT(mContentParent); + MOZ_ASSERT(mActor); + MOZ_ASSERT(mTask); + MOZ_ASSERT(mBackgroundEventTarget); + } + + NS_IMETHOD + Run() override + { + if (NS_IsMainThread()) { + auto raii = mozilla::MakeScopeExit([&] { mContentParent = nullptr; }); + + + if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled", false)) { + RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get(); + if (NS_WARN_IF(!fss || + !fss->ContentProcessHasAccessTo(mContentParent->ChildID(), + mPath))) { + mContentParent->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(mBackgroundEventTarget, mActor.forget()); + } + + RefPtr<ContentParent> mContentParent; + RefPtr<FileSystemRequestParent> mActor; + RefPtr<FileSystemTaskParentBase> mTask; + const nsString mPath; + + nsCOMPtr<nsIEventTarget> mBackgroundEventTarget; +}; + +} // anonymous + +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)))) { + Unused << Send__delete__(this, FileSystemErrorResponse(NS_ERROR_DOM_SECURITY_ERR)); + return; + } + + RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager()); + + // If the ContentParent 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 dom +} // namespace mozilla |