Bug 1331740: Pass correct context for TYPE_DOCUMENT loads within docshell. r=smaug

This commit is contained in:
Christoph Kerschbaumer 2017-09-05 18:01:07 +02:00
parent 0edfbc2d51
commit 1b8c06e845
6 changed files with 119 additions and 56 deletions

View File

@ -9976,39 +9976,26 @@ nsDocShell::InternalLoad(nsIURI* aURI,
// If there's no targetDocShell, that means we are about to create a new
// window (or aWindowTarget is empty). Perform a content policy check before
// creating the window.
if (!targetDocShell) {
nsCOMPtr<Element> requestingElement;
// creating the window. Please note for all other docshell loads
// content policy checks are performed within the contentSecurityManager
// when the channel is about to be openend.
if (!targetDocShell && !aWindowTarget.IsEmpty()) {
MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
"opening a new window requires type to be TYPE_DOCUMENT");
nsISupports* requestingContext = nullptr;
if (contentType == nsIContentPolicy::TYPE_DOCUMENT) {
if (XRE_IsContentProcess()) {
// In e10s the child process doesn't have access to the element that
// contains the browsing context (because that element is in the chrome
// process). So we just pass mScriptGlobal.
requestingContext = ToSupports(mScriptGlobal);
} else {
// This is for loading non-e10s tabs and toplevel windows of various
// sorts.
// For the toplevel window cases, requestingElement will be null.
requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal();
requestingContext = requestingElement;
}
if (XRE_IsContentProcess()) {
// In e10s the child process doesn't have access to the element that
// contains the browsing context (because that element is in the chrome
// process). So we just pass mScriptGlobal.
requestingContext = ToSupports(mScriptGlobal);
} else {
requestingElement = mScriptGlobal->AsOuter()->GetFrameElementInternal();
// This is for loading non-e10s tabs and toplevel windows of various
// sorts.
// For the toplevel window cases, requestingElement will be null.
nsCOMPtr<Element> requestingElement =
mScriptGlobal->AsOuter()->GetFrameElementInternal();
requestingContext = requestingElement;
#ifdef DEBUG
if (requestingElement) {
// Get the docshell type for requestingElement.
nsCOMPtr<nsIDocument> requestingDoc = requestingElement->OwnerDoc();
nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
// requestingElement docshell type = current docshell type.
MOZ_ASSERT(mItemType == elementDocShell->ItemType(),
"subframes should have the same docshell type as their parent");
}
#endif
}
// Since Content Policy checks are performed within docShell as well as
@ -11094,17 +11081,40 @@ nsDocShell::DoURILoad(nsIURI* aURI,
nsCOMPtr<nsINode> loadingNode;
nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
nsCOMPtr<nsIPrincipal> loadingPrincipal;
nsCOMPtr<nsISupports> topLevelLoadingContext;
if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
loadingNode = nullptr;
loadingPrincipal = nullptr;
loadingWindow = mScriptGlobal->AsOuter();
if (XRE_IsContentProcess()) {
// In e10s the child process doesn't have access to the element that
// contains the browsing context (because that element is in the chrome
// process).
nsCOMPtr<nsITabChild> tabChild = GetTabChild();
topLevelLoadingContext = ToSupports(tabChild);
} else {
// This is for loading non-e10s tabs and toplevel windows of various
// sorts.
// For the toplevel window cases, requestingElement will be null.
nsCOMPtr<Element> requestingElement =
loadingWindow->GetFrameElementInternal();
topLevelLoadingContext = requestingElement;
}
} else {
loadingWindow = nullptr;
loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
if (loadingNode) {
// If we have a loading node, then use that as our loadingPrincipal.
loadingPrincipal = loadingNode->NodePrincipal();
#ifdef DEBUG
// Get the docshell type for requestingElement.
nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc();
nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
// requestingElement docshell type = current docshell type.
MOZ_ASSERT(mItemType == elementDocShell->ItemType(),
"subframes should have the same docshell type as their parent");
#endif
} else {
// If this isn't a top-level load and mScriptGlobal's frame element is
// null, then the element got removed from the DOM while we were trying
@ -11165,7 +11175,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
nsCOMPtr<nsILoadInfo> loadInfo =
(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
new LoadInfo(loadingWindow, aTriggeringPrincipal,
new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext,
securityFlags) :
new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
securityFlags, aContentPolicyType);

View File

@ -20,6 +20,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMWindow.h"
#include "nsITabChild.h"
#include "nsIContent.h"
#include "nsIImageLoadingContent.h"
#include "nsILoadContext.h"
@ -93,8 +94,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
{
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext));
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext));
NS_ASSERTION(!requestingContext || node || window,
"Context should be a DOM node or a DOM window!");
nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(requestingContext));
NS_ASSERTION(!requestingContext || node || window || tabChild,
"Context should be a DOM node, DOM window or a tabChild!");
}
#endif

View File

@ -175,7 +175,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
nsContentPolicyType internalContentPolicyType =
aLoadInfo->InternalContentPolicyType();
nsCString mimeTypeGuess;
nsCOMPtr<nsINode> requestingContext = nullptr;
nsCOMPtr<nsISupports> requestingContext = nullptr;
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
@ -229,7 +229,7 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_DOCUMENT: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
requestingContext = aLoadInfo->ContextForTopLevelLoad();
break;
}
@ -259,10 +259,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XMLHTTPREQUEST: {
// alias nsIContentPolicy::TYPE_DATAREQUEST:
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_xml requires requestingContext of type Document");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_xml requires requestingContext of type Document");
}
#endif
// We're checking for the external TYPE_XMLHTTPREQUEST here in case
// an addon creates a request with that type.
if (internalContentPolicyType ==
@ -283,18 +286,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
"type_subrequest requires requestingContext of type Element");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
"type_subrequest requires requestingContext of type Element");
}
#endif
break;
}
case nsIContentPolicy::TYPE_DTD: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_dtd requires requestingContext of type Document");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_dtd requires requestingContext of type Document");
}
#endif
break;
}
@ -312,9 +323,13 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
mimeTypeGuess = EmptyCString();
}
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::ELEMENT_NODE,
"type_media requires requestingContext of type Element");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::ELEMENT_NODE,
"type_media requires requestingContext of type Element");
}
#endif
break;
}
@ -342,18 +357,26 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
case nsIContentPolicy::TYPE_XSLT: {
mimeTypeGuess = NS_LITERAL_CSTRING("application/xml");
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_xslt requires requestingContext of type Document");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_xslt requires requestingContext of type Document");
}
#endif
break;
}
case nsIContentPolicy::TYPE_BEACON: {
mimeTypeGuess = EmptyCString();
requestingContext = aLoadInfo->LoadingNode();
MOZ_ASSERT(!requestingContext ||
requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_beacon requires requestingContext of type Document");
#ifdef DEBUG
{
nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext);
MOZ_ASSERT(!node || node->NodeType() == nsIDOMNode::DOCUMENT_NODE,
"type_beacon requires requestingContext of type Document");
}
#endif
break;
}

View File

@ -40,6 +40,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
aTriggeringPrincipal : mLoadingPrincipal.get())
, mPrincipalToInherit(nullptr)
, mLoadingContext(do_GetWeakReference(aLoadingContext))
, mContextForTopLevelLoad(nullptr)
, mSecurityFlags(aSecurityFlags)
, mInternalContentPolicyType(aContentPolicyType)
, mTainting(LoadTainting::Basic)
@ -211,10 +212,12 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
*/
LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
nsIPrincipal* aTriggeringPrincipal,
nsISupports* aContextForTopLevelLoad,
nsSecurityFlags aSecurityFlags)
: mLoadingPrincipal(nullptr)
, mTriggeringPrincipal(aTriggeringPrincipal)
, mPrincipalToInherit(nullptr)
, mContextForTopLevelLoad(do_GetWeakReference(aContextForTopLevelLoad))
, mSecurityFlags(aSecurityFlags)
, mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT)
, mTainting(LoadTainting::Basic)
@ -276,6 +279,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
, mSandboxedLoadingPrincipal(rhs.mSandboxedLoadingPrincipal)
, mResultPrincipalURI(rhs.mResultPrincipalURI)
, mLoadingContext(rhs.mLoadingContext)
, mContextForTopLevelLoad(rhs.mContextForTopLevelLoad)
, mSecurityFlags(rhs.mSecurityFlags)
, mInternalContentPolicyType(rhs.mInternalContentPolicyType)
, mTainting(rhs.mTainting)
@ -511,6 +515,17 @@ LoadInfo::LoadingNode()
return node;
}
nsISupports*
LoadInfo::ContextForTopLevelLoad()
{
// Most likely you want to query LoadingNode() instead of
// ContextForTopLevelLoad() if this assertion fires.
MOZ_ASSERT(mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
"should only query this context for top level document loads");
nsCOMPtr<nsISupports> context = do_QueryReferent(mContextForTopLevelLoad);
return context;
}
NS_IMETHODIMP
LoadInfo::GetSecurityFlags(nsSecurityFlags* aResult)
{

View File

@ -56,10 +56,12 @@ public:
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType);
// Constructor used for TYPE_DOCUMENT loads which have no reasonable
// loadingNode or loadingPrincipal
// Constructor used for TYPE_DOCUMENT loads which have a different
// loadingContext than other loads. This ContextForTopLevelLoad is
// only used for content policy checks.
LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
nsIPrincipal* aTriggeringPrincipal,
nsISupports* aContextForTopLevelLoad,
nsSecurityFlags aSecurityFlags);
// create an exact copy of the loadinfo
@ -146,6 +148,7 @@ private:
nsCOMPtr<nsIPrincipal> mSandboxedLoadingPrincipal;
nsCOMPtr<nsIURI> mResultPrincipalURI;
nsWeakPtr mLoadingContext;
nsWeakPtr mContextForTopLevelLoad;
nsSecurityFlags mSecurityFlags;
nsContentPolicyType mInternalContentPolicyType;
LoadTainting mTainting;

View File

@ -331,6 +331,16 @@ interface nsILoadInfo : nsISupports
[noscript, notxpcom, nostdcall, binaryname(LoadingNode)]
nsINode binaryLoadingNode();
/**
* A C++ friendly version of the loadingContext for toplevel loads.
* Most likely you want to query the ownerDocument or LoadingNode
* and not this context only available for TYPE_DOCUMENT loads.
* Please note that except for loads of TYPE_DOCUMENT, this
* ContextForTopLevelLoad will always return null.
*/
[noscript, notxpcom, nostdcall, binaryname(ContextForTopLevelLoad)]
nsISupports binaryContextForTopLevelLoad();
/**
* The securityFlags of that channel.
*/