diff options
Diffstat (limited to 'dom/ipc/nsIContentParent.cpp')
-rw-r--r-- | dom/ipc/nsIContentParent.cpp | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/dom/ipc/nsIContentParent.cpp b/dom/ipc/nsIContentParent.cpp new file mode 100644 index 000000000..0ef1abdf7 --- /dev/null +++ b/dom/ipc/nsIContentParent.cpp @@ -0,0 +1,328 @@ +/* -*- 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 "nsIContentParent.h" + +#include "mozilla/AppProcessChecker.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ContentBridgeParent.h" +#include "mozilla/dom/PTabContext.h" +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/dom/ipc/BlobParent.h" +#include "mozilla/dom/ipc/StructuredCloneData.h" +#include "mozilla/jsipc/CrossProcessObjectWrappers.h" +#include "mozilla/ipc/FileDescriptorSetParent.h" +#include "mozilla/ipc/PFileDescriptorSetParent.h" +#include "mozilla/ipc/SendStreamAlloc.h" +#include "mozilla/Unused.h" + +#include "nsFrameMessageManager.h" +#include "nsIWebBrowserChrome.h" +#include "nsPrintfCString.h" +#include "xpcpublic.h" + +using namespace mozilla::jsipc; + +// XXX need another bug to move this to a common header. +#ifdef DISABLE_ASSERTS_FOR_FUZZING +#define ASSERT_UNLESS_FUZZING(...) do { } while (0) +#else +#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__) +#endif + +namespace mozilla { +namespace dom { + +nsIContentParent::nsIContentParent() +{ + mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true); +} + +ContentParent* +nsIContentParent::AsContentParent() +{ + MOZ_ASSERT(IsContentParent()); + return static_cast<ContentParent*>(this); +} + +ContentBridgeParent* +nsIContentParent::AsContentBridgeParent() +{ + MOZ_ASSERT(IsContentBridgeParent()); + return static_cast<ContentBridgeParent*>(this); +} + +PJavaScriptParent* +nsIContentParent::AllocPJavaScriptParent() +{ + return NewJavaScriptParent(); +} + +bool +nsIContentParent::DeallocPJavaScriptParent(PJavaScriptParent* aParent) +{ + ReleaseJavaScriptParent(aParent); + return true; +} + +bool +nsIContentParent::CanOpenBrowser(const IPCTabContext& aContext) +{ + // (PopupIPCTabContext lets the child process prove that it has access to + // the app it's trying to open.) + // On e10s we also allow UnsafeTabContext to allow service workers to open + // windows. This is enforced in MaybeInvalidTabContext. + if (aContext.type() != IPCTabContext::TPopupIPCTabContext && + aContext.type() != IPCTabContext::TUnsafeIPCTabContext) { + ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type. Aborting AllocPBrowserParent."); + return false; + } + + if (aContext.type() == IPCTabContext::TPopupIPCTabContext) { + const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext(); + if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) { + ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type. Aborting AllocPBrowserParent."); + return false; + } + + auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent()); + if (!opener) { + ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent."); + return false; + } + + // Popup windows of isMozBrowserElement frames must be isMozBrowserElement if + // the parent isMozBrowserElement. Allocating a !isMozBrowserElement frame with + // same app ID would allow the content to access data it's not supposed to. + if (!popupContext.isMozBrowserElement() && opener->IsMozBrowserElement()) { + ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent."); + return false; + } + } + + MaybeInvalidTabContext tc(aContext); + if (!tc.IsValid()) { + NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) " + "Aborting AllocPBrowserParent.", + tc.GetInvalidReason()).get()); + return false; + } + + return true; +} + +PBrowserParent* +nsIContentParent::AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext& aContext, + const uint32_t& aChromeFlags, + const ContentParentId& aCpId, + const bool& aIsForApp, + const bool& aIsForBrowser) +{ + Unused << aCpId; + Unused << aIsForApp; + Unused << aIsForBrowser; + + if (!CanOpenBrowser(aContext)) { + return nullptr; + } + + uint32_t chromeFlags = aChromeFlags; + if (aContext.type() == IPCTabContext::TPopupIPCTabContext) { + // CanOpenBrowser has ensured that the IPCTabContext is of + // type PopupIPCTabContext, and that the opener TabParent is + // reachable. + const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext(); + auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent()); + // We must ensure that the private browsing and remoteness flags + // match those of the opener. + nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext(); + if (!loadContext) { + return nullptr; + } + + bool isPrivate; + loadContext->GetUsePrivateBrowsing(&isPrivate); + if (isPrivate) { + chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; + } + } + + // And because we're allocating a remote browser, of course the + // window is remote. + chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW; + + MaybeInvalidTabContext tc(aContext); + MOZ_ASSERT(tc.IsValid()); + TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), chromeFlags); + + // We release this ref in DeallocPBrowserParent() + NS_ADDREF(parent); + return parent; +} + +bool +nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame) +{ + TabParent* parent = TabParent::GetFrom(aFrame); + NS_RELEASE(parent); + return true; +} + +PBlobParent* +nsIContentParent::AllocPBlobParent(const BlobConstructorParams& aParams) +{ + return BlobParent::Create(this, aParams); +} + +bool +nsIContentParent::DeallocPBlobParent(PBlobParent* aActor) +{ + BlobParent::Destroy(aActor); + return true; +} + +BlobParent* +nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aBlob); + + RefPtr<BlobImpl> blobImpl = aBlob->Impl(); + MOZ_ASSERT(blobImpl); + + return GetOrCreateActorForBlobImpl(blobImpl); +} + +BlobParent* +nsIContentParent::GetOrCreateActorForBlobImpl(BlobImpl* aImpl) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aImpl); + + BlobParent* actor = BlobParent::GetOrCreate(this, aImpl); + NS_ENSURE_TRUE(actor, nullptr); + + return actor; +} + +bool +nsIContentParent::RecvSyncMessage(const nsString& aMsg, + const ClonedMessageData& aData, + InfallibleTArray<CpowEntry>&& aCpows, + const IPC::Principal& aPrincipal, + nsTArray<ipc::StructuredCloneData>* aRetvals) +{ + // FIXME Permission check in Content process + nsIPrincipal* principal = aPrincipal; + if (IsContentParent()) { + ContentParent* parent = AsContentParent(); + if (!ContentParent::IgnoreIPCPrincipal() && + parent && principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + } + + RefPtr<nsFrameMessageManager> ppm = mMessageManager; + if (ppm) { + ipc::StructuredCloneData data; + ipc::UnpackClonedMessageDataForParent(aData, data); + + CrossProcessCpowHolder cpows(this, aCpows); + ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, + aMsg, true, &data, &cpows, aPrincipal, aRetvals); + } + return true; +} + +bool +nsIContentParent::RecvRpcMessage(const nsString& aMsg, + const ClonedMessageData& aData, + InfallibleTArray<CpowEntry>&& aCpows, + const IPC::Principal& aPrincipal, + nsTArray<ipc::StructuredCloneData>* aRetvals) +{ + // FIXME Permission check in Content process + nsIPrincipal* principal = aPrincipal; + if (IsContentParent()) { + ContentParent* parent = AsContentParent(); + if (!ContentParent::IgnoreIPCPrincipal() && + parent && principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + } + + RefPtr<nsFrameMessageManager> ppm = mMessageManager; + if (ppm) { + ipc::StructuredCloneData data; + ipc::UnpackClonedMessageDataForParent(aData, data); + + CrossProcessCpowHolder cpows(this, aCpows); + ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, + aMsg, true, &data, &cpows, aPrincipal, aRetvals); + } + return true; +} + +PFileDescriptorSetParent* +nsIContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD) +{ + return new FileDescriptorSetParent(aFD); +} + +bool +nsIContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor) +{ + delete static_cast<FileDescriptorSetParent*>(aActor); + return true; +} + +PSendStreamParent* +nsIContentParent::AllocPSendStreamParent() +{ + return mozilla::ipc::AllocPSendStreamParent(); +} + +bool +nsIContentParent::DeallocPSendStreamParent(PSendStreamParent* aActor) +{ + delete aActor; + return true; +} + +bool +nsIContentParent::RecvAsyncMessage(const nsString& aMsg, + InfallibleTArray<CpowEntry>&& aCpows, + const IPC::Principal& aPrincipal, + const ClonedMessageData& aData) +{ + // FIXME Permission check in Content process + nsIPrincipal* principal = aPrincipal; + if (IsContentParent()) { + ContentParent* parent = AsContentParent(); + if (!ContentParent::IgnoreIPCPrincipal() && + parent && principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + } + + RefPtr<nsFrameMessageManager> ppm = mMessageManager; + if (ppm) { + ipc::StructuredCloneData data; + ipc::UnpackClonedMessageDataForParent(aData, data); + + CrossProcessCpowHolder cpows(this, aCpows); + ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, + aMsg, false, &data, &cpows, aPrincipal, nullptr); + } + return true; +} + +} // namespace dom +} // namespace mozilla |