Bug 1339004 - Do DocGroup labeling in dom/security. r=smaug, r=ckerschb
MozReview-Commit-ID: 3QoH8P4J85I
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -20,16 +20,18 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMWindow.h"
#include "nsIContent.h"
#include "nsILoadContext.h"
#include "nsCOMArray.h"
#include "nsContentUtils.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
+#include "nsIContentSecurityPolicy.h"
+#include "mozilla/dom/TabGroup.h"
using mozilla::LogLevel;
NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
static mozilla::LazyLogModule gConPolLog("nsContentPolicy");
nsresult
@@ -124,16 +126,32 @@ nsContentPolicy::CheckPolicy(CPMethod
/*
* Enumerate mPolicies and ask each of them, taking the logical AND of
* their permissions.
*/
nsresult rv;
nsCOMArray<nsIContentPolicy> entries;
mPolicies.GetEntries(entries);
+
+ nsCOMPtr<nsPIDOMWindowOuter> window;
+ if (nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext)) {
+ window = node->OwnerDoc()->GetWindow();
+ } else {
+ window = do_QueryInterface(requestingContext);
+ }
+
+ if (requestPrincipal) {
+ nsCOMPtr<nsIContentSecurityPolicy> csp;
+ requestPrincipal->GetCsp(getter_AddRefs(csp));
+ if (csp && window) {
+ csp->EnsureEventTarget(window->EventTargetFor(TaskCategory::Other));
+ }
+ }
+
int32_t count = entries.Count();
for (int32_t i = 0; i < count; i++) {
/* check the appropriate policy */
// Send internal content policy type to CSP and mixed content blocker
nsContentPolicyType type = externalType;
if (mixedContentBlocker == entries[i] || cspService == entries[i]) {
type = contentType;
}
@@ -145,22 +163,16 @@ nsContentPolicy::CheckPolicy(CPMethod
if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
/* policy says no, no point continuing to check */
return NS_OK;
}
}
nsCOMPtr<nsIDOMElement> topFrameElement;
bool isTopLevel = true;
- nsCOMPtr<nsPIDOMWindowOuter> window;
- if (nsCOMPtr<nsINode> node = do_QueryInterface(requestingContext)) {
- window = node->OwnerDoc()->GetWindow();
- } else {
- window = do_QueryInterface(requestingContext);
- }
if (window) {
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
if (loadContext) {
loadContext->GetTopFrameElement(getter_AddRefs(topFrameElement));
}
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -4,16 +4,17 @@
#include "nsISerializable.idl"
#include "nsIContentPolicy.idl"
interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
interface nsIDOMDocument;
+interface nsIEventTarget;
interface nsIPrincipal;
interface nsIURI;
/**
* nsIContentSecurityPolicy
* Describes an XPCOM component used to model and enforce CSPs. Instances of
* this class may have multiple policies within them, but there should only be
* one of these per document/principal.
@@ -215,16 +216,20 @@ interface nsIContentSecurityPolicy : nsI
* Called after the CSP object is created to fill in appropriate request
* context. Either use
* * aDocument (preferred), or if no document is available, then provide
* * aPrincipal
*/
void setRequestContext(in nsIDOMDocument aDocument,
in nsIPrincipal aPrincipal);
+ /**
+ * Ensure we have a nsIEventTarget to use to label CSPReportSenderRunnable
+ */
+ [noscript] void ensureEventTarget(in nsIEventTarget aEventTarget);
/*
* Checks if a CSP requires Subresource Integrity (SRI)
* for a given nsContentPolicyType.
*/
bool requireSRIForType(in nsContentPolicyType aContentType);
/**
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -39,16 +39,19 @@
#include "nsStringStream.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/CSPReportBinding.h"
#include "mozilla/dom/CSPDictionariesBinding.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "nsINetworkInterceptController.h"
#include "nsSandboxFlags.h"
#include "nsIScriptElement.h"
+#include "nsIEventTarget.h"
+#include "mozilla/dom/DocGroup.h"
+#include "nsXULAppAPI.h"
using namespace mozilla;
static LogModule*
GetCspContextLog()
{
static LazyLogModule gCspContextPRLog("CSPContext");
return gCspContextPRLog;
@@ -660,30 +663,45 @@ nsCSPContext::SetRequestContext(nsIDOMDo
// the innerWindowID is not available for CSPs delivered through the
// header at the time setReqeustContext is called - let's queue up
// console messages until it becomes available, see flushConsoleMessages
mQueueUpMessages = !mInnerWindowID;
mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
// set the flag on the document for CSP telemetry
doc->SetHasCSP(true);
+ mEventTarget = doc->EventTargetFor(TaskCategory::Other);
}
else {
CSPCONTEXTLOG(("No Document in SetRequestContext; can not query loadgroup; sending reports may fail."));
mLoadingPrincipal = aPrincipal;
mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
// if no document is available, then it also does not make sense to queue console messages
// sending messages to the browser conolse instead of the web console in that case.
mQueueUpMessages = false;
}
NS_ASSERTION(mSelfURI, "mSelfURI not available, can not translate 'self' into actual URI");
return NS_OK;
}
+NS_IMETHODIMP
+nsCSPContext::EnsureEventTarget(nsIEventTarget* aEventTarget)
+{
+ NS_ENSURE_ARG(aEventTarget);
+ // Don't bother if we did have a valid event target (if the csp object is
+ // tied to a document in SetRequestContext)
+ if (mEventTarget) {
+ return NS_OK;
+ }
+
+ mEventTarget = aEventTarget;
+ return NS_OK;
+}
+
struct ConsoleMsgQueueElem {
nsXPIDLString mMsg;
nsString mSourceName;
nsString mSourceLine;
uint32_t mLineNumber;
uint32_t mColumnNumber;
uint32_t mSeverityFlag;
};
@@ -1159,27 +1177,40 @@ nsCSPContext::AsyncReportViolation(nsISu
uint32_t aViolatedPolicyIndex,
const nsAString& aObserverSubject,
const nsAString& aSourceFile,
const nsAString& aScriptSample,
uint32_t aLineNum)
{
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
- NS_DispatchToMainThread(new CSPReportSenderRunnable(aBlockedContentSource,
- aOriginalURI,
- aViolatedPolicyIndex,
- mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
- aViolatedDirective,
- aObserverSubject,
- aSourceFile,
- aScriptSample,
- aLineNum,
- this));
- return NS_OK;
+ nsCOMPtr<nsIRunnable> task =
+ new CSPReportSenderRunnable(aBlockedContentSource,
+ aOriginalURI,
+ aViolatedPolicyIndex,
+ mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
+ aViolatedDirective,
+ aObserverSubject,
+ aSourceFile,
+ aScriptSample,
+ aLineNum,
+ this);
+
+ if (XRE_IsContentProcess()) {
+ if (mEventTarget) {
+ if (nsCOMPtr<nsINamed> named = do_QueryInterface(task)) {
+ named->SetName("CSPReportSenderRunnable");
+ }
+ mEventTarget->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
+ return NS_OK;
+ }
+ }
+
+ NS_DispatchToMainThread(task.forget());
+ return NS_OK;
}
NS_IMETHODIMP
nsCSPContext::RequireSRIForType(nsContentPolicyType aContentType, bool* outRequiresSRIForType)
{
*outRequiresSRIForType = false;
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
if (mPolicies[i]->hasDirective(REQUIRE_SRI_FOR)) {
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -21,16 +21,17 @@
#define NS_CSPCONTEXT_CONTRACTID "@mozilla.org/cspcontext;1"
// 09d9ed1a-e5d4-4004-bfe0-27ceb923d9ac
#define NS_CSPCONTEXT_CID \
{ 0x09d9ed1a, 0xe5d4, 0x4004, \
{ 0xbf, 0xe0, 0x27, 0xce, 0xb9, 0x23, 0xd9, 0xac } }
class nsINetworkInterceptController;
+class nsIEventTarget;
struct ConsoleMsgQueueElem;
class nsCSPContext : public nsIContentSecurityPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTSECURITYPOLICY
NS_DECL_NSISERIALIZABLE
@@ -116,16 +117,17 @@ class nsCSPContext : public nsIContentSe
// to avoid memory leaks. Within the destructor of the principal we explicitly
// set mLoadingPrincipal to null.
nsIPrincipal* mLoadingPrincipal;
// helper members used to queue up web console messages till
// the windowID becomes available. see flushConsoleMessages()
nsTArray<ConsoleMsgQueueElem> mConsoleMsgQueue;
bool mQueueUpMessages;
+ nsCOMPtr<nsIEventTarget> mEventTarget;
};
// Class that listens to violation report transmission and logs errors.
class CSPViolationReportListener : public nsIStreamListener
{
public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1149,22 +1149,27 @@ private:
// However, we must still override the principal since the nsIPrincipal
// URL may be different due to same-origin redirects. Unfortunately this
// URL must exactly match the final worker script URL in order to
// properly set the referrer header on fetch/xhr requests. If bug 1340694
// is ever fixed this can be removed.
rv = mWorkerPrivate->SetPrincipalFromChannel(channel);
NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIContentSecurityPolicy> csp = mWorkerPrivate->GetCSP();
// We did inherit CSP in bug 1223647. If we do not already have a CSP, we
// should get it from the HTTP headers on the worker script.
- if (!mWorkerPrivate->GetCSP() && CSPService::sCSPEnabled) {
- rv = mWorkerPrivate->SetCSPFromHeaderValues(tCspHeaderValue,
- tCspROHeaderValue);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (CSPService::sCSPEnabled) {
+ if (!csp) {
+ rv = mWorkerPrivate->SetCSPFromHeaderValues(tCspHeaderValue,
+ tCspROHeaderValue);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ csp->EnsureEventTarget(mWorkerPrivate->MainThreadEventTarget());
+ }
}
mWorkerPrivate->SetReferrerPolicyFromHeaderValue(tRPHeaderCValue);
WorkerPrivate* parent = mWorkerPrivate->GetParent();
if (parent) {
// XHR Params Allowed
mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2636,32 +2636,48 @@ WorkerPrivateParent<Derived>::GetDocumen
}
parent = parent->GetParent();
}
// couldn't query a document, give up and return nullptr
return nullptr;
}
template <class Derived>
+void
+WorkerPrivateParent<Derived>::SetCSP(nsIContentSecurityPolicy* aCSP)
+{
+ AssertIsOnMainThread();
+ if (!aCSP) {
+ return;
+ }
+ WorkerPrivate* self = ParentAsWorkerPrivate();
+ aCSP->EnsureEventTarget(self->mMainThreadEventTarget);
+ mLoadInfo.mCSP = aCSP;
+}
+
+template <class Derived>
nsresult
WorkerPrivateParent<Derived>::SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
const nsACString& aCSPReportOnlyHeaderValue)
{
AssertIsOnMainThread();
MOZ_DIAGNOSTIC_ASSERT(!mLoadInfo.mCSP);
NS_ConvertASCIItoUTF16 cspHeaderValue(aCSPHeaderValue);
NS_ConvertASCIItoUTF16 cspROHeaderValue(aCSPReportOnlyHeaderValue);
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsresult rv = mLoadInfo.mPrincipal->EnsureCSP(nullptr, getter_AddRefs(csp));
if (!csp) {
return NS_OK;
}
+ WorkerPrivate* self = ParentAsWorkerPrivate();
+ csp->EnsureEventTarget(self->mMainThreadEventTarget);
+
// If there's a CSP header, apply it.
if (!cspHeaderValue.IsEmpty()) {
rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
NS_ENSURE_SUCCESS(rv, rv);
}
// If there's a report-only CSP header, apply it.
if (!cspROHeaderValue.IsEmpty()) {
rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -698,21 +698,17 @@ public:
nsIContentSecurityPolicy*
GetCSP() const
{
AssertIsOnMainThread();
return mLoadInfo.mCSP;
}
void
- SetCSP(nsIContentSecurityPolicy* aCSP)
- {
- AssertIsOnMainThread();
- mLoadInfo.mCSP = aCSP;
- }
+ SetCSP(nsIContentSecurityPolicy* aCSP);
nsresult
SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
const nsACString& aCSPReportOnlyHeaderValue);
void
SetReferrerPolicyFromHeaderValue(const nsACString& aReferrerPolicyHeaderValue);