gecko-dev/dom/ipc/nsIContentParent.cpp

300 lines
9.3 KiB
C++

/* -*- 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/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(xpc::GetJSRuntime());
}
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 isBrowser frames must be isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID would allow
// the content to access data it's not supposed to.
if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
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;
}
bool
nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal)
{
// 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