FileSystemRequestParent.cpp (5447B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/FileSystemRequestParent.h" 8 9 #include "GetDirectoryListingTask.h" 10 #include "GetFileOrDirectoryTask.h" 11 #include "GetFilesTask.h" 12 #include "mozilla/Preferences.h" 13 #include "mozilla/dom/BlobImpl.h" 14 #include "mozilla/dom/ContentParent.h" 15 #include "mozilla/dom/FileSystemBase.h" 16 #include "mozilla/dom/FileSystemSecurity.h" 17 #include "mozilla/dom/OSFileSystem.h" 18 #include "mozilla/dom/PFileSystemParams.h" 19 #include "mozilla/ipc/BackgroundParent.h" 20 #include "nsProxyRelease.h" 21 22 using namespace mozilla::ipc; 23 24 namespace mozilla::dom { 25 26 FileSystemRequestParent::FileSystemRequestParent() : mDestroyed(false) { 27 AssertIsOnBackgroundThread(); 28 } 29 30 FileSystemRequestParent::~FileSystemRequestParent() { 31 AssertIsOnBackgroundThread(); 32 } 33 34 #define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \ 35 case FileSystemParams::TFileSystem##name##Params: { \ 36 const FileSystem##name##Params& p = aParams; \ 37 mFileSystem = new OSFileSystemParent(p.filesystem()); \ 38 MOZ_ASSERT(mFileSystem); \ 39 mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \ 40 if (NS_WARN_IF(rv.Failed())) { \ 41 rv.SuppressException(); \ 42 return false; \ 43 } \ 44 break; \ 45 } 46 47 bool FileSystemRequestParent::Initialize(const FileSystemParams& aParams) { 48 AssertIsOnBackgroundThread(); 49 50 ErrorResult rv; 51 52 switch (aParams.type()) { 53 FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetDirectoryListing) 54 FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory) 55 FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFiles) 56 57 default: { 58 MOZ_CRASH("not reached"); 59 break; 60 } 61 } 62 63 if (NS_WARN_IF(!mTask || !mFileSystem)) { 64 // Should never reach here. 65 return false; 66 } 67 68 return true; 69 } 70 71 namespace { 72 73 class CheckPermissionRunnable final : public Runnable { 74 public: 75 CheckPermissionRunnable( 76 already_AddRefed<ThreadsafeContentParentHandle> aParent, 77 FileSystemRequestParent* aActor, FileSystemTaskParentBase* aTask, 78 const nsAString& aPath) 79 : Runnable("dom::CheckPermissionRunnable"), 80 mContentHandle(aParent), 81 mActor(aActor), 82 mTask(aTask), 83 mPath(aPath), 84 mBackgroundEventTarget(GetCurrentSerialEventTarget()) { 85 AssertIsInMainProcess(); 86 AssertIsOnBackgroundThread(); 87 88 MOZ_ASSERT(mContentHandle); 89 MOZ_ASSERT(mActor); 90 MOZ_ASSERT(mTask); 91 MOZ_ASSERT(mBackgroundEventTarget); 92 } 93 94 NS_IMETHOD 95 Run() override { 96 if (NS_IsMainThread()) { 97 if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled", 98 false)) { 99 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get(); 100 if (NS_WARN_IF(!fss || !fss->ContentProcessHasAccessTo( 101 mContentHandle->ChildID(), mPath))) { 102 AssertIsOnMainThread(); 103 if (RefPtr<ContentParent> contentParent = 104 mContentHandle->GetContentParent()) { 105 contentParent->KillHard("This path is not allowed."); 106 } 107 return NS_OK; 108 } 109 } 110 111 return mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); 112 } 113 114 AssertIsOnBackgroundThread(); 115 116 // It can happen that this actor has been destroyed in the meantime we were 117 // on the main-thread. 118 if (!mActor->Destroyed()) { 119 mTask->Start(); 120 } 121 122 return NS_OK; 123 } 124 125 private: 126 ~CheckPermissionRunnable() { 127 NS_ProxyRelease("CheckPermissionRunnable::mActor", mBackgroundEventTarget, 128 mActor.forget()); 129 } 130 131 RefPtr<ThreadsafeContentParentHandle> mContentHandle; 132 RefPtr<FileSystemRequestParent> mActor; 133 RefPtr<FileSystemTaskParentBase> mTask; 134 const nsString mPath; 135 136 nsCOMPtr<nsIEventTarget> mBackgroundEventTarget; 137 }; 138 139 } // namespace 140 141 void FileSystemRequestParent::Start() { 142 AssertIsInMainProcess(); 143 AssertIsOnBackgroundThread(); 144 145 MOZ_ASSERT(!mDestroyed); 146 MOZ_ASSERT(mFileSystem); 147 MOZ_ASSERT(mTask); 148 149 nsAutoString path; 150 if (NS_WARN_IF(NS_FAILED(mTask->GetTargetPath(path)))) { 151 (void)Send__delete__(this, 152 FileSystemErrorResponse(NS_ERROR_DOM_SECURITY_ERR)); 153 return; 154 } 155 156 RefPtr<ThreadsafeContentParentHandle> parent = 157 BackgroundParent::GetContentParentHandle(Manager()); 158 159 // If the ThreadsafeContentParentHandle is null we are dealing with a 160 // same-process actor. 161 if (!parent) { 162 mTask->Start(); 163 return; 164 } 165 166 RefPtr<Runnable> runnable = 167 new CheckPermissionRunnable(parent.forget(), this, mTask, path); 168 NS_DispatchToMainThread(runnable); 169 } 170 171 void FileSystemRequestParent::ActorDestroy(ActorDestroyReason aWhy) { 172 AssertIsOnBackgroundThread(); 173 MOZ_ASSERT(!mDestroyed); 174 175 if (!mFileSystem) { 176 return; 177 } 178 179 mFileSystem->Shutdown(); 180 mFileSystem = nullptr; 181 mTask = nullptr; 182 mDestroyed = true; 183 } 184 185 } // namespace mozilla::dom