Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2024-01-11 09:52:46 +08:00
commit 80c4f1d745
79 changed files with 1353 additions and 509 deletions

View file

@ -535,7 +535,8 @@ NS_IMPL_ISUPPORTS(nsScriptSecurityManager,
///////////////// Security Checks ///////////////// ///////////////// Security Checks /////////////////
bool bool
nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx) nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx,
JS::HandleValue aValue)
{ {
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal(); nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
@ -558,12 +559,23 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
} }
if (reportViolation) { if (reportViolation) {
nsAutoString fileName; JS::Rooted<JSString*> jsString(cx, JS::ToString(cx, aValue));
unsigned lineNum = 0; if (NS_WARN_IF(!jsString)) {
NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP"); JS_ClearPendingException(cx);
return false;
}
nsAutoJSString scriptSample;
if (NS_WARN_IF(!scriptSample.init(cx, jsString))) {
JS_ClearPendingException(cx);
return false;
}
JS::AutoFilename scriptFilename; JS::AutoFilename scriptFilename;
if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) { nsAutoString fileName;
unsigned lineNum = 0;
unsigned columnNum = 0;
if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum, &columnNum)) {
if (const char *file = scriptFilename.get()) { if (const char *file = scriptFilename.get()) {
CopyUTF8toUTF16(nsDependentCString(file), fileName); CopyUTF8toUTF16(nsDependentCString(file), fileName);
} }
@ -574,6 +586,7 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
fileName, fileName,
scriptSample, scriptSample,
lineNum, lineNum,
columnNum,
EmptyString(), EmptyString(),
EmptyString()); EmptyString());
} }

View file

@ -91,7 +91,7 @@ private:
// Decides, based on CSP, whether or not eval() and stuff can be executed. // Decides, based on CSP, whether or not eval() and stuff can be executed.
static bool static bool
ContentSecurityPolicyPermitsJSAction(JSContext *cx); ContentSecurityPolicyPermitsJSAction(JSContext *cx, JS::HandleValue aValue);
static bool static bool
JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second); JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second);

View file

@ -135,6 +135,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
CASE_RETURN( TYPE_INTERNAL_STYLESHEET ); CASE_RETURN( TYPE_INTERNAL_STYLESHEET );
CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD ); CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD );
CASE_RETURN( TYPE_SAVEAS_DOWNLOAD ); CASE_RETURN( TYPE_SAVEAS_DOWNLOAD );
CASE_RETURN( TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS );
default: default:
return "<Unknown Type>"; return "<Unknown Type>";
} }

View file

@ -2395,34 +2395,35 @@ nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode,
return CallQueryInterface(common, aCommonAncestor); return CallQueryInterface(common, aCommonAncestor);
} }
// static template <typename Node, typename GetParentFunc>
nsINode* static Node*
nsContentUtils::GetCommonAncestor(nsINode* aNode1, GetCommonAncestorInternal(Node* aNode1,
nsINode* aNode2) Node* aNode2,
GetParentFunc aGetParentFunc)
{ {
if (aNode1 == aNode2) { if (aNode1 == aNode2) {
return aNode1; return aNode1;
} }
// Build the chain of parents // Build the chain of parents
AutoTArray<nsINode*, 30> parents1, parents2; AutoTArray<Node*, 30> parents1, parents2;
do { do {
parents1.AppendElement(aNode1); parents1.AppendElement(aNode1);
aNode1 = aNode1->GetParentNode(); aNode1 = aGetParentFunc(aNode1);
} while (aNode1); } while (aNode1);
do { do {
parents2.AppendElement(aNode2); parents2.AppendElement(aNode2);
aNode2 = aNode2->GetParentNode(); aNode2 = aGetParentFunc(aNode2);
} while (aNode2); } while (aNode2);
// Find where the parent chain differs // Find where the parent chain differs
uint32_t pos1 = parents1.Length(); uint32_t pos1 = parents1.Length();
uint32_t pos2 = parents2.Length(); uint32_t pos2 = parents2.Length();
nsINode* parent = nullptr; Node* parent = nullptr;
uint32_t len; uint32_t len;
for (len = std::min(pos1, pos2); len > 0; --len) { for (len = std::min(pos1, pos2); len > 0; --len) {
nsINode* child1 = parents1.ElementAt(--pos1); Node* child1 = parents1.ElementAt(--pos1);
nsINode* child2 = parents2.ElementAt(--pos2); Node* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) { if (child1 != child2) {
break; break;
} }
@ -2432,6 +2433,25 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1,
return parent; return parent;
} }
/* static */
nsINode*
nsContentUtils::GetCommonAncestor(nsINode* aNode1, nsINode* aNode2)
{
return GetCommonAncestorInternal(aNode1, aNode2, [](nsINode* aNode) {
return aNode->GetParentNode();
});
}
/* static */
nsIContent*
nsContentUtils::GetCommonFlattenedTreeAncestor(nsIContent* aContent1,
nsIContent* aContent2)
{
return GetCommonAncestorInternal(aContent1, aContent2, [](nsIContent* aContent) {
return aContent->GetFlattenedTreeParent();
});
}
// static // static
nsINode* nsINode*
nsContentUtils::GetCommonAncestorUnderInteractiveContent(nsINode* aNode1, nsContentUtils::GetCommonAncestorUnderInteractiveContent(nsINode* aNode1,
@ -8595,6 +8615,7 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_INTERNAL_WORKER: case nsIContentPolicy::TYPE_INTERNAL_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
return nsIContentPolicy::TYPE_SCRIPT; return nsIContentPolicy::TYPE_SCRIPT;
case nsIContentPolicy::TYPE_INTERNAL_EMBED: case nsIContentPolicy::TYPE_INTERNAL_EMBED:

View file

@ -333,11 +333,17 @@ public:
nsIDOMNode** aCommonAncestor); nsIDOMNode** aCommonAncestor);
/** /**
* Returns the common ancestor, if any, for two nodes. Returns null if the * Returns the common ancestor, if any, for two nodes.
* nodes are disconnected. * Returns null if the nodes are disconnected.
*/ */
static nsINode* GetCommonAncestor(nsINode* aNode1, static nsINode* GetCommonAncestor(nsINode* aNode1, nsINode* aNode2);
nsINode* aNode2);
/**
* Returns the common flattened tree ancestor, if any, for two given content
* nodes.
*/
static nsIContent* GetCommonFlattenedTreeAncestor(nsIContent* aContent1,
nsIContent* aContent2);
/** /**
* Returns the common ancestor under interactive content, if any. * Returns the common ancestor under interactive content, if any.

View file

@ -11910,6 +11910,7 @@ nsIDocument::InlineScriptAllowedByCSP()
true, // aParserCreated true, // aParserCreated
EmptyString(), // FIXME get script sample (bug 1314567) EmptyString(), // FIXME get script sample (bug 1314567)
0, // aLineNumber 0, // aLineNumber
0, // aColumnNumber
&allowsInlineScript); &allowsInlineScript);
NS_ENSURE_SUCCESS(rv, true); NS_ENSURE_SUCCESS(rv, true);
} }

View file

@ -538,10 +538,8 @@ nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, nsIDOMElement* aStartElem
NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG);
window = GetCurrentWindow(startContent); window = GetCurrentWindow(startContent);
} } else {
else {
window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get(); window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get();
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
} }
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@ -867,7 +865,7 @@ nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
} }
} }
NotifyFocusStateChange(content, shouldShowFocusRing, false); NotifyFocusStateChange(content, nullptr, shouldShowFocusRing, false);
} }
return NS_OK; return NS_OK;
@ -973,6 +971,7 @@ nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow)
if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) { if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) {
NotifyFocusStateChange(oldFocusedContent, NotifyFocusStateChange(oldFocusedContent,
nullptr,
mFocusedWindow->ShouldShowFocusRing(), mFocusedWindow->ShouldShowFocusRing(),
false); false);
window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0); window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
@ -1091,12 +1090,21 @@ nsFocusManager::ParentActivated(mozIDOMWindowProxy* aWindow, bool aActive)
/* static */ /* static */
void void
nsFocusManager::NotifyFocusStateChange(nsIContent* aContent, nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
nsIContent* aContentToFocus,
bool aWindowShouldShowFocusRing, bool aWindowShouldShowFocusRing,
bool aGettingFocus) bool aGettingFocus)
{ {
MOZ_ASSERT_IF(aContentToFocus, !aGettingFocus);
if (!aContent->IsElement()) { if (!aContent->IsElement()) {
return; return;
} }
nsIContent* commonAncestor = nullptr;
if (aContentToFocus && aContentToFocus->IsElement()) {
commonAncestor =
nsContentUtils::GetCommonFlattenedTreeAncestor(aContent, aContentToFocus);
}
EventStates eventState = NS_EVENT_STATE_FOCUS; EventStates eventState = NS_EVENT_STATE_FOCUS;
if (aWindowShouldShowFocusRing) { if (aWindowShouldShowFocusRing) {
eventState |= NS_EVENT_STATE_FOCUSRING; eventState |= NS_EVENT_STATE_FOCUSRING;
@ -1108,9 +1116,18 @@ nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
aContent->AsElement()->RemoveStates(eventState); aContent->AsElement()->RemoveStates(eventState);
} }
for (Element* element = aContent->AsElement(); element; for (nsIContent* content = aContent;
element = element->GetParentElementCrossingShadowRoot()) { content && content != commonAncestor;
content = content->GetFlattenedTreeParent()) {
if (!content->IsElement()) {
continue;
}
Element* element = content->AsElement();
if (aGettingFocus) { if (aGettingFocus) {
if (element->State().HasState(NS_EVENT_STATE_FOCUS_WITHIN)) {
break;
}
element->AddStates(NS_EVENT_STATE_FOCUS_WITHIN); element->AddStates(NS_EVENT_STATE_FOCUS_WITHIN);
} else { } else {
element->RemoveStates(NS_EVENT_STATE_FOCUS_WITHIN); element->RemoveStates(NS_EVENT_STATE_FOCUS_WITHIN);
@ -1673,7 +1690,10 @@ nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear,
content && content->IsInComposedDoc() && !IsNonFocusableRoot(content); content && content->IsInComposedDoc() && !IsNonFocusableRoot(content);
if (content) { if (content) {
if (sendBlurEvent) { if (sendBlurEvent) {
NotifyFocusStateChange(content, shouldShowFocusRing, false); NotifyFocusStateChange(content,
aContentToFocus,
shouldShowFocusRing,
false);
} }
// if an object/plug-in/remote browser is being blurred, move the system focus // if an object/plug-in/remote browser is being blurred, move the system focus
@ -1921,7 +1941,10 @@ nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow,
if (aFocusChanged) if (aFocusChanged)
ScrollIntoView(presShell, aContent, aFlags); ScrollIntoView(presShell, aContent, aFlags);
NotifyFocusStateChange(aContent, aWindow->ShouldShowFocusRing(), true); NotifyFocusStateChange(aContent,
nullptr,
aWindow->ShouldShowFocusRing(),
true);
// if this is an object/plug-in/remote browser, focus its widget. Note that we might // if this is an object/plug-in/remote browser, focus its widget. Note that we might
// no longer be in the same document, due to the events we fired above when // no longer be in the same document, due to the events we fired above when

View file

@ -583,6 +583,7 @@ private:
// focus rings: in the losing focus case that information could be // focus rings: in the losing focus case that information could be
// wrong.. // wrong..
static void NotifyFocusStateChange(nsIContent* aContent, static void NotifyFocusStateChange(nsIContent* aContent,
nsIContent* aContentToFocus,
bool aWindowShouldShowFocusRing, bool aWindowShouldShowFocusRing,
bool aGettingFocus); bool aGettingFocus);

View file

@ -333,6 +333,14 @@ interface nsIContentPolicyBase : nsISupports
*/ */
const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 42; const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 42;
/**
* Indicates an importScripts() inside a worker script.
*
* This will be mapped to TYPE_SCRIPT before being passed to content policy
* implementations.
*/
const nsContentPolicyType TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS = 43;
/* When adding new content types, please update nsContentBlocker, /* When adding new content types, please update nsContentBlocker,
* NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective, * NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective,
* DoContentSecurityChecks, all nsIContentPolicy implementations, the * DoContentSecurityChecks, all nsIContentPolicy implementations, the

View file

@ -101,6 +101,19 @@ public:
* was set * was set
*/ */
virtual uint32_t GetLineNumber() = 0; virtual uint32_t GetLineNumber() = 0;
// This doesn't entirely belong here since they only make sense for
// some types of linking elements, but it's a better place than
// anywhere else.
virtual void SetColumnNumber(uint32_t aColumnNumber) = 0;
/**
* Get the column number, as previously set by SetColumnNumber.
*
* @return the column number of this element; or 1 if no column number
* was set
*/
virtual uint32_t GetColumnNumber() = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheetLinkingElement, NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheetLinkingElement,

View file

@ -9,6 +9,7 @@
#include "mozilla/Function.h" #include "mozilla/Function.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/FunctionBinding.h" #include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/ModuleScript.h" #include "mozilla/dom/ModuleScript.h"
#include "nsAXPCNativeCallContext.h" #include "nsAXPCNativeCallContext.h"
@ -52,7 +53,8 @@ public:
Function& aFunction, Function& aFunction,
nsTArray<JS::Heap<JS::Value>>&& aArguments); nsTArray<JS::Heap<JS::Value>>&& aArguments);
nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate, nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression); const nsAString& aExpression, bool* aAllowEval,
ErrorResult& aRv);
virtual const nsAString& GetHandlerText() override; virtual const nsAString& GetHandlerText() override;
@ -182,54 +184,6 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler)
static bool
CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
{
// if CSP is enabled, and setTimeout/setInterval was called with a string,
// disable the registration and log an error
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (!doc) {
// if there's no document, we don't have to do anything.
return true;
}
nsCOMPtr<nsIContentSecurityPolicy> csp;
aError = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
if (aError.Failed()) {
return false;
}
if (!csp) {
return true;
}
bool allowsEval = true;
bool reportViolation = false;
aError = csp->GetAllowsEval(&reportViolation, &allowsEval);
if (aError.Failed()) {
return false;
}
if (reportViolation) {
// TODO : need actual script sample in violation report.
NS_NAMED_LITERAL_STRING(scriptSample,
"call to eval() or related function blocked by CSP");
// Get the calling location.
uint32_t lineNum = 0;
nsAutoString fileNameString;
if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
fileNameString.AssignLiteral("unknown");
}
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
fileNameString, scriptSample, lineNum,
EmptyString(), EmptyString());
}
return allowsEval;
}
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler() nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
: mLineNo(0) : mLineNo(0)
, mColumn(0) , mColumn(0)
@ -273,8 +227,9 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
return; return;
} }
*aAllowEval = CheckCSPForEval(aCx, aWindow, aError); aError = CSPEvalChecker::CheckForWindow(aCx, aWindow, aExpression,
if (aError.Failed() || !*aAllowEval) { aAllowEval);
if (NS_WARN_IF(aError.Failed()) || !*aAllowEval) {
return; return;
} }
@ -297,7 +252,9 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx, nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
WorkerPrivate* aWorkerPrivate, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression) const nsAString& aExpression,
bool* aAllowEval,
ErrorResult& aError)
: mLineNo(0) : mLineNo(0)
, mColumn(0) , mColumn(0)
, mExpr(aExpression) , mExpr(aExpression)
@ -305,6 +262,12 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
MOZ_ASSERT(aWorkerPrivate); MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread(); aWorkerPrivate->AssertIsOnWorkerThread();
aError = CSPEvalChecker::CheckForWorker(aCx, aWorkerPrivate, aExpression,
aAllowEval);
if (NS_WARN_IF(aError.Failed()) || !*aAllowEval) {
return;
}
Init(aCx); Init(aCx);
} }
@ -399,9 +362,15 @@ NS_CreateJSTimeoutHandler(JSContext *aCx, WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIScriptTimeoutHandler> already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate, NS_CreateJSTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression) const nsAString& aExpression, ErrorResult& aRv)
{ {
bool allowEval = false;
RefPtr<nsJSScriptTimeoutHandler> handler = RefPtr<nsJSScriptTimeoutHandler> handler =
new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aExpression); new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aExpression, &allowEval,
aRv);
if (aRv.Failed() || !allowEval) {
return nullptr;
}
return handler.forget(); return handler.forget();
} }

View file

@ -40,6 +40,7 @@ nsStyleLinkElement::nsStyleLinkElement()
: mDontLoadStyle(false) : mDontLoadStyle(false)
, mUpdatesEnabled(true) , mUpdatesEnabled(true)
, mLineNumber(1) , mLineNumber(1)
, mColumnNumber(1)
{ {
} }
@ -127,6 +128,18 @@ nsStyleLinkElement::GetLineNumber()
return mLineNumber; return mLineNumber;
} }
/* virtual */ void
nsStyleLinkElement::SetColumnNumber(uint32_t aColumnNumber)
{
mColumnNumber = aColumnNumber;
}
/* virtual */ uint32_t
nsStyleLinkElement::GetColumnNumber()
{
return mColumnNumber;
}
/* static */ bool /* static */ bool
nsStyleLinkElement::IsImportEnabled() nsStyleLinkElement::IsImportEnabled()
{ {
@ -412,8 +425,10 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent, if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
thisContent->NodePrincipal(), thisContent->NodePrincipal(),
doc->GetDocumentURI(), doc->GetDocumentURI(),
mLineNumber, text, &rv)) mLineNumber, mColumnNumber, text,
&rv)) {
return rv; return rv;
}
// Parse the style sheet. // Parse the style sheet.
rv = doc->CSSLoader()-> rv = doc->CSSLoader()->

View file

@ -54,6 +54,8 @@ public:
virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override; virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
virtual void SetLineNumber(uint32_t aLineNumber) override; virtual void SetLineNumber(uint32_t aLineNumber) override;
virtual uint32_t GetLineNumber() override; virtual uint32_t GetLineNumber() override;
void SetColumnNumber(uint32_t aColumnNumber) override;
uint32_t GetColumnNumber() override;
enum RelValue { enum RelValue {
ePREFETCH = 0x00000001, ePREFETCH = 0x00000001,
@ -140,6 +142,7 @@ protected:
bool mDontLoadStyle; bool mDontLoadStyle;
bool mUpdatesEnabled; bool mUpdatesEnabled;
uint32_t mLineNumber; uint32_t mLineNumber;
uint32_t mColumnNumber;
}; };
#endif /* nsStyleLinkElement_h___ */ #endif /* nsStyleLinkElement_h___ */

View file

@ -191,7 +191,7 @@ nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
if (!isNativeAnon && if (!isNativeAnon &&
!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(), !nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(),
doc->GetDocumentURI(), 0, aValue, doc->GetDocumentURI(), 0, 0, aValue,
nullptr)) nullptr))
return; return;

View file

@ -34,7 +34,7 @@ namespace db {
const int32_t kFirstShippedSchemaVersion = 15; const int32_t kFirstShippedSchemaVersion = 15;
namespace { namespace {
// Update this whenever the DB schema is changed. // Update this whenever the DB schema is changed.
const int32_t kLatestSchemaVersion = 24; const int32_t kLatestSchemaVersion = 25;
// --------- // ---------
// The following constants define the SQL schema. These are defined in the // The following constants define the SQL schema. These are defined in the
// same order the SQL should be executed in CreateOrMigrateSchema(). They are // same order the SQL should be executed in CreateOrMigrateSchema(). They are
@ -287,7 +287,8 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 &&
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET == 39 && nsIContentPolicy::TYPE_INTERNAL_STYLESHEET == 39 &&
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD == 40 && nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD == 40 &&
nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON == 41 && nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON == 41 &&
nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD == 42, nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD == 42 &&
nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS == 43,
"nsContentPolicyType values are as expected"); "nsContentPolicyType values are as expected");
namespace { namespace {
@ -2478,6 +2479,7 @@ nsresult MigrateFrom20To21(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema); nsresult MigrateFrom21To22(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema); nsresult MigrateFrom22To23(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema); nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema);
nsresult MigrateFrom24To25(mozIStorageConnection* aConn, bool& aRewriteSchema);
// Configure migration functions to run for the given starting version. // Configure migration functions to run for the given starting version.
Migration sMigrationList[] = { Migration sMigrationList[] = {
Migration(15, MigrateFrom15To16), Migration(15, MigrateFrom15To16),
@ -2489,6 +2491,7 @@ Migration sMigrationList[] = {
Migration(21, MigrateFrom21To22), Migration(21, MigrateFrom21To22),
Migration(22, MigrateFrom22To23), Migration(22, MigrateFrom22To23),
Migration(23, MigrateFrom23To24), Migration(23, MigrateFrom23To24),
Migration(24, MigrateFrom24To25),
}; };
uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration); uint32_t sMigrationListLength = sizeof(sMigrationList) / sizeof(Migration);
nsresult nsresult
@ -3013,6 +3016,17 @@ nsresult MigrateFrom23To24(mozIStorageConnection* aConn, bool& aRewriteSchema)
return rv; return rv;
} }
nsresult MigrateFrom24To25(mozIStorageConnection* aConn, bool& aRewriteSchema)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(aConn);
// The only change between 24 and 25 was a new nsIContentPolicy type.
nsresult rv = aConn->SetSchemaVersion(25);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
return rv;
}
} // anonymous namespace } // anonymous namespace
} // namespace db } // namespace db
} // namespace cache } // namespace cache

View file

@ -598,7 +598,7 @@ private:
innerID = NS_LITERAL_STRING("ServiceWorker"); innerID = NS_LITERAL_STRING("ServiceWorker");
// Use scope as ID so the webconsole can decide if the message should // Use scope as ID so the webconsole can decide if the message should
// show up per tab // show up per tab
id.AssignWithConversion(mWorkerPrivate->WorkerName()); id.AssignWithConversion(mWorkerPrivate->ServiceWorkerScope());
} else { } else {
innerID = NS_LITERAL_STRING("Worker"); innerID = NS_LITERAL_STRING("Worker");
} }

View file

@ -787,28 +787,22 @@ EventListenerManager::SetEventHandler(nsIAtom* aName,
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp)); rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (csp) { unsigned lineNum = 0;
// let's generate a script sample and pass it as aContent, unsigned columnNum = 0;
// it will not match the hash, but allows us to pass
// the script sample in aContent.
nsAutoString scriptSample, attr, tagName(NS_LITERAL_STRING("UNKNOWN"));
aName->ToString(attr);
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mTarget));
if (domNode) {
domNode->GetNodeName(tagName);
}
// build a "script sample" based on what we know about this element
scriptSample.Assign(attr);
scriptSample.AppendLiteral(" attribute on ");
scriptSample.Append(tagName);
scriptSample.AppendLiteral(" element");
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx && !JS::DescribeScriptedCaller(cx, nullptr, &lineNum, &columnNum)) {
JS_ClearPendingException(cx);
}
if (csp) {
bool allowsInlineScript = true; bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT, rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce EmptyString(), // aNonce
true, // aParserCreated (true because attribute event handler) true, // aParserCreated (true because attribute event handler)
scriptSample, aBody,
0, // aLineNumber lineNum, // aLineNumber
columnNum, // aColumnNumber
&allowsInlineScript); &allowsInlineScript);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

View file

@ -4849,48 +4849,13 @@ GetLabelTarget(nsIContent* aPossibleLabel)
return label->GetLabeledElement(); return label->GetLabeledElement();
} }
static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2) static nsIContent*
FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
{ {
// Find closest common ancestor if (!aNode1 || !aNode2) {
if (aNode1 && aNode2) { return nullptr;
// Find the nearest common ancestor by counting the distance to the
// root and then walking up again, in pairs.
int32_t offset = 0;
nsIContent *anc1 = aNode1;
for (;;) {
++offset;
nsIContent* parent = anc1->GetFlattenedTreeParent();
if (!parent)
break;
anc1 = parent;
}
nsIContent *anc2 = aNode2;
for (;;) {
--offset;
nsIContent* parent = anc2->GetFlattenedTreeParent();
if (!parent)
break;
anc2 = parent;
}
if (anc1 == anc2) {
anc1 = aNode1;
anc2 = aNode2;
while (offset > 0) {
anc1 = anc1->GetFlattenedTreeParent();
--offset;
}
while (offset < 0) {
anc2 = anc2->GetFlattenedTreeParent();
++offset;
}
while (anc1 != anc2) {
anc1 = anc1->GetFlattenedTreeParent();
anc2 = anc2->GetFlattenedTreeParent();
}
return anc1;
}
} }
return nullptr; return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
} }
/* static */ /* static */

View file

@ -710,7 +710,7 @@ WorkerFetchResolver::FlushConsoleReport()
return; return;
} }
swm->FlushReportsToAllClients(worker->WorkerName(), mReporter); swm->FlushReportsToAllClients(worker->ServiceWorkerScope(), mReporter);
return; return;
} }

View file

@ -12,7 +12,6 @@
#include "nsIOutputStream.h" #include "nsIOutputStream.h"
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsIThreadRetargetableRequest.h" #include "nsIThreadRetargetableRequest.h"
#include "nsIUploadChannel2.h" #include "nsIUploadChannel2.h"
@ -449,38 +448,6 @@ FetchDriver::FailWithNetworkError()
mChannel = nullptr; mChannel = nullptr;
} }
namespace {
class FillResponseHeaders final : public nsIHttpHeaderVisitor {
InternalResponse* mResponse;
~FillResponseHeaders()
{ }
public:
NS_DECL_ISUPPORTS
explicit FillResponseHeaders(InternalResponse* aResponse)
: mResponse(aResponse)
{
}
NS_IMETHOD
VisitHeader(const nsACString & aHeader, const nsACString & aValue) override
{
ErrorResult result;
mResponse->Headers()->Append(aHeader, aValue, result);
if (result.Failed()) {
NS_WARNING(nsPrintfCString("Fetch ignoring illegal header - '%s': '%s'",
PromiseFlatCString(aHeader).get(),
PromiseFlatCString(aValue).get()).get());
result.SuppressException();
}
return NS_OK;
}
};
NS_IMPL_ISUPPORTS(FillResponseHeaders, nsIHttpHeaderVisitor)
} // namespace
NS_IMETHODIMP NS_IMETHODIMP
FetchDriver::OnStartRequest(nsIRequest* aRequest, FetchDriver::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext) nsISupports* aContext)
@ -540,11 +507,7 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
response = new InternalResponse(responseStatus, statusText, response = new InternalResponse(responseStatus, statusText,
mRequest->GetCredentialsMode()); mRequest->GetCredentialsMode());
RefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response); response->Headers()->FillResponseHeaders(httpChannel);
rv = httpChannel->VisitResponseHeaders(visitor);
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_WARNING("Failed to visit all headers.");
}
// If Content-Encoding or Transfer-Encoding headers are set, then the actual // If Content-Encoding or Transfer-Encoding headers are set, then the actual
// Content-Length (which refer to the decoded data) is obscured behind the encodings. // Content-Length (which refer to the decoded data) is obscured behind the encodings.

View file

@ -11,6 +11,7 @@
#include "nsCharSeparatedTokenizer.h" #include "nsCharSeparatedTokenizer.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
@ -478,6 +479,48 @@ InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aR
} }
} }
namespace {
class FillHeaders final : public nsIHttpHeaderVisitor
{
RefPtr<InternalHeaders> mInternalHeaders;
~FillHeaders() = default;
public:
NS_DECL_ISUPPORTS
explicit FillHeaders(InternalHeaders* aInternalHeaders)
: mInternalHeaders(aInternalHeaders)
{
MOZ_DIAGNOSTIC_ASSERT(mInternalHeaders);
}
NS_IMETHOD
VisitHeader(const nsACString& aHeader, const nsACString& aValue) override
{
IgnoredErrorResult result;
mInternalHeaders->Append(aHeader, aValue, result);
return NS_OK;
}
};
NS_IMPL_ISUPPORTS(FillHeaders, nsIHttpHeaderVisitor)
} // namespace
void
InternalHeaders::FillResponseHeaders(nsIRequest* aRequest)
{
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
if (!httpChannel) {
return;
}
RefPtr<FillHeaders> visitor = new FillHeaders(this);
httpChannel->VisitResponseHeaders(visitor);
}
bool bool
InternalHeaders::HasOnlySimpleHeaders() const InternalHeaders::HasOnlySimpleHeaders() const
{ {

View file

@ -114,6 +114,7 @@ public:
void Fill(const InternalHeaders& aInit, ErrorResult& aRv); void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv); void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv); void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv);
void FillResponseHeaders(nsIRequest* aRequest);
bool HasOnlySimpleHeaders() const; bool HasOnlySimpleHeaders() const;

View file

@ -234,6 +234,7 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD: case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD:
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
context = RequestContext::Script; context = RequestContext::Script;
break; break;
case nsIContentPolicy::TYPE_INTERNAL_WORKER: case nsIContentPolicy::TYPE_INTERNAL_WORKER:

View file

@ -6,11 +6,9 @@
#include "nsIContentPolicy.idl" #include "nsIContentPolicy.idl"
interface nsIURI; interface nsIURI;
interface nsIChannel;
interface nsIDocShell; interface nsIDocShell;
interface nsIDOMDocument; interface nsIDOMDocument;
interface nsIPrincipal; interface nsIPrincipal;
interface nsIURI;
/** /**
* nsIContentSecurityPolicy * nsIContentSecurityPolicy
@ -142,6 +140,8 @@ interface nsIContentSecurityPolicy : nsISerializable
* (and compare to the hashes listed in the policy) * (and compare to the hashes listed in the policy)
* @param aLineNumber The line number of the inline resource * @param aLineNumber The line number of the inline resource
* (used for reporting) * (used for reporting)
* @param aColumnNumber The column number of the inline resource
* (used for reporting)
* @return * @return
* Whether or not the effects of the inline style should be allowed * Whether or not the effects of the inline style should be allowed
* (block the rules if false). * (block the rules if false).
@ -150,7 +150,8 @@ interface nsIContentSecurityPolicy : nsISerializable
in AString aNonce, in AString aNonce,
in boolean aParserCreated, in boolean aParserCreated,
in AString aContent, in AString aContent,
in unsigned long aLineNumber); in unsigned long aLineNumber,
in unsigned long aColumnNumber);
/** /**
* whether this policy allows eval and eval-like functions * whether this policy allows eval and eval-like functions
@ -190,6 +191,8 @@ interface nsIContentSecurityPolicy : nsISerializable
* sample of the violating content (to aid debugging) * sample of the violating content (to aid debugging)
* @param lineNum * @param lineNum
* source line number of the violation (if available) * source line number of the violation (if available)
* @param columnNum
* source column number of the violation (if available)
* @param aNonce * @param aNonce
* (optional) If this is a nonce violation, include the nonce so we can * (optional) If this is a nonce violation, include the nonce so we can
* recheck to determine which policies were violated and send the * recheck to determine which policies were violated and send the
@ -204,6 +207,7 @@ interface nsIContentSecurityPolicy : nsISerializable
in AString sourceFile, in AString sourceFile,
in AString scriptSample, in AString scriptSample,
in int32_t lineNum, in int32_t lineNum,
in int32_t columnNum,
[optional] in AString nonce, [optional] in AString nonce,
[optional] in AString content); [optional] in AString content);

View file

@ -185,6 +185,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
true, // aParserCreated true, // aParserCreated
EmptyString(), // aContent EmptyString(), // aContent
0, // aLineNumber 0, // aLineNumber
0, // aColumnNumber
&allowsInlineScript); &allowsInlineScript);
//return early if inline scripts are not allowed //return early if inline scripts are not allowed

View file

@ -224,7 +224,7 @@ ServiceWorkerScopePathMismatch=Failed to register a ServiceWorker: The path of t
# LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker, %2$S is a stringified numeric HTTP status code like "404" and %3$S is a URL. # LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker, %2$S is a stringified numeric HTTP status code like "404" and %3$S is a URL.
ServiceWorkerRegisterNetworkError=Failed to register/update a ServiceWorker for scope ‘%1$S’: Load failed with status %2$S for script ‘%3$S’. ServiceWorkerRegisterNetworkError=Failed to register/update a ServiceWorker for scope ‘%1$S’: Load failed with status %2$S for script ‘%3$S’.
# LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker, %2$S is a MIME Media Type like "text/plain" and %3$S is a URL. # LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker, %2$S is a MIME Media Type like "text/plain" and %3$S is a URL.
ServiceWorkerRegisterMimeTypeError=Failed to register/update a ServiceWorker for scope ‘%1$S’: Bad Content-Type of ‘%2$S’ received for script ‘%3$S’. Must be ‘text/javascript’, ‘application/x-javascript’, or ‘application/javascript’. ServiceWorkerRegisterMimeTypeError2=Failed to register/update a ServiceWorker for scope ‘%1$S’: Bad Content-Type of ‘%2$S’ received for script ‘%3$S’. Must be ‘text/javascript’, ‘application/x-javascript’, or ‘application/javascript’.
# LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker. # LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker.
ServiceWorkerGraceTimeoutTermination=Terminating ServiceWorker for scope ‘%1$S’ with pending waitUntil/respondWith promises because of grace timeout. ServiceWorkerGraceTimeoutTermination=Terminating ServiceWorker for scope ‘%1$S’ with pending waitUntil/respondWith promises because of grace timeout.
ExecCommandCutCopyDeniedNotInputDriven=document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler. ExecCommandCutCopyDeniedNotInputDriven=document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler.

View file

@ -112,10 +112,6 @@ couldntParsePort = Couldn’t parse port in %1$S
# LOCALIZATION NOTE (duplicateDirective): # LOCALIZATION NOTE (duplicateDirective):
# %1$S is the name of the duplicate directive # %1$S is the name of the duplicate directive
duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored. duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored.
# LOCALIZATION NOTE (deprecatedChildSrcDirective):
# %1$S is the value of the deprecated directive.
# Do not localize: worker-src, frame-src
deprecatedChildSrcDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘worker-src’ to control workers, or directive ‘frame-src’ to control frames respectively.
# LOCALIZATION NOTE (couldntParseInvalidSandboxFlag): # LOCALIZATION NOTE (couldntParseInvalidSandboxFlag):
# %1$S is the option that could not be understood # %1$S is the option that could not be understood
couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’ couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’

View file

@ -82,6 +82,8 @@ MimeTypeMismatch=The resource from “%1$S” was blocked due to MIME type misma
XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”? XCTOHeaderValueMissing=X-Content-Type-Options header warning: value was “%1$S”; did you mean to send “nosniff”?
BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type. BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type.
# LOCALIZATION NOTE: Do not translate "importScripts()"
BlockImportScriptsWithWrongMimeType=Loading script from “%1$S” with importScripts() was blocked because of a disallowed MIME type.
# LOCALIZATION NOTE: Do not translate "data: URI". # LOCALIZATION NOTE: Do not translate "data: URI".
BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”) BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)

View file

@ -1474,6 +1474,7 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT, rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
nonce, parserCreated, scriptText, nonce, parserCreated, scriptText,
aElement->GetScriptLineNumber(), aElement->GetScriptLineNumber(),
aElement->GetScriptColumnNumber(),
&allowInlineScript); &allowInlineScript);
return allowInlineScript; return allowInlineScript;
} }
@ -2695,10 +2696,11 @@ ScriptLoader::VerifySRI(ScriptLoadRequest* aRequest,
nsAutoCString violationURISpec; nsAutoCString violationURISpec;
mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec); mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
uint32_t lineNo = aRequest->Element() ? aRequest->Element()->GetScriptLineNumber() : 0; uint32_t lineNo = aRequest->Element() ? aRequest->Element()->GetScriptLineNumber() : 0;
uint32_t columnNo = aRequest->Element() ? aRequest->Element()->GetScriptColumnNumber() : 0;
csp->LogViolationDetails( csp->LogViolationDetails(
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT, nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
NS_ConvertUTF8toUTF16(violationURISpec), NS_ConvertUTF8toUTF16(violationURISpec),
EmptyString(), lineNo, EmptyString(), EmptyString()); EmptyString(), lineNo, columnNo, EmptyString(), EmptyString());
rv = NS_ERROR_SRI_CORRUPT; rv = NS_ERROR_SRI_CORRUPT;
} }
} }

View file

@ -30,6 +30,7 @@ public:
explicit nsIScriptElement(mozilla::dom::FromParser aFromParser) explicit nsIScriptElement(mozilla::dom::FromParser aFromParser)
: mLineNumber(1), : mLineNumber(1),
mColumnNumber(1),
mAlreadyStarted(false), mAlreadyStarted(false),
mMalformed(false), mMalformed(false),
mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER || mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
@ -138,6 +139,16 @@ public:
return mLineNumber; return mLineNumber;
} }
void SetScriptColumnNumber(uint32_t aColumnNumber)
{
mColumnNumber = aColumnNumber;
}
uint32_t GetScriptColumnNumber()
{
return mColumnNumber;
}
void SetIsMalformed() void SetIsMalformed()
{ {
mMalformed = true; mMalformed = true;
@ -281,6 +292,11 @@ protected:
*/ */
uint32_t mLineNumber; uint32_t mLineNumber;
/**
* The start column number of the script.
*/
uint32_t mColumnNumber;
/** /**
* The "already started" flag per HTML5. * The "already started" flag per HTML5.
*/ */

View file

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/ErrorResult.h"
#include "nsGlobalWindow.h"
#include "nsIDocument.h"
#include "nsCOMPtr.h"
#include "nsJSUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
namespace {
nsresult
CheckInternal(nsIContentSecurityPolicy* aCSP,
const nsAString& aExpression,
const nsAString& aFileNameString,
uint32_t aLineNum,
uint32_t aColumnNum,
bool* aAllowed)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aAllowed);
// The value is set at any "return", but better to have a default value here.
*aAllowed = false;
if (!aCSP) {
*aAllowed = true;
return NS_OK;
}
bool reportViolation = false;
nsresult rv = aCSP->GetAllowsEval(&reportViolation, aAllowed);
if (NS_WARN_IF(NS_FAILED(rv))) {
*aAllowed = false;
return rv;
}
if (reportViolation) {
aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
aFileNameString, aExpression, aLineNum,
aColumnNum, EmptyString(), EmptyString());
}
return NS_OK;
}
class WorkerCSPCheckRunnable final : public WorkerMainThreadRunnable
{
public:
WorkerCSPCheckRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression,
const nsAString& aFileNameString,
uint32_t aLineNum,
uint32_t aColumnNum)
: WorkerMainThreadRunnable(aWorkerPrivate,
NS_LITERAL_CSTRING("CSP Eval Check"))
, mExpression(aExpression)
, mFileNameString(aFileNameString)
, mLineNum(aLineNum)
, mColumnNum(aColumnNum)
, mEvalAllowed(false)
{}
bool
MainThreadRun() override
{
mResult = CheckInternal(mWorkerPrivate->GetCSP(), mExpression,
mFileNameString, mLineNum, mColumnNum,
&mEvalAllowed);
return true;
}
nsresult
GetResult(bool* aAllowed)
{
MOZ_ASSERT(aAllowed);
*aAllowed = mEvalAllowed;
return mResult;
}
private:
const nsString mExpression;
const nsString mFileNameString;
const uint32_t mLineNum;
const uint32_t mColumnNum;
bool mEvalAllowed;
nsresult mResult;
};
} // anonymous
/* static */ nsresult
CSPEvalChecker::CheckForWindow(JSContext* aCx, nsGlobalWindow* aWindow,
const nsAString& aExpression, bool* aAllowEval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aAllowEval);
// The value is set at any "return", but better to have a default value here.
*aAllowEval = false;
// if CSP is enabled, and setTimeout/setInterval was called with a string,
// disable the registration and log an error
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (!doc) {
// if there's no document, we don't have to do anything.
*aAllowEval = true;
return NS_OK;
}
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsresult rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
if (NS_WARN_IF(NS_FAILED(rv))) {
*aAllowEval = false;
return rv;
}
// Get the calling location.
uint32_t lineNum = 0;
uint32_t columnNum = 0;
nsAutoString fileNameString;
if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
&columnNum)) {
fileNameString.AssignLiteral("unknown");
}
rv = CheckInternal(csp, aExpression, fileNameString, lineNum, columnNum,
aAllowEval);
if (NS_WARN_IF(NS_FAILED(rv))) {
*aAllowEval = false;
return rv;
}
return NS_OK;
}
/* static */ nsresult
CSPEvalChecker::CheckForWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression, bool* aAllowEval)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aAllowEval);
// The value is set at any "return", but better to have a default value here.
*aAllowEval = false;
// Get the calling location.
uint32_t lineNum = 0;
uint32_t columnNum = 0;
nsAutoString fileNameString;
if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
&columnNum)) {
fileNameString.AssignLiteral("unknown");
}
RefPtr<WorkerCSPCheckRunnable> r =
new WorkerCSPCheckRunnable(aWorkerPrivate, aExpression, fileNameString,
lineNum, columnNum);
ErrorResult error;
r->Dispatch(Canceling, error);
if (NS_WARN_IF(error.Failed())) {
*aAllowEval = false;
return error.StealNSResult();
}
nsresult rv = r->GetResult(aAllowEval);
if (NS_WARN_IF(NS_FAILED(rv))) {
*aAllowEval = false;
return rv;
}
return NS_OK;
}

View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_dom_CSPEvalChecker_h
#define mozilla_dom_CSPEvalChecker_h
#include "nsString.h"
struct JSContext;
class nsGlobalWindow;
namespace mozilla {
namespace dom {
namespace workers {
class WorkerPrivate;
}
using namespace mozilla::dom::workers;
class CSPEvalChecker final
{
public:
static nsresult
CheckForWindow(JSContext* aCx, nsGlobalWindow* aWindow,
const nsAString& aExpression, bool* aAllowEval);
static nsresult
CheckForWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression, bool* aAllowEval);
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_CSPEvalChecker_h

View file

@ -7,6 +7,7 @@ TEST_DIRS += ['test']
EXPORTS.mozilla.dom += [ EXPORTS.mozilla.dom += [
'ContentVerifier.h', 'ContentVerifier.h',
'CSPEvalChecker.h',
'nsContentSecurityManager.h', 'nsContentSecurityManager.h',
'nsCSPContext.h', 'nsCSPContext.h',
'nsCSPService.h', 'nsCSPService.h',
@ -24,6 +25,7 @@ EXPORTS += [
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [
'ContentVerifier.cpp', 'ContentVerifier.cpp',
'CSPEvalChecker.cpp',
'nsContentSecurityManager.cpp', 'nsContentSecurityManager.cpp',
'nsCSPContext.cpp', 'nsCSPContext.cpp',
'nsCSPParser.cpp', 'nsCSPParser.cpp',
@ -39,6 +41,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul' FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/caps', '/caps',
'/dom/base',
'/netwerk/base', '/netwerk/base',
] ]

View file

@ -3,6 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <string>
#include <unordered_set>
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsContentPolicyUtils.h" #include "nsContentPolicyUtils.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
@ -37,6 +40,7 @@
#include "nsScriptSecurityManager.h" #include "nsScriptSecurityManager.h"
#include "nsStringStream.h" #include "nsStringStream.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/CSPReportBinding.h" #include "mozilla/dom/CSPReportBinding.h"
#include "mozilla/dom/CSPDictionariesBinding.h" #include "mozilla/dom/CSPDictionariesBinding.h"
#include "mozilla/net/ReferrerPolicy.h" #include "mozilla/net/ReferrerPolicy.h"
@ -58,6 +62,29 @@ GetCspContextLog()
static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512; static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512;
#ifdef DEBUG
/**
* This function is only used for verification purposes within
* GatherSecurityPolicyViolationEventData.
*/
static bool
ValidateDirectiveName(const nsAString& aDirective)
{
static const auto directives = [] () {
std::unordered_set<std::string> directives;
constexpr size_t dirLen = sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]);
for (size_t i = 0; i < dirLen; ++i) {
directives.insert(CSPStrDirectives[i]);
}
return directives;
} ();
nsAutoString directive(aDirective);
auto itr = directives.find(NS_ConvertUTF16toUTF8(directive).get());
return itr != directives.end();
}
#endif // DEBUG
/** /**
* Creates a key for use in the ShouldLoad cache. * Creates a key for use in the ShouldLoad cache.
* Looks like: <uri>!<nsIContentPolicy::LOAD_TYPE> * Looks like: <uri>!<nsIContentPolicy::LOAD_TYPE>
@ -237,15 +264,25 @@ nsCSPContext::permitsInternal(CSPDirective aDir,
// decision may be wrong due to the inability to get the nonce, and will // decision may be wrong due to the inability to get the nonce, and will
// incorrectly fail the unit tests. // incorrectly fail the unit tests.
if (!aIsPreload && aSendViolationReports) { if (!aIsPreload && aSendViolationReports) {
uint32_t lineNumber = 0;
uint32_t columnNumber = 0;
nsAutoCString spec;
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
nsJSUtils::GetCallingLocation(cx, spec, &lineNumber, &columnNumber);
// If GetCallingLocation fails linenumber & columnNumber are set to 0
// anyway so we can skip checking if that is the case.
}
this->AsyncReportViolation((aSendContentLocationInViolationReports ? this->AsyncReportViolation((aSendContentLocationInViolationReports ?
aContentLocation : nullptr), aContentLocation : nullptr),
aOriginalURI, /* in case of redirect originalURI is not null */ aOriginalURI, /* in case of redirect originalURI is not null */
violatedDirective, violatedDirective,
p, /* policy index */ p, /* policy index */
EmptyString(), /* no observer subject */ EmptyString(), /* no observer subject */
EmptyString(), /* no source file */ NS_ConvertUTF8toUTF16(spec), /* source file. */
EmptyString(), /* no script sample */ EmptyString(), /* no script sample */
0); /* no line number */ lineNumber, /* line number */
columnNumber); /* column number */
} }
} }
} }
@ -266,12 +303,22 @@ NS_IMPL_ISUPPORTS_CI(nsCSPContext,
nsIContentSecurityPolicy, nsIContentSecurityPolicy,
nsISerializable) nsISerializable)
int32_t nsCSPContext::sScriptSampleMaxLength;
nsCSPContext::nsCSPContext() nsCSPContext::nsCSPContext()
: mInnerWindowID(0) : mInnerWindowID(0)
, mLoadingContext(nullptr) , mLoadingContext(nullptr)
, mLoadingPrincipal(nullptr) , mLoadingPrincipal(nullptr)
, mQueueUpMessages(true) , mQueueUpMessages(true)
{ {
static bool sInitialized = false;
if (!sInitialized) {
Preferences::AddIntVarCache(&sScriptSampleMaxLength,
"security.csp.reporting.script-sample.max-length",
40);
sInitialized = true;
}
CSPCONTEXTLOG(("nsCSPContext::nsCSPContext")); CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
} }
@ -444,7 +491,8 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
const nsAString& aContent, const nsAString& aContent,
const nsAString& aViolatedDirective, const nsAString& aViolatedDirective,
uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
nsString observerSubject; nsString observerSubject;
// if the nonce is non empty, then we report the nonce error, otherwise // if the nonce is non empty, then we report the nonce error, otherwise
@ -463,7 +511,7 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
if (selfICString) { if (selfICString) {
selfICString->SetData(nsDependentCString("self")); selfICString->SetData(nsDependentCString("inline"));
} }
nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString)); nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
@ -474,11 +522,27 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
} }
nsAutoString codeSample(aContent); nsAutoString codeSample(aContent);
// cap the length of the script sample at 40 chars // cap the length of the script sample
if (codeSample.Length() > 40) { if (codeSample.Length() > ScriptSampleMaxLength()) {
codeSample.Truncate(40); codeSample.Truncate(ScriptSampleMaxLength());
codeSample.AppendLiteral("..."); codeSample.AppendLiteral("...");
} }
uint32_t lineNumber = aLineNumber;
uint32_t columnNumber = aColumnNumber;
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
if (!nsJSUtils::GetCallingLocation(cx, sourceFile, &lineNumber,
&columnNumber)) {
// Get Calling Location resets line/col to 0
// so we reset those to the intial arguments
// in case it failed
lineNumber = aLineNumber;
columnNumber = aColumnNumber;
}
}
AsyncReportViolation(selfISupports, // aBlockedContentSource AsyncReportViolation(selfISupports, // aBlockedContentSource
mSelfURI, // aOriginalURI mSelfURI, // aOriginalURI
aViolatedDirective, // aViolatedDirective aViolatedDirective, // aViolatedDirective
@ -486,7 +550,8 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
observerSubject, // aObserverSubject observerSubject, // aObserverSubject
NS_ConvertUTF8toUTF16(sourceFile), // aSourceFile NS_ConvertUTF8toUTF16(sourceFile), // aSourceFile
codeSample, // aScriptSample codeSample, // aScriptSample
aLineNumber); // aLineNum lineNumber, // aLineNum
columnNumber); // aColumnNum
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -495,6 +560,7 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
bool aParserCreated, bool aParserCreated,
const nsAString& aContent, const nsAString& aContent,
uint32_t aLineNumber, uint32_t aLineNumber,
uint32_t aColumnNumber,
bool* outAllowsInline) bool* outAllowsInline)
{ {
*outAllowsInline = true; *outAllowsInline = true;
@ -539,7 +605,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
aContent, aContent,
violatedDirective, violatedDirective,
i, i,
aLineNumber); aLineNumber,
aColumnNumber);
} }
} }
return NS_OK; return NS_OK;
@ -558,7 +625,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
* which is why we must check allows() again here. * which is why we must check allows() again here.
* *
* Note: This macro uses some parameters from its caller's context: * Note: This macro uses some parameters from its caller's context:
* p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, selfISupports * p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, aColumnNum,
* selfISupports
* *
* @param violationType: the VIOLATION_TYPE_* constant (partial symbol) * @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
* such as INLINE_SCRIPT * such as INLINE_SCRIPT
@ -585,8 +653,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
nsIContentPolicy::TYPE_ ## contentPolicyType, \ nsIContentPolicy::TYPE_ ## contentPolicyType, \
violatedDirective); \ violatedDirective); \
this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \ this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
NS_LITERAL_STRING(observerTopic), \ NS_LITERAL_STRING(observerTopic), aSourceFile,\
aSourceFile, aScriptSample, aLineNum); \ aScriptSample, aLineNum, aColumnNum); \
} \ } \
PR_END_MACRO; \ PR_END_MACRO; \
break break
@ -618,6 +686,7 @@ nsCSPContext::LogViolationDetails(uint16_t aViolationType,
const nsAString& aSourceFile, const nsAString& aSourceFile,
const nsAString& aScriptSample, const nsAString& aScriptSample,
int32_t aLineNum, int32_t aLineNum,
int32_t aColumnNum,
const nsAString& aNonce, const nsAString& aNonce,
const nsAString& aContent) const nsAString& aContent)
{ {
@ -626,7 +695,16 @@ nsCSPContext::LogViolationDetails(uint16_t aViolationType,
nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
if (selfICString) { if (selfICString) {
selfICString->SetData(nsDependentCString("self")); if (aViolationType == nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL) {
selfICString->SetData(nsDependentCString("eval"));
} else if (aViolationType == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT ||
aViolationType == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE) {
selfICString->SetData(nsDependentCString("inline"));
} else {
// All the other types should have a URL, but just in case, let's use
// 'self' here.
selfICString->SetData(nsDependentCString("self"));
}
} }
nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString)); nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
@ -799,34 +877,23 @@ StripURIForReporting(nsIURI* aURI,
aURI->GetSpecIgnoringRef(outStrippedURI); aURI->GetSpecIgnoringRef(outStrippedURI);
} }
/**
* Sends CSP violation reports to all sources listed under report-uri.
*
* @param aBlockedContentSource
* Either a CSP Source (like 'self', as string) or nsIURI: the source
* of the violation.
* @param aOriginalUri
* The original URI if the blocked content is a redirect, else null
* @param aViolatedDirective
* the directive that was violated (string).
* @param aSourceFile
* name of the file containing the inline script violation
* @param aScriptSample
* a sample of the violating inline script
* @param aLineNum
* source line number of the violation (if available)
*/
nsresult nsresult
nsCSPContext::SendReports(nsISupports* aBlockedContentSource, nsCSPContext::GatherSecurityPolicyViolationEventData(
nsIURI* aOriginalURI, nsIURI* aBlockedURI,
nsAString& aViolatedDirective, const nsACString& aBlockedString,
uint32_t aViolatedPolicyIndex, nsIURI* aOriginalURI,
nsAString& aSourceFile, nsAString& aViolatedDirective,
nsAString& aScriptSample, uint32_t aViolatedPolicyIndex,
uint32_t aLineNum) nsAString& aSourceFile,
nsAString& aScriptSample,
uint32_t aLineNum,
uint32_t aColumnNum,
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
{ {
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1); NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
MOZ_ASSERT(ValidateDirectiveName(aViolatedDirective), "Invalid directive name");
if (!CSPService::sCSPReportingEnabled) { if (!CSPService::sCSPReportingEnabled) {
// Reporting is pref-disabled. Don't do any actual work and return success. // Reporting is pref-disabled. Don't do any actual work and return success.
nsContentUtils::ReportToConsoleNonLocalized( nsContentUtils::ReportToConsoleNonLocalized(
@ -837,48 +904,39 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
return NS_OK; return NS_OK;
} }
dom::CSPReport report;
nsresult rv; nsresult rv;
// blocked-uri
if (aBlockedContentSource) {
nsAutoCString reportBlockedURI;
nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
// could be a string or URI
if (uri) {
StripURIForReporting(uri, mSelfURI, reportBlockedURI);
} else {
nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
if (cstr) {
cstr->GetData(reportBlockedURI);
}
}
if (reportBlockedURI.IsEmpty()) {
// this can happen for frame-ancestors violation where the violating
// ancestor is cross-origin.
NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
}
report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
}
// document-uri // document-uri
nsAutoCString reportDocumentURI; nsAutoCString reportDocumentURI;
StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI); StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI); aViolationEventInit.mDocumentURI = NS_ConvertUTF8toUTF16(reportDocumentURI);
// referrer
aViolationEventInit.mReferrer = mReferrer;
// blocked-uri
if (aBlockedURI) {
nsAutoCString reportBlockedURI;
StripURIForReporting(aBlockedURI, mSelfURI, reportBlockedURI);
aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(reportBlockedURI);
} else {
aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(aBlockedString);
}
// effective-directive
// The name of the policy directive that was violated.
aViolationEventInit.mEffectiveDirective = aViolatedDirective;
// violated-directive
// In CSP2, the policy directive that was violated, as it appears in the policy.
// In CSP3, the same as effective-directive.
aViolationEventInit.mViolatedDirective = aViolatedDirective;
// original-policy // original-policy
nsAutoString originalPolicy; nsAutoString originalPolicy;
rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy); rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
report.mCsp_report.mOriginal_policy = originalPolicy; aViolationEventInit.mOriginalPolicy = originalPolicy;
// referrer
if (!mReferrer.IsEmpty()) {
report.mCsp_report.mReferrer = mReferrer;
}
// violated-directive
report.mCsp_report.mViolated_directive = aViolatedDirective;
// source-file // source-file
if (!aSourceFile.IsEmpty()) { if (!aSourceFile.IsEmpty()) {
@ -890,20 +948,102 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
sourceURI->GetSpecIgnoringRef(spec); sourceURI->GetSpecIgnoringRef(spec);
aSourceFile = NS_ConvertUTF8toUTF16(spec); aSourceFile = NS_ConvertUTF8toUTF16(spec);
} }
aViolationEventInit.mSourceFile = aSourceFile;
}
// sample, max 40 chars.
aViolationEventInit.mSample = aScriptSample;
uint32_t length = aViolationEventInit.mSample.Length();
if (length > ScriptSampleMaxLength()) {
uint32_t desiredLength = ScriptSampleMaxLength();
// Don't cut off right before a low surrogate. Just include it.
if (NS_IS_LOW_SURROGATE(aViolationEventInit.mSample[desiredLength])) {
desiredLength++;
}
aViolationEventInit.mSample.Replace(ScriptSampleMaxLength(),
length - desiredLength,
nsContentUtils::GetLocalizedEllipsis());
}
// disposition
aViolationEventInit.mDisposition = mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag()
? mozilla::dom::SecurityPolicyViolationEventDisposition::Report
: mozilla::dom::SecurityPolicyViolationEventDisposition::Enforce;
// status-code
uint16_t statusCode = 0;
{
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
if (doc) {
nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(doc->GetChannel());
if (channel) {
uint32_t responseStatus = 0;
nsresult rv = channel->GetResponseStatus(&responseStatus);
if (NS_SUCCEEDED(rv) && (responseStatus <= UINT16_MAX)) {
statusCode = static_cast<uint16_t>(responseStatus);
}
}
}
}
aViolationEventInit.mStatusCode = statusCode;
// line-number
aViolationEventInit.mLineNumber = aLineNum;
// column-number
aViolationEventInit.mColumnNumber = aColumnNum;
aViolationEventInit.mBubbles = true;
aViolationEventInit.mComposed = true;
return NS_OK;
}
nsresult
nsCSPContext::SendReports(
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
uint32_t aViolatedPolicyIndex)
{
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
dom::CSPReport report;
// blocked-uri
report.mCsp_report.mBlocked_uri = aViolationEventInit.mBlockedURI;
// document-uri
report.mCsp_report.mDocument_uri = aViolationEventInit.mDocumentURI;
// original-policy
report.mCsp_report.mOriginal_policy = aViolationEventInit.mOriginalPolicy;
// referrer
report.mCsp_report.mReferrer = aViolationEventInit.mReferrer;
// violated-directive
report.mCsp_report.mViolated_directive = aViolationEventInit.mViolatedDirective;
// source-file
if (!aViolationEventInit.mSourceFile.IsEmpty()) {
report.mCsp_report.mSource_file.Construct(); report.mCsp_report.mSource_file.Construct();
report.mCsp_report.mSource_file.Value() = aSourceFile; report.mCsp_report.mSource_file.Value() = aViolationEventInit.mSourceFile;
} }
// script-sample // script-sample
if (!aScriptSample.IsEmpty()) { if (!aViolationEventInit.mSample.IsEmpty()) {
report.mCsp_report.mScript_sample.Construct(); report.mCsp_report.mScript_sample.Construct();
report.mCsp_report.mScript_sample.Value() = aScriptSample; report.mCsp_report.mScript_sample.Value() = aViolationEventInit.mSample;
} }
// line-number // line-number
if (aLineNum != 0) { if (aViolationEventInit.mLineNumber != 0) {
report.mCsp_report.mLine_number.Construct(); report.mCsp_report.mLine_number.Construct();
report.mCsp_report.mLine_number.Value() = aLineNum; report.mCsp_report.mLine_number.Value() = aViolationEventInit.mLineNumber;
}
if (aViolationEventInit.mColumnNumber != 0) {
report.mCsp_report.mColumn_number.Construct();
report.mCsp_report.mColumn_number.Value() = aViolationEventInit.mColumnNumber;
} }
nsString csp_report; nsString csp_report;
@ -916,11 +1056,11 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
nsTArray<nsString> reportURIs; nsTArray<nsString> reportURIs;
mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs); mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext); nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
nsCOMPtr<nsIURI> reportURI; nsCOMPtr<nsIURI> reportURI;
nsCOMPtr<nsIChannel> reportChannel; nsCOMPtr<nsIChannel> reportChannel;
nsresult rv;
for (uint32_t r = 0; r < reportURIs.Length(); r++) { for (uint32_t r = 0; r < reportURIs.Length(); r++) {
nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]); nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
// try to create a new uri from every report-uri string // try to create a new uri from every report-uri string
@ -930,7 +1070,9 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
CSPCONTEXTLOG(("Could not create nsIURI for report URI %s", CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
reportURICstring.get())); reportURICstring.get()));
logToConsole(u"triedToSendReport", params, ArrayLength(params), logToConsole(u"triedToSendReport", params, ArrayLength(params),
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
nsIScriptError::errorFlag);
continue; // don't return yet, there may be more URIs continue; // don't return yet, there may be more URIs
} }
@ -971,7 +1113,9 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
if (!isHttpScheme) { if (!isHttpScheme) {
const char16_t* params[] = { reportURIs[r].get() }; const char16_t* params[] = { reportURIs[r].get() };
logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params), logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params),
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
nsIScriptError::errorFlag);
continue; continue;
} }
@ -1035,7 +1179,9 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
const char16_t* params[] = { reportURIs[r].get() }; const char16_t* params[] = { reportURIs[r].get() };
CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0])); CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0]));
logToConsole(u"triedToSendReport", params, ArrayLength(params), logToConsole(u"triedToSendReport", params, ArrayLength(params),
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag); aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
nsIScriptError::errorFlag);
} else { } else {
CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get())); CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
} }
@ -1043,6 +1189,26 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
return NS_OK; return NS_OK;
} }
nsresult
nsCSPContext::FireViolationEvent(
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
{
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
if (!doc) {
return NS_OK;
}
RefPtr<mozilla::dom::Event> event =
mozilla::dom::SecurityPolicyViolationEvent::Constructor(
doc,
NS_LITERAL_STRING("securitypolicyviolation"),
aViolationEventInit);
event->SetTrusted(true);
bool rv;
return doc->DispatchEvent(event, &rv);
}
/** /**
* Dispatched from the main thread to send reports for one CSP violation. * Dispatched from the main thread to send reports for one CSP violation.
*/ */
@ -1058,6 +1224,7 @@ class CSPReportSenderRunnable final : public Runnable
const nsAString& aSourceFile, const nsAString& aSourceFile,
const nsAString& aScriptSample, const nsAString& aScriptSample,
uint32_t aLineNum, uint32_t aLineNum,
uint32_t aColumnNum,
nsCSPContext* aCSPContext) nsCSPContext* aCSPContext)
: mBlockedContentSource(aBlockedContentSource) : mBlockedContentSource(aBlockedContentSource)
, mOriginalURI(aOriginalURI) , mOriginalURI(aOriginalURI)
@ -1067,6 +1234,7 @@ class CSPReportSenderRunnable final : public Runnable
, mSourceFile(aSourceFile) , mSourceFile(aSourceFile)
, mScriptSample(aScriptSample) , mScriptSample(aScriptSample)
, mLineNum(aLineNum) , mLineNum(aLineNum)
, mColumnNum(aColumnNum)
, mCSPContext(aCSPContext) , mCSPContext(aCSPContext)
{ {
NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive"); NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
@ -1088,34 +1256,50 @@ class CSPReportSenderRunnable final : public Runnable
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
// 1) notify observers nsresult rv;
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
NS_ASSERTION(observerService, "needs observer service");
nsresult rv = observerService->NotifyObservers(mObserverSubject,
CSP_VIOLATION_TOPIC,
mViolatedDirective.get());
NS_ENSURE_SUCCESS(rv, rv);
// 2) send reports for the policy that was violated // 0) prepare violation data
mCSPContext->SendReports(mBlockedContentSource, mOriginalURI, mozilla::dom::SecurityPolicyViolationEventInit init;
mViolatedDirective, mViolatedPolicyIndex,
mSourceFile, mScriptSample, mLineNum);
// 3) log to console (one per policy violation)
// mBlockedContentSource could be a URI or a string. // mBlockedContentSource could be a URI or a string.
nsCOMPtr<nsIURI> blockedURI = do_QueryInterface(mBlockedContentSource); nsCOMPtr<nsIURI> blockedURI = do_QueryInterface(mBlockedContentSource);
// if mBlockedContentSource is not a URI, it could be a string // if mBlockedContentSource is not a URI, it could be a string
nsCOMPtr<nsISupportsCString> blockedString = do_QueryInterface(mBlockedContentSource); nsCOMPtr<nsISupportsCString> blockedICString = do_QueryInterface(mBlockedContentSource);
nsAutoCString blockedDataStr;
if (blockedICString) {
blockedICString->GetData(blockedDataStr);
}
rv = mCSPContext->GatherSecurityPolicyViolationEventData(
blockedURI, blockedDataStr, mOriginalURI,
mViolatedDirective, mViolatedPolicyIndex,
mSourceFile, mScriptSample, mLineNum,
mColumnNum, init);
NS_ENSURE_SUCCESS(rv, rv);
nsCString blockedDataStr; // 1) notify observers
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
NS_ASSERTION(observerService, "needs observer service");
rv = observerService->NotifyObservers(mObserverSubject,
CSP_VIOLATION_TOPIC,
mViolatedDirective.get());
NS_ENSURE_SUCCESS(rv, rv);
// 2) send reports for the policy that was violated
mCSPContext->SendReports(init, mViolatedPolicyIndex);
// 3) log to console (one per policy violation)
// if mBlockedContentSource is not a URI, it could be a string
nsCOMPtr<nsISupportsCString> blockedString = do_QueryInterface(mBlockedContentSource);
if (blockedURI) { if (blockedURI) {
blockedURI->GetSpec(blockedDataStr); blockedURI->GetSpec(blockedDataStr);
bool isData = false; if (blockedDataStr.Length() > nsCSPContext::ScriptSampleMaxLength()) {
rv = blockedURI->SchemeIs("data", &isData); bool isData = false;
if (NS_SUCCEEDED(rv) && isData) { rv = blockedURI->SchemeIs("data", &isData);
blockedDataStr.Truncate(40); if (NS_SUCCEEDED(rv) && isData &&
blockedDataStr.AppendASCII("..."); blockedDataStr.Length() > nsCSPContext::ScriptSampleMaxLength()) {
blockedDataStr.Truncate(nsCSPContext::ScriptSampleMaxLength());
blockedDataStr.Append(NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis()));
}
} }
} else if (blockedString) { } else if (blockedString) {
blockedString->GetData(blockedDataStr); blockedString->GetData(blockedDataStr);
@ -1128,8 +1312,12 @@ class CSPReportSenderRunnable final : public Runnable
mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" : mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" :
u"CSPViolationWithURI", u"CSPViolationWithURI",
params, ArrayLength(params), mSourceFile, mScriptSample, params, ArrayLength(params), mSourceFile, mScriptSample,
mLineNum, 0, nsIScriptError::errorFlag); mLineNum, mColumnNum, nsIScriptError::errorFlag);
} }
// 4) fire violation event
mCSPContext->FireViolationEvent(init);
return NS_OK; return NS_OK;
} }
@ -1143,6 +1331,7 @@ class CSPReportSenderRunnable final : public Runnable
nsString mSourceFile; nsString mSourceFile;
nsString mScriptSample; nsString mScriptSample;
uint32_t mLineNum; uint32_t mLineNum;
uint32_t mColumnNum;
RefPtr<nsCSPContext> mCSPContext; RefPtr<nsCSPContext> mCSPContext;
}; };
@ -1170,6 +1359,8 @@ class CSPReportSenderRunnable final : public Runnable
* a sample of the violating inline script * a sample of the violating inline script
* @param aLineNum * @param aLineNum
* source line number of the violation (if available) * source line number of the violation (if available)
* @param aColumnNum
* source column number of the violation (if available)
*/ */
nsresult nsresult
nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource, nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
@ -1179,7 +1370,8 @@ nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
const nsAString& aObserverSubject, const nsAString& aObserverSubject,
const nsAString& aSourceFile, const nsAString& aSourceFile,
const nsAString& aScriptSample, const nsAString& aScriptSample,
uint32_t aLineNum) uint32_t aLineNum,
uint32_t aColumnNum)
{ {
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1); NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
@ -1192,6 +1384,7 @@ nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
aSourceFile, aSourceFile,
aScriptSample, aScriptSample,
aLineNum, aLineNum,
aColumnNum,
this)); this));
return NS_OK; return NS_OK;
} }

View file

@ -7,6 +7,7 @@
#define nsCSPContext_h___ #define nsCSPContext_h___
#include "mozilla/dom/nsCSPUtils.h" #include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
@ -56,13 +57,43 @@ class nsCSPContext : public nsIContentSecurityPolicy
uint32_t aColumnNumber, uint32_t aColumnNumber,
uint32_t aSeverityFlag); uint32_t aSeverityFlag);
nsresult SendReports(nsISupports* aBlockedContentSource,
nsIURI* aOriginalURI, /**
nsAString& aViolatedDirective, * Construct SecurityPolicyViolationEventInit structure.
uint32_t aViolatedPolicyIndex, *
nsAString& aSourceFile, * @param aBlockedURI
nsAString& aScriptSample, * A nsIURI: the source of the violation.
uint32_t aLineNum); * @param aOriginalUri
* The original URI if the blocked content is a redirect, else null
* @param aViolatedDirective
* the directive that was violated (string).
* @param aSourceFile
* name of the file containing the inline script violation
* @param aScriptSample
* a sample of the violating inline script
* @param aLineNum
* source line number of the violation (if available)
* @param aViolationEventInit
* The output
*/
nsresult GatherSecurityPolicyViolationEventData(
nsIURI* aBlockedURI,
const nsACString& aBlockedString,
nsIURI* aOriginalURI,
nsAString& aViolatedDirective,
uint32_t aViolatedPolicyIndex,
nsAString& aSourceFile,
nsAString& aScriptSample,
uint32_t aLineNum,
uint32_t aColumnNum,
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
nsresult SendReports(
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
uint32_t aViolatedPolicyIndex);
nsresult FireViolationEvent(
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
nsresult AsyncReportViolation(nsISupports* aBlockedContentSource, nsresult AsyncReportViolation(nsISupports* aBlockedContentSource,
nsIURI* aOriginalURI, nsIURI* aOriginalURI,
@ -71,7 +102,8 @@ class nsCSPContext : public nsIContentSecurityPolicy
const nsAString& aObserverSubject, const nsAString& aObserverSubject,
const nsAString& aSourceFile, const nsAString& aSourceFile,
const nsAString& aScriptSample, const nsAString& aScriptSample,
uint32_t aLineNum); uint32_t aLineNum,
uint32_t aColumnNum);
// Hands off! Don't call this method unless you know what you // Hands off! Don't call this method unless you know what you
// are doing. It's only supposed to be called from within // are doing. It's only supposed to be called from within
@ -80,10 +112,14 @@ class nsCSPContext : public nsIContentSecurityPolicy
mLoadingPrincipal = nullptr; mLoadingPrincipal = nullptr;
} }
nsWeakPtr GetLoadingContext(){ nsWeakPtr GetLoadingContext() {
return mLoadingContext; return mLoadingContext;
} }
static uint32_t ScriptSampleMaxLength() {
return std::max(sScriptSampleMaxLength, 0);
}
private: private:
bool permitsInternal(CSPDirective aDir, bool permitsInternal(CSPDirective aDir,
nsIURI* aContentLocation, nsIURI* aContentLocation,
@ -102,7 +138,10 @@ class nsCSPContext : public nsIContentSecurityPolicy
const nsAString& aContent, const nsAString& aContent,
const nsAString& aViolatedDirective, const nsAString& aViolatedDirective,
uint32_t aViolatedPolicyIndex, uint32_t aViolatedPolicyIndex,
uint32_t aLineNumber); uint32_t aLineNumber,
uint32_t aColumnNumber);
static int32_t sScriptSampleMaxLength;
nsString mReferrer; nsString mReferrer;
uint64_t mInnerWindowID; // used for web console logging uint64_t mInnerWindowID; // used for web console logging

View file

@ -1056,14 +1056,10 @@ nsCSPParser::directiveName()
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken)); return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
} }
// child-src by itself is deprecatd but will be enforced // if we have a child-src, cache it as a fallback for
// * for workers (if worker-src is not explicitly specified) // * workers (if worker-src is not explicitly specified)
// * for frames (if frame-src is not explicitly specified) // * frames (if frame-src is not explicitly specified)
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE)) { if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE)) {
const char16_t* params[] = { mCurToken.get() };
logWarningErrorToConsole(nsIScriptError::warningFlag,
"deprecatedChildSrcDirective",
params, ArrayLength(params));
mChildSrc = new nsCSPChildSrcDirective(CSP_StringToCSPDirective(mCurToken)); mChildSrc = new nsCSPChildSrcDirective(CSP_StringToCSPDirective(mCurToken));
return mChildSrc; return mChildSrc;
} }
@ -1115,6 +1111,10 @@ nsCSPParser::directive()
return; return;
} }
if (CSP_IsEmptyDirective(mCurValue, mCurToken)) {
return;
}
// Try to create a new CSPDirective // Try to create a new CSPDirective
nsCSPDirective* cspDir = directiveName(); nsCSPDirective* cspDir = directiveName();
if (!cspDir) { if (!cspDir) {

View file

@ -212,6 +212,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_SCRIPT: case nsIContentPolicy::TYPE_SCRIPT:
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD: case nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD:
case nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS:
return nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE; return nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_STYLESHEET: case nsIContentPolicy::TYPE_STYLESHEET:
@ -292,6 +293,13 @@ CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI)
return hostsrc; return hostsrc;
} }
bool
CSP_IsEmptyDirective(const nsAString& aValue, const nsAString& aDir)
{
return (aDir.Length() == 0 &&
aValue.Length() == 0);
}
bool bool
CSP_IsValidDirective(const nsAString& aDir) CSP_IsValidDirective(const nsAString& aDir)
{ {
@ -1257,6 +1265,12 @@ bool nsCSPDirective::equals(CSPDirective aDirective) const
return (mDirective == aDirective); return (mDirective == aDirective);
} }
void
nsCSPDirective::getDirName(nsAString& outStr) const
{
outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
}
/* =============== nsCSPChildSrcDirective ============= */ /* =============== nsCSPChildSrcDirective ============= */
nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective) nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
@ -1342,6 +1356,13 @@ nsBlockAllMixedContentDirective::toString(nsAString& outStr) const
nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)); nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT));
} }
void
nsBlockAllMixedContentDirective::getDirName(nsAString& outStr) const
{
outStr.AppendASCII(CSP_CSPDirectiveToString(
nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT));
}
/* =============== nsUpgradeInsecureDirective ============= */ /* =============== nsUpgradeInsecureDirective ============= */
nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective) nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective)
@ -1360,6 +1381,13 @@ nsUpgradeInsecureDirective::toString(nsAString& outStr) const
nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)); nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
} }
void
nsUpgradeInsecureDirective::getDirName(nsAString& outStr) const
{
outStr.AppendASCII(CSP_CSPDirectiveToString(
nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
}
/* ===== nsRequireSRIForDirective ========================= */ /* ===== nsRequireSRIForDirective ========================= */
nsRequireSRIForDirective::nsRequireSRIForDirective(CSPDirective aDirective) nsRequireSRIForDirective::nsRequireSRIForDirective(CSPDirective aDirective)
@ -1411,6 +1439,13 @@ nsRequireSRIForDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHas
return (aKeyword != CSP_REQUIRE_SRI_FOR); return (aKeyword != CSP_REQUIRE_SRI_FOR);
} }
void
nsRequireSRIForDirective::getDirName(nsAString& outStr) const
{
outStr.AppendASCII(CSP_CSPDirectiveToString(
nsIContentSecurityPolicy::REQUIRE_SRI_FOR));
}
/* ===== nsCSPPolicy ========================= */ /* ===== nsCSPPolicy ========================= */
nsCSPPolicy::nsCSPPolicy() nsCSPPolicy::nsCSPPolicy()
@ -1464,7 +1499,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
if (mDirectives[i]->equals(aDir)) { if (mDirectives[i]->equals(aDir)) {
if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly, if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly,
mUpgradeInsecDir, aParserCreated)) { mUpgradeInsecDir, aParserCreated)) {
mDirectives[i]->toString(outViolatedDirective); mDirectives[i]->getDirName(outViolatedDirective);
return false; return false;
} }
return true; return true;
@ -1479,7 +1514,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
if (!aSpecific && defaultDir) { if (!aSpecific && defaultDir) {
if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly, if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly,
mUpgradeInsecDir, aParserCreated)) { mUpgradeInsecDir, aParserCreated)) {
defaultDir->toString(outViolatedDirective); defaultDir->getDirName(outViolatedDirective);
return false; return false;
} }
return true; return true;
@ -1605,7 +1640,7 @@ nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
nsCSPDirective* defaultDir = nullptr; nsCSPDirective* defaultDir = nullptr;
for (uint32_t i = 0; i < mDirectives.Length(); i++) { for (uint32_t i = 0; i < mDirectives.Length(); i++) {
if (mDirectives[i]->restrictsContentType(aContentType)) { if (mDirectives[i]->restrictsContentType(aContentType)) {
mDirectives[i]->toString(outDirective); mDirectives[i]->getDirName(outDirective);
return; return;
} }
if (mDirectives[i]->isDefaultDirective()) { if (mDirectives[i]->isDefaultDirective()) {
@ -1615,7 +1650,7 @@ nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
// if we haven't found a matching directive yet, // if we haven't found a matching directive yet,
// the contentType must be restricted by the default directive // the contentType must be restricted by the default directive
if (defaultDir) { if (defaultDir) {
defaultDir->toString(outDirective); defaultDir->getDirName(outDirective);
return; return;
} }
NS_ASSERTION(false, "Can not query directive string for contentType!"); NS_ASSERTION(false, "Can not query directive string for contentType!");

View file

@ -235,6 +235,7 @@ nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp,
class nsCSPHostSrc; class nsCSPHostSrc;
nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI); nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI);
bool CSP_IsEmptyDirective(const nsAString& aValue, const nsAString& aDir);
bool CSP_IsValidDirective(const nsAString& aDir); bool CSP_IsValidDirective(const nsAString& aDir);
bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir); bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir);
bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey); bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey);
@ -493,6 +494,8 @@ class nsCSPDirective {
bool visitSrcs(nsCSPSrcVisitor* aVisitor) const; bool visitSrcs(nsCSPSrcVisitor* aVisitor) const;
virtual void getDirName(nsAString& outStr) const;
protected: protected:
CSPDirective mDirective; CSPDirective mDirective;
nsTArray<nsCSPBaseSrc*> mSrcs; nsTArray<nsCSPBaseSrc*> mSrcs;
@ -571,6 +574,8 @@ class nsBlockAllMixedContentDirective : public nsCSPDirective {
void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
{ MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); } { MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); }
void getDirName(nsAString& outStr) const override;
}; };
/* =============== nsUpgradeInsecureDirective === */ /* =============== nsUpgradeInsecureDirective === */
@ -624,6 +629,8 @@ class nsUpgradeInsecureDirective : public nsCSPDirective {
void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs) void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
{ MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); } { MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); }
void getDirName(nsAString& outStr) const override;
}; };
/* ===== nsRequireSRIForDirective ========================= */ /* ===== nsRequireSRIForDirective ========================= */
@ -641,6 +648,7 @@ class nsRequireSRIForDirective : public nsCSPDirective {
bool restrictsContentType(nsContentPolicyType aType) const; bool restrictsContentType(nsContentPolicyType aType) const;
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const; bool aParserCreated) const;
void getDirName(nsAString& outStr) const override;
private: private:
nsTArray<nsContentPolicyType> mTypes; nsTArray<nsContentPolicyType> mTypes;

View file

@ -405,7 +405,7 @@ nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
doc->NodePrincipal(), doc->NodePrincipal(),
doc->GetDocumentURI(), doc->GetDocumentURI(),
0, aString, nullptr)) { 0, 0, aString, nullptr)) {
return; return;
} }

View file

@ -16,6 +16,7 @@ dictionary CSPReportProperties {
DOMString source-file; DOMString source-file;
DOMString script-sample; DOMString script-sample;
long line-number; long line-number;
long column-number;
}; };
dictionary CSPReport { dictionary CSPReport {

View file

@ -0,0 +1,41 @@
/* 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/. */
enum SecurityPolicyViolationEventDisposition
{
"enforce", "report"
};
[Constructor(DOMString type, optional SecurityPolicyViolationEventInit eventInitDict)]
interface SecurityPolicyViolationEvent : Event
{
readonly attribute DOMString documentURI;
readonly attribute DOMString referrer;
readonly attribute DOMString blockedURI;
readonly attribute DOMString violatedDirective;
readonly attribute DOMString effectiveDirective;
readonly attribute DOMString originalPolicy;
readonly attribute DOMString sourceFile;
readonly attribute DOMString sample;
readonly attribute SecurityPolicyViolationEventDisposition disposition;
readonly attribute unsigned short statusCode;
readonly attribute long lineNumber;
readonly attribute long columnNumber;
};
dictionary SecurityPolicyViolationEventInit : EventInit
{
DOMString documentURI = "";
DOMString referrer = "";
DOMString blockedURI = "";
DOMString violatedDirective = "";
DOMString effectiveDirective = "";
DOMString originalPolicy = "";
DOMString sourceFile = "";
DOMString sample = "";
SecurityPolicyViolationEventDisposition disposition = "report";
unsigned short statusCode = 0;
long lineNumber = 0;
long columnNumber = 0;
};

View file

@ -694,6 +694,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'PromiseRejectionEvent.webidl', 'PromiseRejectionEvent.webidl',
'RecordErrorEvent.webidl', 'RecordErrorEvent.webidl',
'ScrollViewChangeEvent.webidl', 'ScrollViewChangeEvent.webidl',
'SecurityPolicyViolationEvent.webidl',
'ServiceWorkerMessageEvent.webidl', 'ServiceWorkerMessageEvent.webidl',
'StyleRuleChangeEvent.webidl', 'StyleRuleChangeEvent.webidl',
'StyleSheetApplicableStateChangeEvent.webidl', 'StyleSheetApplicableStateChangeEvent.webidl',

View file

@ -6,7 +6,7 @@
#ifndef mozilla_dom_workers_queue_h__ #ifndef mozilla_dom_workers_queue_h__
#define mozilla_dom_workers_queue_h__ #define mozilla_dom_workers_queue_h__
#include "Workers.h" #include "mozilla/dom/workers/Workers.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsTArray.h" #include "nsTArray.h"

View file

@ -547,14 +547,21 @@ class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable
{ {
nsString mFileName; nsString mFileName;
uint32_t mLineNum; uint32_t mLineNum;
uint32_t mColumnNum;
nsString mScriptSample;
public: public:
LogViolationDetailsRunnable(WorkerPrivate* aWorker, LogViolationDetailsRunnable(WorkerPrivate* aWorker,
const nsString& aFileName, const nsString& aFileName,
uint32_t aLineNum) uint32_t aLineNum,
uint32_t aColumnNum,
const nsAString& aScriptSample)
: WorkerMainThreadRunnable(aWorker, : WorkerMainThreadRunnable(aWorker,
NS_LITERAL_CSTRING("RuntimeService :: LogViolationDetails")) NS_LITERAL_CSTRING("RuntimeService :: LogViolationDetails"))
, mFileName(aFileName), mLineNum(aLineNum) , mFileName(aFileName)
, mLineNum(aLineNum)
, mColumnNum(aColumnNum)
, mScriptSample(aScriptSample)
{ {
MOZ_ASSERT(aWorker); MOZ_ASSERT(aWorker);
} }
@ -566,24 +573,38 @@ private:
}; };
bool bool
ContentSecurityPolicyAllows(JSContext* aCx) ContentSecurityPolicyAllows(JSContext* aCx, JS::HandleValue aValue)
{ {
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
worker->AssertIsOnWorkerThread(); worker->AssertIsOnWorkerThread();
if (worker->GetReportCSPViolations()) { if (worker->GetReportCSPViolations()) {
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, aValue));
if (NS_WARN_IF(!jsString)) {
JS_ClearPendingException(aCx);
return false;
}
nsAutoJSString scriptSample;
if (NS_WARN_IF(!scriptSample.init(aCx, jsString))) {
JS_ClearPendingException(aCx);
return false;
}
nsString fileName; nsString fileName;
uint32_t lineNum = 0; uint32_t lineNum = 0;
uint32_t columnNum = 0;
JS::AutoFilename file; JS::AutoFilename file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineNum) && file.get()) { if (JS::DescribeScriptedCaller(aCx, &file, &lineNum, &columnNum) && file.get()) {
fileName = NS_ConvertUTF8toUTF16(file.get()); fileName = NS_ConvertUTF8toUTF16(file.get());
} else { } else {
MOZ_ASSERT(!JS_IsExceptionPending(aCx)); MOZ_ASSERT(!JS_IsExceptionPending(aCx));
} }
RefPtr<LogViolationDetailsRunnable> runnable = RefPtr<LogViolationDetailsRunnable> runnable =
new LogViolationDetailsRunnable(worker, fileName, lineNum); new LogViolationDetailsRunnable(worker, fileName, lineNum, columnNum,
scriptSample);
ErrorResult rv; ErrorResult rv;
runnable->Dispatch(Killing, rv); runnable->Dispatch(Killing, rv);
@ -2698,11 +2719,9 @@ LogViolationDetailsRunnable::MainThreadRun()
nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP(); nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
if (csp) { if (csp) {
NS_NAMED_LITERAL_STRING(scriptSample,
"Call to eval() or related function blocked by CSP.");
if (mWorkerPrivate->GetReportCSPViolations()) { if (mWorkerPrivate->GetReportCSPViolations()) {
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
mFileName, scriptSample, mLineNum, mFileName, mScriptSample, mLineNum, mColumnNum,
EmptyString(), EmptyString()); EmptyString(), EmptyString());
} }
} }

View file

@ -59,6 +59,7 @@
#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SRILogHelper.h" #include "mozilla/dom/SRILogHelper.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "Principal.h" #include "Principal.h"
#include "WorkerHolder.h" #include "WorkerHolder.h"
@ -112,7 +113,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
const nsAString& aScriptURL, const nsAString& aScriptURL,
bool aIsMainScript, bool aIsMainScript,
WorkerScriptType aWorkerScriptType, WorkerScriptType aWorkerScriptType,
nsContentPolicyType aContentPolicyType, nsContentPolicyType aMainScriptContentPolicyType,
nsLoadFlags aLoadFlags, nsLoadFlags aLoadFlags,
bool aDefaultURIEncoding, bool aDefaultURIEncoding,
nsIChannel** aChannel) nsIChannel** aChannel)
@ -169,6 +170,10 @@ ChannelFromScriptURL(nsIPrincipal* principal,
secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
} }
nsContentPolicyType contentPolicyType =
aIsMainScript ? aMainScriptContentPolicyType
: nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS;
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
// If we have the document, use it. Unfortunately, for dedicated workers // If we have the document, use it. Unfortunately, for dedicated workers
// 'parentDoc' ends up being the parent document, which is not the document // 'parentDoc' ends up being the parent document, which is not the document
@ -179,7 +184,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
uri, uri,
parentDoc, parentDoc,
secFlags, secFlags,
aContentPolicyType, contentPolicyType,
loadGroup, loadGroup,
nullptr, // aCallbacks nullptr, // aCallbacks
aLoadFlags, aLoadFlags,
@ -194,7 +199,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
uri, uri,
principal, principal,
secFlags, secFlags,
aContentPolicyType, contentPolicyType,
loadGroup, loadGroup,
nullptr, // aCallbacks nullptr, // aCallbacks
aLoadFlags, aLoadFlags,
@ -464,6 +469,8 @@ private:
nsCOMPtr<nsIURI> mBaseURI; nsCOMPtr<nsIURI> mBaseURI;
mozilla::dom::ChannelInfo mChannelInfo; mozilla::dom::ChannelInfo mChannelInfo;
UniquePtr<PrincipalInfo> mPrincipalInfo; UniquePtr<PrincipalInfo> mPrincipalInfo;
nsCString mCSPHeaderValue;
nsCString mCSPReportOnlyHeaderValue;
}; };
NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver) NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver)
@ -657,6 +664,34 @@ private:
ScriptLoadInfo& loadInfo = mLoadInfos[aIndex]; ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
// Checking the MIME type is only required for ServiceWorkers'
// importScripts, per step 10 of https://w3c.github.io/ServiceWorker/#importscripts
//
// "Extract a MIME type from the response’s header list. If this MIME type
// (ignoring parameters) is not a JavaScript MIME type, return a network error."
if (mWorkerPrivate->IsServiceWorker()) {
nsAutoCString mimeType;
channel->GetContentType(mimeType);
if (!nsContentUtils::IsJavascriptMIMEType(NS_ConvertUTF8toUTF16(mimeType))) {
const nsCString& scope =
mWorkerPrivate->ServiceWorkerScope();
ServiceWorkerManager::LocalizeAndReportToAllClients(
scope, "ServiceWorkerRegisterMimeTypeError2",
nsTArray<nsString> {
NS_ConvertUTF8toUTF16(scope),
NS_ConvertUTF8toUTF16(mimeType),
loadInfo.mURL
}
);
channel->Cancel(NS_ERROR_DOM_NETWORK_ERR);
return NS_ERROR_DOM_NETWORK_ERR;
}
}
MOZ_ASSERT(channel == loadInfo.mChannel); MOZ_ASSERT(channel == loadInfo.mChannel);
// We synthesize the result code, but its never exposed to content. // We synthesize the result code, but its never exposed to content.
@ -691,6 +726,7 @@ private:
} }
ir->SetPrincipalInfo(Move(principalInfo)); ir->SetPrincipalInfo(Move(principalInfo));
ir->Headers()->FillResponseHeaders(loadInfo.mChannel);
RefPtr<mozilla::dom::Response> response = RefPtr<mozilla::dom::Response> response =
new mozilla::dom::Response(mCacheCreator->Global(), ir, nullptr); new mozilla::dom::Response(mCacheCreator->Global(), ir, nullptr);
@ -1127,11 +1163,11 @@ private:
("Scriptloader::Load, SRI required but not supported in workers")); ("Scriptloader::Load, SRI required but not supported in workers"));
nsCOMPtr<nsIContentSecurityPolicy> wcsp; nsCOMPtr<nsIContentSecurityPolicy> wcsp;
chanLoadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(wcsp)); chanLoadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(wcsp));
MOZ_ASSERT(wcsp, "We sould have a CSP for the worker here"); MOZ_ASSERT(wcsp, "We should have a CSP for the worker here");
if (wcsp) { if (wcsp) {
wcsp->LogViolationDetails( wcsp->LogViolationDetails(
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT, nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
aLoadInfo.mURL, EmptyString(), 0, EmptyString(), EmptyString()); aLoadInfo.mURL, EmptyString(), 0, 0, EmptyString(), EmptyString());
} }
return NS_ERROR_SRI_CORRUPT; return NS_ERROR_SRI_CORRUPT;
} }
@ -1199,53 +1235,14 @@ private:
// load group's appId and browser element flag. // load group's appId and browser element flag.
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal)); MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
mWorkerPrivate->SetPrincipal(channelPrincipal, channelLoadGroup); mWorkerPrivate->SetPrincipalOnMainThread(channelPrincipal, channelLoadGroup);
// We did inherit CSP in bug 1223647. If we do not already have a CSP, we // 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. // should get it from the HTTP headers on the worker script.
if (!mWorkerPrivate->GetCSP() && CSPService::sCSPEnabled) { if (!mWorkerPrivate->GetCSP() && CSPService::sCSPEnabled) {
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue); rv = mWorkerPrivate->SetCSPFromHeaderValues(tCspHeaderValue,
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue); tCspROHeaderValue);
NS_ENSURE_SUCCESS(rv, rv);
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
MOZ_ASSERT(principal, "Should not be null");
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->EnsureCSP(nullptr, getter_AddRefs(csp));
if (csp) {
// 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);
NS_ENSURE_SUCCESS(rv, rv);
}
// Set evalAllowed, default value is set in GetAllowsEval
bool evalAllowed = false;
bool reportEvalViolations = false;
rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
NS_ENSURE_SUCCESS(rv, rv);
mWorkerPrivate->SetCSP(csp);
mWorkerPrivate->SetEvalAllowed(evalAllowed);
mWorkerPrivate->SetReportCSPViolations(reportEvalViolations);
// Set ReferrerPolicy, default value is set in GetReferrerPolicy
bool hasReferrerPolicy = false;
uint32_t rp = mozilla::net::RP_Default;
rv = csp->GetReferrerPolicy(&rp, &hasReferrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
if (hasReferrerPolicy) { //FIXME bug 1307366: move RP out of CSP code
mWorkerPrivate->SetReferrerPolicy(static_cast<net::ReferrerPolicy>(rp));
}
}
} }
if (parent) { if (parent) {
// XHR Params Allowed // XHR Params Allowed
@ -1270,7 +1267,9 @@ private:
DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString, DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
uint32_t aStringLen, uint32_t aStringLen,
const mozilla::dom::ChannelInfo& aChannelInfo, const mozilla::dom::ChannelInfo& aChannelInfo,
UniquePtr<PrincipalInfo> aPrincipalInfo) UniquePtr<PrincipalInfo> aPrincipalInfo,
const nsACString& aCSPHeaderValue,
const nsACString& aCSPReportOnlyHeaderValue)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(aIndex < mLoadInfos.Length()); MOZ_ASSERT(aIndex < mLoadInfos.Length());
@ -1279,6 +1278,7 @@ private:
nsCOMPtr<nsIPrincipal> responsePrincipal = nsCOMPtr<nsIPrincipal> responsePrincipal =
PrincipalInfoToPrincipal(*aPrincipalInfo); PrincipalInfoToPrincipal(*aPrincipalInfo);
MOZ_DIAGNOSTIC_ASSERT(responsePrincipal);
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal(); nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
if (!principal) { if (!principal) {
@ -1306,17 +1306,35 @@ private:
mWorkerPrivate->SetBaseURI(finalURI); mWorkerPrivate->SetBaseURI(finalURI);
} }
mozilla::DebugOnly<nsIPrincipal*> principal = mWorkerPrivate->GetPrincipal();
MOZ_ASSERT(principal);
nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup(); nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup();
MOZ_ASSERT(loadGroup); MOZ_DIAGNOSTIC_ASSERT(loadGroup);
mozilla::DebugOnly<bool> equal = false; #if defined(DEBUG)
MOZ_ASSERT(responsePrincipal && NS_SUCCEEDED(responsePrincipal->Equals(principal, &equal))); nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
MOZ_ASSERT(equal); MOZ_DIAGNOSTIC_ASSERT(principal);
bool equal = false;
MOZ_ALWAYS_SUCCEEDS(responsePrincipal->Equals(principal, &equal));
MOZ_DIAGNOSTIC_ASSERT(equal);
nsCOMPtr<nsIContentSecurityPolicy> csp;
MOZ_ALWAYS_SUCCEEDS(responsePrincipal->GetCsp(getter_AddRefs(csp)));
MOZ_DIAGNOSTIC_ASSERT(!csp);
#endif
mWorkerPrivate->InitChannelInfo(aChannelInfo); mWorkerPrivate->InitChannelInfo(aChannelInfo);
mWorkerPrivate->SetPrincipal(responsePrincipal, loadGroup);
// Override the principal on the WorkerPrivate. We just asserted that
// this is the same as our current WorkerPrivate principal, so this is
// almost a no-op. We must do, it though, in order to avoid accidentally
// propagating the CSP object back to the ServiceWorkerRegistration
// principal. If bug 965637 is fixed then this can be removed.
rv = mWorkerPrivate->SetPrincipalOnMainThread(responsePrincipal, loadGroup);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
rv = mWorkerPrivate->SetCSPFromHeaderValues(aCSPHeaderValue,
aCSPReportOnlyHeaderValue);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
} }
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
@ -1730,6 +1748,14 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
return; return;
} }
InternalHeaders* headers = response->GetInternalHeaders();
IgnoredErrorResult ignored;
headers->Get(NS_LITERAL_CSTRING("content-security-policy"),
mCSPHeaderValue, ignored);
headers->Get(NS_LITERAL_CSTRING("content-security-policy-report-only"),
mCSPReportOnlyHeaderValue, ignored);
nsCOMPtr<nsIInputStream> inputStream; nsCOMPtr<nsIInputStream> inputStream;
response->GetBody(getter_AddRefs(inputStream)); response->GetBody(getter_AddRefs(inputStream));
mChannelInfo = response->GetChannelInfo(); mChannelInfo = response->GetChannelInfo();
@ -1741,7 +1767,8 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
if (!inputStream) { if (!inputStream) {
mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached; mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo, mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo,
Move(mPrincipalInfo)); Move(mPrincipalInfo), mCSPHeaderValue,
mCSPReportOnlyHeaderValue);
return; return;
} }
@ -1801,7 +1828,8 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont
MOZ_ASSERT(mPrincipalInfo); MOZ_ASSERT(mPrincipalInfo);
mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo, mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo,
Move(mPrincipalInfo)); Move(mPrincipalInfo), mCSPHeaderValue,
mCSPReportOnlyHeaderValue);
return NS_OK; return NS_OK;
} }
@ -2170,7 +2198,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
nsIDocument* aParentDoc, nsIDocument* aParentDoc,
nsILoadGroup* aLoadGroup, nsILoadGroup* aLoadGroup,
const nsAString& aScriptURL, const nsAString& aScriptURL,
nsContentPolicyType aContentPolicyType, nsContentPolicyType aMainScriptContentPolicyType,
bool aDefaultURIEncoding, bool aDefaultURIEncoding,
nsIChannel** aChannel) nsIChannel** aChannel)
{ {
@ -2183,8 +2211,9 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup, return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
ios, secMan, aScriptURL, true, WorkerScript, ios, secMan, aScriptURL, true, WorkerScript,
aContentPolicyType, nsIRequest::LOAD_NORMAL, aMainScriptContentPolicyType,
aDefaultURIEncoding, aChannel); nsIRequest::LOAD_NORMAL, aDefaultURIEncoding,
aChannel);
} }
nsresult nsresult

View file

@ -805,7 +805,7 @@ public:
WaitUntilHandler(WorkerPrivate* aWorkerPrivate, JSContext* aCx) WaitUntilHandler(WorkerPrivate* aWorkerPrivate, JSContext* aCx)
: mWorkerPrivate(aWorkerPrivate) : mWorkerPrivate(aWorkerPrivate)
, mScope(mWorkerPrivate->WorkerName()) , mScope(mWorkerPrivate->ServiceWorkerScope())
, mLine(0) , mLine(0)
, mColumn(0) , mColumn(0)
{ {

View file

@ -3154,10 +3154,12 @@ already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope, ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
nsIPrincipal* aPrincipal) nsIPrincipal* aPrincipal)
{ {
nsresult rv;
#ifdef DEBUG #ifdef DEBUG
AssertIsOnMainThread(); AssertIsOnMainThread();
nsCOMPtr<nsIURI> scopeURI; nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr); rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
MOZ_ASSERT(NS_SUCCEEDED(rv)); MOZ_ASSERT(NS_SUCCEEDED(rv));
RefPtr<ServiceWorkerRegistrationInfo> tmp = RefPtr<ServiceWorkerRegistrationInfo> tmp =
@ -3165,8 +3167,35 @@ ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
MOZ_ASSERT(!tmp); MOZ_ASSERT(!tmp);
#endif #endif
// The environment that registers the document may have some CSP applied
// to its principal. This should not be inherited by the registration
// itself or the worker it creates. To avoid confusion in callsites
// downstream we strip the CSP from the principal now.
//
// Unfortunately there is no API to clone a principal without its CSP. To
// achieve the same thing we serialize to the IPC PrincipalInfo type and
// back to an nsIPrincipal.
PrincipalInfo principalInfo;
rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsCOMPtr<nsIPrincipal> cleanPrincipal =
PrincipalInfoToPrincipal(principalInfo, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
// Verify that we do not have any CSP set on our principal "clone".
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
nsCOMPtr<nsIContentSecurityPolicy> csp;
MOZ_ALWAYS_SUCCEEDS(cleanPrincipal->GetCsp(getter_AddRefs(csp)));
MOZ_DIAGNOSTIC_ASSERT(!csp);
#endif
RefPtr<ServiceWorkerRegistrationInfo> registration = RefPtr<ServiceWorkerRegistrationInfo> registration =
new ServiceWorkerRegistrationInfo(aScope, aPrincipal); new ServiceWorkerRegistrationInfo(aScope, cleanPrincipal);
// From now on ownership of registration is with // From now on ownership of registration is with
// mServiceWorkerRegistrationInfos. // mServiceWorkerRegistrationInfos.
AddScopeAndRegistration(aScope, registration); AddScopeAndRegistration(aScope, registration);

View file

@ -1760,26 +1760,30 @@ ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
info.mStorageAllowed = access > nsContentUtils::StorageAccess::ePrivateBrowsing; info.mStorageAllowed = access > nsContentUtils::StorageAccess::ePrivateBrowsing;
info.mOriginAttributes = mInfo->GetOriginAttributes(); info.mOriginAttributes = mInfo->GetOriginAttributes();
// The ServiceWorkerRegistration principal should never have any CSP
// set. The CSP from the page that registered the SW should not be
// inherited. Verify this is the case in non-release builds
#if defined(DEBUG)
nsCOMPtr<nsIContentSecurityPolicy> csp; nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = info.mPrincipal->GetCsp(getter_AddRefs(csp)); rv = info.mPrincipal->GetCsp(getter_AddRefs(csp));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
MOZ_DIAGNOSTIC_ASSERT(!csp);
#endif
info.mCSP = csp; // Default CSP permissions for now. These will be overrided if necessary
if (info.mCSP) { // based on the script CSP headers during load in ScriptLoader.
rv = info.mCSP->GetAllowsEval(&info.mReportCSPViolations, info.mEvalAllowed = true;
&info.mEvalAllowed); info.mReportCSPViolations = false;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
info.mEvalAllowed = true;
info.mReportCSPViolations = false;
}
WorkerPrivate::OverrideLoadInfoLoadGroup(info); WorkerPrivate::OverrideLoadInfoLoadGroup(info);
rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
AutoJSAPI jsapi; AutoJSAPI jsapi;
jsapi.Init(); jsapi.Init();
ErrorResult error; ErrorResult error;

View file

@ -52,6 +52,11 @@ ServiceWorkerRegisterJob::AsyncExecute()
} }
} else { } else {
registration = swm->CreateNewRegistration(mScope, mPrincipal); registration = swm->CreateNewRegistration(mScope, mPrincipal);
if (!registration) {
FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
return;
}
} }
SetRegistration(registration); SetRegistration(registration);

View file

@ -239,6 +239,7 @@ public:
CompareCallback* aCallback) CompareCallback* aCallback)
: mRegistration(aRegistration) : mRegistration(aRegistration)
, mCallback(aCallback) , mCallback(aCallback)
, mInternalHeaders(new InternalHeaders())
, mState(WaitingForOpen) , mState(WaitingForOpen)
, mNetworkFinished(false) , mNetworkFinished(false)
, mCacheFinished(false) , mCacheFinished(false)
@ -425,12 +426,22 @@ public:
return mCacheStorage; return mCacheStorage;
} }
void nsresult
InitChannelInfo(nsIChannel* aChannel) OnStartRequest(nsIChannel* aChannel)
{ {
nsresult rv = SetPrincipalInfo(aChannel);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mChannelInfo.InitFromChannel(aChannel); mChannelInfo.InitFromChannel(aChannel);
mInternalHeaders->FillResponseHeaders(aChannel);
return NS_OK;
} }
nsresult nsresult
SetPrincipalInfo(nsIChannel* aChannel) SetPrincipalInfo(nsIChannel* aChannel)
{ {
@ -553,6 +564,9 @@ private:
ir->SetPrincipalInfo(Move(mPrincipalInfo)); ir->SetPrincipalInfo(Move(mPrincipalInfo));
} }
IgnoredErrorResult ignored;
ir->Headers()->Fill(*mInternalHeaders, ignored);
RefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir, nullptr); RefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir, nullptr);
RequestOrUSVString request; RequestOrUSVString request;
@ -587,6 +601,7 @@ private:
nsString mNewCacheName; nsString mNewCacheName;
ChannelInfo mChannelInfo; ChannelInfo mChannelInfo;
RefPtr<InternalHeaders> mInternalHeaders;
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
@ -682,8 +697,7 @@ CompareNetwork::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
MOZ_ASSERT(channel == mChannel); MOZ_ASSERT(channel == mChannel);
#endif #endif
mManager->InitChannelInfo(mChannel); nsresult rv = mManager->OnStartRequest(mChannel);
nsresult rv = mManager->SetPrincipalInfo(mChannel);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@ -787,12 +801,11 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext
return rv; return rv;
} }
if (!mimeType.LowerCaseEqualsLiteral("text/javascript") && if (mimeType.IsEmpty() ||
!mimeType.LowerCaseEqualsLiteral("application/x-javascript") && !nsContentUtils::IsJavascriptMIMEType(NS_ConvertUTF8toUTF16(mimeType))) {
!mimeType.LowerCaseEqualsLiteral("application/javascript")) {
RefPtr<ServiceWorkerRegistrationInfo> registration = mManager->GetRegistration(); RefPtr<ServiceWorkerRegistrationInfo> registration = mManager->GetRegistration();
ServiceWorkerManager::LocalizeAndReportToAllClients( ServiceWorkerManager::LocalizeAndReportToAllClients(
registration->mScope, "ServiceWorkerRegisterMimeTypeError", registration->mScope, "ServiceWorkerRegisterMimeTypeError2",
nsTArray<nsString> { NS_ConvertUTF8toUTF16(registration->mScope), nsTArray<nsString> { NS_ConvertUTF8toUTF16(registration->mScope),
NS_ConvertUTF8toUTF16(mimeType), mManager->URL() }); NS_ConvertUTF8toUTF16(mimeType), mManager->URL() });
mManager->NetworkFinished(NS_ERROR_DOM_SECURITY_ERR); mManager->NetworkFinished(NS_ERROR_DOM_SECURITY_ERR);

View file

@ -58,6 +58,7 @@
#include "mozilla/dom/MessageEventBinding.h" #include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/MessagePort.h" #include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/Performance.h" #include "mozilla/dom/Performance.h"
#include "mozilla/dom/PMessagePort.h" #include "mozilla/dom/PMessagePort.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
@ -549,7 +550,7 @@ private:
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) { if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->WorkerName(), aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), aWorkerPrivate->ScriptURL(),
EmptyString(), EmptyString(), EmptyString(), EmptyString(), EmptyString(), EmptyString(),
0, 0, JSREPORT_ERROR, JSEXN_ERR); 0, 0, JSREPORT_ERROR, JSEXN_ERR);
@ -1254,7 +1255,7 @@ private:
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) { if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->WorkerName(), aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), aWorkerPrivate->ScriptURL(),
mReport.mMessage, mReport.mMessage,
mReport.mFilename, mReport.mLine, mReport.mLineNumber, mReport.mFilename, mReport.mLine, mReport.mLineNumber,
@ -2382,6 +2383,56 @@ WorkerPrivateParent<Derived>::GetDocument() const
return nullptr; return nullptr;
} }
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;
}
// 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);
NS_ENSURE_SUCCESS(rv, rv);
}
// Set evalAllowed, default value is set in GetAllowsEval
bool evalAllowed = false;
bool reportEvalViolations = false;
rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
NS_ENSURE_SUCCESS(rv, rv);
// Set ReferrerPolicy, default value is set in GetReferrerPolicy
bool hasReferrerPolicy = false;
uint32_t rp = mozilla::net::RP_Unset;
rv = csp->GetReferrerPolicy(&rp, &hasReferrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
mLoadInfo.mCSP = csp;
mLoadInfo.mEvalAllowed = evalAllowed;
mLoadInfo.mReportCSPViolations = reportEvalViolations;
if (hasReferrerPolicy) {
mLoadInfo.mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
}
return NS_OK;
}
// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the // Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
// templates. // templates.
@ -3628,47 +3679,53 @@ WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
nsContentUtils::GetUTFOrigin(aBaseURI, mLocationInfo.mOrigin); nsContentUtils::GetUTFOrigin(aBaseURI, mLocationInfo.mOrigin);
} }
template <class Derived> nsresult
void WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup)
nsILoadGroup* aLoadGroup)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal)); MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
MOZ_ASSERT(!mLoadInfo.mPrincipalInfo);
mLoadInfo.mPrincipal = aPrincipal; mPrincipal = aPrincipal;
mLoadInfo.mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal); mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
aPrincipal->GetCsp(getter_AddRefs(mLoadInfo.mCSP)); nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
NS_ENSURE_SUCCESS(rv, rv);
if (mLoadInfo.mCSP) { if (mCSP) {
mLoadInfo.mCSP->GetAllowsEval(&mLoadInfo.mReportCSPViolations, mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
&mLoadInfo.mEvalAllowed);
// Set ReferrerPolicy // Set ReferrerPolicy
bool hasReferrerPolicy = false; bool hasReferrerPolicy = false;
uint32_t rp = mozilla::net::RP_Default; uint32_t rp = mozilla::net::RP_Unset;
nsresult rv = mLoadInfo.mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy); rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
NS_ENSURE_SUCCESS_VOID(rv); NS_ENSURE_SUCCESS(rv, rv);
if (hasReferrerPolicy) { if (hasReferrerPolicy) {
mLoadInfo.mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp); mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
} }
} else { } else {
mLoadInfo.mEvalAllowed = true; mEvalAllowed = true;
mLoadInfo.mReportCSPViolations = false; mReportCSPViolations = false;
} }
mLoadInfo.mLoadGroup = aLoadGroup; mLoadGroup = aLoadGroup;
mLoadInfo.mPrincipalInfo = new PrincipalInfo(); mPrincipalInfo = new PrincipalInfo();
mLoadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup); mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
nsContentUtils::GetUTFOrigin(aPrincipal, mLoadInfo.mOrigin); rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_SUCCEEDS( return NS_OK;
PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo)); }
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
{
return mLoadInfo.SetPrincipalOnMainThread(aPrincipal, aLoadGroup);
} }
template <class Derived> template <class Derived>
@ -6679,7 +6736,7 @@ WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
if (IsSharedWorker()) { if (IsSharedWorker()) {
globalScope = new SharedWorkerGlobalScope(this, WorkerName()); globalScope = new SharedWorkerGlobalScope(this, WorkerName());
} else if (IsServiceWorker()) { } else if (IsServiceWorker()) {
globalScope = new ServiceWorkerGlobalScope(this, WorkerName()); globalScope = new ServiceWorkerGlobalScope(this, ServiceWorkerScope());
} else { } else {
globalScope = new DedicatedWorkerGlobalScope(this); globalScope = new DedicatedWorkerGlobalScope(this);
} }

View file

@ -6,7 +6,7 @@
#ifndef mozilla_dom_workers_workerprivate_h__ #ifndef mozilla_dom_workers_workerprivate_h__
#define mozilla_dom_workers_workerprivate_h__ #define mozilla_dom_workers_workerprivate_h__
#include "Workers.h" #include "mozilla/dom/workers/Workers.h"
#include "js/CharacterEncoding.h" #include "js/CharacterEncoding.h"
#include "nsIContentPolicy.h" #include "nsIContentPolicy.h"
@ -34,8 +34,8 @@
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsTObserverArray.h" #include "nsTObserverArray.h"
#include "Queue.h" #include "mozilla/dom/workerinternals/Queue.h"
#include "WorkerHolder.h" #include "mozilla/dom/workers/bindings/WorkerHolder.h"
#ifdef XP_WIN #ifdef XP_WIN
#undef PostMessage #undef PostMessage
@ -535,6 +535,13 @@ public:
return mLoadInfo.mServiceWorkerID; return mLoadInfo.mServiceWorkerID;
} }
const nsCString&
ServiceWorkerScope() const
{
MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());
return mWorkerName;
}
nsIURI* nsIURI*
GetBaseURI() const GetBaseURI() const
{ {
@ -656,8 +663,8 @@ public:
return mLoadInfo.mPrincipal; return mLoadInfo.mPrincipal;
} }
void nsresult
SetPrincipal(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup); SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
bool bool
UsesSystemPrincipal() const UsesSystemPrincipal() const
@ -701,6 +708,10 @@ public:
mLoadInfo.mCSP = aCSP; mLoadInfo.mCSP = aCSP;
} }
nsresult
SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue,
const nsACString& aCSPReportOnlyHeaderValue);
net::ReferrerPolicy net::ReferrerPolicy
GetReferrerPolicy() const GetReferrerPolicy() const
{ {
@ -827,7 +838,7 @@ public:
const nsCString& const nsCString&
WorkerName() const WorkerName() const
{ {
MOZ_ASSERT(IsServiceWorker() || IsSharedWorker()); MOZ_ASSERT(IsSharedWorker());
return mWorkerName; return mWorkerName;
} }

View file

@ -6,14 +6,14 @@
#ifndef mozilla_dom_workers_workerrunnable_h__ #ifndef mozilla_dom_workers_workerrunnable_h__
#define mozilla_dom_workers_workerrunnable_h__ #define mozilla_dom_workers_workerrunnable_h__
#include "Workers.h" #include "mozilla/dom/workers/Workers.h"
#include "nsICancelableRunnable.h" #include "nsICancelableRunnable.h"
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "nsThreadUtils.h" /* nsRunnable */ #include "nsThreadUtils.h" /* nsRunnable */
#include "WorkerHolder.h" #include "mozilla/dom/workers/bindings/WorkerHolder.h"
struct JSContext; struct JSContext;
class nsIEventTarget; class nsIEventTarget;

View file

@ -58,7 +58,8 @@ NS_CreateJSTimeoutHandler(JSContext* aCx,
extern already_AddRefed<nsIScriptTimeoutHandler> extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, NS_CreateJSTimeoutHandler(JSContext* aCx,
mozilla::dom::workers::WorkerPrivate* aWorkerPrivate, mozilla::dom::workers::WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression); const nsAString& aExpression,
mozilla::ErrorResult& aRv);
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -268,7 +269,7 @@ WorkerGlobalScope::SetTimeout(JSContext* aCx,
nsCOMPtr<nsIScriptTimeoutHandler> handler = nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv); NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aArguments, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (!handler) {
return 0; return 0;
} }
@ -285,7 +286,11 @@ WorkerGlobalScope::SetTimeout(JSContext* aCx,
mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIScriptTimeoutHandler> handler = nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler); NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aRv);
if (!handler) {
return 0;
}
return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv); return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, false, aRv);
} }
@ -326,7 +331,10 @@ WorkerGlobalScope::SetInterval(JSContext* aCx,
Sequence<JS::Value> dummy; Sequence<JS::Value> dummy;
nsCOMPtr<nsIScriptTimeoutHandler> handler = nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler); NS_CreateJSTimeoutHandler(aCx, mWorkerPrivate, aHandler, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return 0;
}
return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv); return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, true, aRv);
} }

View file

@ -268,6 +268,8 @@ struct WorkerLoadInfo
~WorkerLoadInfo(); ~WorkerLoadInfo();
void StealFrom(WorkerLoadInfo& aOther); void StealFrom(WorkerLoadInfo& aOther);
nsresult SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
}; };
// All of these are implemented in RuntimeService.cpp // All of these are implemented in RuntimeService.cpp

View file

@ -19,6 +19,11 @@ EXPORTS.mozilla.dom += [
'WorkerScope.h', 'WorkerScope.h',
] ]
# Private stuff.
EXPORTS.mozilla.dom.workerinternals += [
'Queue.h',
]
EXPORTS.mozilla.dom.workers += [ EXPORTS.mozilla.dom.workers += [
'RuntimeService.h', 'RuntimeService.h',
'ServiceWorkerCommon.h', 'ServiceWorkerCommon.h',

View file

@ -248,10 +248,11 @@ NS_IMETHODIMP
nsXBLContentSink::HandleStartElement(const char16_t *aName, nsXBLContentSink::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount, nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount,
aLineNumber); aLineNumber, aColumnNumber);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
@ -850,7 +851,8 @@ nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
nsresult nsresult
nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
FromParser aFromParser) FromParser aFromParser)
{ {
@ -858,7 +860,7 @@ nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) { if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
#endif #endif
return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo, return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
aLineNumber, aResult, aLineNumber, aColumnNumber, aResult,
aAppendContent, aFromParser); aAppendContent, aFromParser);
#ifdef MOZ_XUL #ifdef MOZ_XUL
} }

View file

@ -69,7 +69,8 @@ public:
NS_IMETHOD HandleStartElement(const char16_t *aName, NS_IMETHOD HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) override; uint32_t aLineNumber,
uint32_t aColumnNumber) override;
NS_IMETHOD HandleEndElement(const char16_t *aName) override; NS_IMETHOD HandleEndElement(const char16_t *aName) override;
@ -89,7 +90,8 @@ protected:
bool NotifyForDocElement() override { return false; } bool NotifyForDocElement() override { return false; }
nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
mozilla::dom::FromParser aFromParser) override; mozilla::dom::FromParser aFromParser) override;

View file

@ -446,7 +446,8 @@ nsXMLContentSink::SetParser(nsParserBase* aParser)
nsresult nsresult
nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
FromParser aFromParser) FromParser aFromParser)
{ {
@ -466,6 +467,7 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
) { ) {
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content); nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
sele->SetScriptLineNumber(aLineNumber); sele->SetScriptLineNumber(aLineNumber);
sele->SetScriptColumnNumber(aColumnNumber);
sele->SetCreatorParser(GetParser()); sele->SetCreatorParser(GetParser());
} }
@ -500,6 +502,7 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
} }
if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) { if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
ssle->SetLineNumber(aFromParser ? aLineNumber : 0); ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
ssle->SetColumnNumber(aFromParser ? aColumnNumber : 0);
} }
} }
} }
@ -918,10 +921,11 @@ NS_IMETHODIMP
nsXMLContentSink::HandleStartElement(const char16_t *aName, nsXMLContentSink::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber, return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
true); aColumnNumber, true);
} }
nsresult nsresult
@ -929,6 +933,7 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber, uint32_t aLineNumber,
uint32_t aColumnNumber,
bool aInterruptable) bool aInterruptable)
{ {
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount"); NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
@ -963,7 +968,7 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
nsIDOMNode::ELEMENT_NODE); nsIDOMNode::ELEMENT_NODE);
result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber, result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
getter_AddRefs(content), &appendContent, aColumnNumber, getter_AddRefs(content), &appendContent,
FROM_PARSER_NETWORK); FROM_PARSER_NETWORK);
NS_ENSURE_SUCCESS(result, result); NS_ENSURE_SUCCESS(result, result);

View file

@ -114,7 +114,8 @@ protected:
nsIContent *aContent); nsIContent *aContent);
virtual bool NotifyForDocElement() { return true; } virtual bool NotifyForDocElement() { return true; }
virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
mozilla::dom::FromParser aFromParser); mozilla::dom::FromParser aFromParser);
@ -161,7 +162,7 @@ protected:
nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts, nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aLineNumber, uint32_t aAttsCount, uint32_t aLineNumber,
bool aInterruptable); uint32_t aColumnNumber, bool aInterruptable);
nsresult HandleEndElement(const char16_t *aName, bool aInterruptable); nsresult HandleEndElement(const char16_t *aName, bool aInterruptable);
nsresult HandleCharacterData(const char16_t *aData, uint32_t aLength, nsresult HandleCharacterData(const char16_t *aData, uint32_t aLength,
bool aInterruptable); bool aInterruptable);

View file

@ -83,7 +83,8 @@ protected:
nsIAtom* aTagName, nsIAtom* aTagName,
nsIContent* aContent) override; nsIContent* aContent) override;
virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
mozilla::dom::FromParser aFromParser) override; mozilla::dom::FromParser aFromParser) override;
virtual nsresult CloseElement(nsIContent* aContent) override; virtual nsresult CloseElement(nsIContent* aContent) override;
@ -199,7 +200,8 @@ nsXMLFragmentContentSink::SetDocElement(int32_t aNameSpaceID,
nsresult nsresult
nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent, nsIContent** aResult, bool* aAppendContent,
FromParser /*aFromParser*/) FromParser /*aFromParser*/)
{ {
@ -207,6 +209,7 @@ nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCo
// fancy CloseElement stuff. // fancy CloseElement stuff.
nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount, nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount,
aNodeInfo, aLineNumber, aNodeInfo, aLineNumber,
aColumnNumber,
aResult, aAppendContent, aResult, aAppendContent,
NOT_FROM_PARSER); NOT_FROM_PARSER);

View file

@ -122,7 +122,8 @@ NS_IMETHODIMP
txStylesheetSink::HandleStartElement(const char16_t *aName, txStylesheetSink::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount"); NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");

View file

@ -437,7 +437,8 @@ NS_IMETHODIMP
XULContentSinkImpl::HandleStartElement(const char16_t *aName, XULContentSinkImpl::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
// XXX Hopefully the parser will flag this before we get here. If // XXX Hopefully the parser will flag this before we get here. If
// we're in the epilog, there should be no new elements // we're in the epilog, there should be no new elements
@ -694,7 +695,7 @@ XULContentSinkImpl::ReportError(const char16_t* aErrorText,
parsererror.Append((char16_t)0xFFFF); parsererror.Append((char16_t)0xFFFF);
parsererror.AppendLiteral("parsererror"); parsererror.AppendLiteral("parsererror");
rv = HandleStartElement(parsererror.get(), noAtts, 0, 0); rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
NS_ENSURE_SUCCESS(rv,rv); NS_ENSURE_SUCCESS(rv,rv);
rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText)); rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
@ -704,7 +705,7 @@ XULContentSinkImpl::ReportError(const char16_t* aErrorText,
sourcetext.Append((char16_t)0xFFFF); sourcetext.Append((char16_t)0xFFFF);
sourcetext.AppendLiteral("sourcetext"); sourcetext.AppendLiteral("sourcetext");
rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0); rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
NS_ENSURE_SUCCESS(rv,rv); NS_ENSURE_SUCCESS(rv,rv);
rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText)); rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));

View file

@ -67,6 +67,7 @@ static const char *kTypeString[] = {
"", // TYPE_INTERNAL_STYLESHEET_PRELOAD "", // TYPE_INTERNAL_STYLESHEET_PRELOAD
"", // TYPE_INTERNAL_IMAGE_FAVICON "", // TYPE_INTERNAL_IMAGE_FAVICON
"saveas_download", "saveas_download",
"", // TYPE_INTERNAL_WORKERS_IMPORT_SCRIPTS
}; };
#define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString) #define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)

View file

@ -64,10 +64,10 @@ typedef bool
/* /*
* Used to check if a CSP instance wants to disable eval() and friends. * Used to check if a CSP instance wants to disable eval() and friends.
* See js_CheckCSPPermitsJSAction() in jsobj. * See GlobalObject::isRuntimeCodeGenEnabled() in vm/GlobalObject.cpp.
*/ */
typedef bool typedef bool
(* JSCSPEvalChecker)(JSContext* cx); (* JSCSPEvalChecker)(JSContext* cx, JS::HandleValue aValue);
struct JSSecurityCallbacks { struct JSSecurityCallbacks {
JSCSPEvalChecker contentSecurityPolicyAllows; JSCSPEvalChecker contentSecurityPolicyAllows;

View file

@ -227,7 +227,7 @@ EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr cal
AssertInnerizedEnvironmentChain(cx, *env); AssertInnerizedEnvironmentChain(cx, *env);
Rooted<GlobalObject*> envGlobal(cx, &env->global()); Rooted<GlobalObject*> envGlobal(cx, &env->global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, envGlobal)) { if (!GlobalObject::isRuntimeCodeGenEnabled(cx, v, envGlobal)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL); JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
return false; return false;
} }
@ -330,7 +330,8 @@ js::DirectEvalStringFromIon(JSContext* cx,
AssertInnerizedEnvironmentChain(cx, *env); AssertInnerizedEnvironmentChain(cx, *env);
Rooted<GlobalObject*> envGlobal(cx, &env->global()); Rooted<GlobalObject*> envGlobal(cx, &env->global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, envGlobal)) { RootedValue v(cx, StringValue(str));
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, v, envGlobal)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL); JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
return false; return false;
} }

View file

@ -150,8 +150,8 @@ MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest
MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS, 0, JSEXN_RANGEERR, "too many arguments provided for a function call") MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS, 0, JSEXN_RANGEERR, "too many arguments provided for a function call")
// CSP // CSP
MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_ERR, "call to eval() blocked by CSP") MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_EVALERR, "call to eval() blocked by CSP")
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_ERR, "call to Function() blocked by CSP") MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_EVALERR, "call to Function() blocked by CSP")
// Wrappers // Wrappers
MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}") MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}")

View file

@ -1625,13 +1625,6 @@ static bool
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind, FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind) FunctionAsyncKind asyncKind)
{ {
// Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
return false;
}
bool isStarGenerator = generatorKind == StarGenerator; bool isStarGenerator = generatorKind == StarGenerator;
bool isAsync = asyncKind == AsyncFunction; bool isAsync = asyncKind == AsyncFunction;
MOZ_ASSERT(generatorKind != LegacyGenerator); MOZ_ASSERT(generatorKind != LegacyGenerator);
@ -1733,6 +1726,14 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
if (!functionText) if (!functionText)
return false; return false;
// Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global());
RootedValue v(cx, StringValue(functionText));
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, v, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
return false;
}
/* /*
* NB: (new Function) is not lexically closed by its caller, it's just an * NB: (new Function) is not lexically closed by its caller, it's just an
* anonymous function in the top-level scope that its constructor inhabits. * anonymous function in the top-level scope that its constructor inhabits.

View file

@ -543,17 +543,23 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
} }
/* static */ bool /* static */ bool
GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global) GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, HandleValue code,
Handle<GlobalObject*> global)
{ {
HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED); HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
if (v.isUndefined()) { if (v.isUndefined()) {
/* /*
* If there are callbacks, make sure that the CSP callback is installed * If there are callbacks, make sure that the CSP callback is installed
* and that it permits runtime code generation, then cache the result. * and that it permits runtime code generation.
*/ */
JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows; JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
Value boolValue = BooleanValue(!allows || allows(cx)); if (allows)
v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue); return allows(cx, code);
// Let's cache the result only if the contentSecurityPolicyAllows callback is not set. In
// this way, contentSecurityPolicyAllows callback is executed each time, with the current
// HandleValue code.
v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, JS::TrueValue());
} }
return !v.isFalse(); return !v.isFalse();
} }

View file

@ -803,7 +803,8 @@ class GlobalObject : public NativeObject
template<typename T> template<typename T>
inline Value createArrayFromBuffer() const; inline Value createArrayFromBuffer() const;
static bool isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global); static bool isRuntimeCodeGenEnabled(JSContext* cx, HandleValue code,
Handle<GlobalObject*> global);
// Warn about use of the deprecated watch/unwatch functions in the global // Warn about use of the deprecated watch/unwatch functions in the global
// in which |obj| was created, if no prior warning was given. // in which |obj| was created, if no prior warning was given.

View file

@ -955,7 +955,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
csp->LogViolationDetails( csp->LogViolationDetails(
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE, nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE,
NS_ConvertUTF8toUTF16(spec), EmptyString(), NS_ConvertUTF8toUTF16(spec), EmptyString(),
0, EmptyString(), EmptyString()); 0, 0, EmptyString(), EmptyString());
return NS_OK; return NS_OK;
} }
} else { } else {

View file

@ -739,6 +739,7 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
nsIURI* aSourceURI, nsIURI* aSourceURI,
uint32_t aLineNumber, uint32_t aLineNumber,
uint32_t aColumnNumber,
const nsSubstring& aStyleText, const nsSubstring& aStyleText,
nsresult* aRv) nsresult* aRv)
{ {
@ -776,7 +777,7 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET, rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
nonce, nonce,
false, // aParserCreated only applies to scripts false, // aParserCreated only applies to scripts
aStyleText, aLineNumber, aStyleText, aLineNumber, aColumnNumber,
&allowInlineStyle); &allowInlineStyle);
NS_ENSURE_SUCCESS(rv, false); NS_ENSURE_SUCCESS(rv, false);

View file

@ -164,6 +164,9 @@ public:
* @param aLineNumber * @param aLineNumber
* Line number of inline style element in the containing document (for * Line number of inline style element in the containing document (for
* reporting violations) * reporting violations)
* @param aColumnNumber
* Column number of inline style element in the containing document (for
* reporting violations)
* @param aStyleText * @param aStyleText
* Contents of the inline style element (for reporting violations) * Contents of the inline style element (for reporting violations)
* @param aRv * @param aRv
@ -175,6 +178,7 @@ public:
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
nsIURI* aSourceURI, nsIURI* aSourceURI,
uint32_t aLineNumber, uint32_t aLineNumber,
uint32_t aColumnNumber,
const nsSubstring& aStyleText, const nsSubstring& aStyleText,
nsresult* aRv); nsresult* aRv);

View file

@ -2204,6 +2204,9 @@ pref("security.sri.enable", true);
// Block scripts with wrong MIME type such as image/ or video/. // Block scripts with wrong MIME type such as image/ or video/.
pref("security.block_script_with_wrong_mime", true); pref("security.block_script_with_wrong_mime", true);
// Block scripts with wrong MIME type when loading via importScripts() in workers.
pref("security.block_importScripts_with_wrong_mime", false);
// Block images of wrong MIME for XCTO: nosniff. // Block images of wrong MIME for XCTO: nosniff.
pref("security.xcto_nosniff_block_images", false); pref("security.xcto_nosniff_block_images", false);

View file

@ -1160,35 +1160,42 @@ EnsureMIMEOfScript(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo*
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/plain"))) { if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/plain"))) {
// script load has type text/plain // script load has type text/plain
return NS_OK; } else if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/xml"))) {
}
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/xml"))) {
// script load has type text/xml // script load has type text/xml
return NS_OK; } else if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("application/octet-stream"))) {
}
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("application/octet-stream"))) {
// script load has type application/octet-stream // script load has type application/octet-stream
return NS_OK; } else if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("application/xml"))) {
}
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("application/xml"))) {
// script load has type application/xml // script load has type application/xml
return NS_OK; } else if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/html"))) {
}
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("text/html"))) {
// script load has type text/html // script load has type text/html
return NS_OK; } else if (contentType.IsEmpty()) {
}
if (contentType.IsEmpty()) {
// script load has no type // script load has no type
return NS_OK; } else {
// script load has unknown type
// We restrict importScripts() in worker code to JavaScript MIME types.
if (aLoadInfo->InternalContentPolicyType() ==
nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS) {
// Instead of consulting Preferences::GetBool() all the time we
// can cache the result to speed things up.
static bool sCachedBlockImportScriptsWithWrongMime = false;
static bool sIsInited = false;
if (!sIsInited) {
sIsInited = true;
Preferences::AddBoolVarCache(
&sCachedBlockImportScriptsWithWrongMime,
"security.block_importScripts_with_wrong_mime");
}
// Do not block the load if the feature is not enabled.
if (!sCachedBlockImportScriptsWithWrongMime) {
return NS_OK;
}
ReportTypeBlocking(aURI, aLoadInfo, "BlockImportScriptsWithWrongMimeType");
return NS_ERROR_CORRUPTED_CONTENT;
}
} }
// script load has unknown type
return NS_OK; return NS_OK;
} }

View file

@ -394,7 +394,8 @@ nsExpatDriver::HandleStartElement(const char16_t *aValue,
nsresult rv = mSink-> nsresult rv = mSink->
HandleStartElement(aValue, aAtts, attrArrayLength, HandleStartElement(aValue, aAtts, attrArrayLength,
XML_GetCurrentLineNumber(mExpatParser)); XML_GetCurrentLineNumber(mExpatParser),
XML_GetCurrentColumnNumber(mExpatParser));
MaybeStopParser(rv); MaybeStopParser(rv);
} }
} }

View file

@ -28,11 +28,13 @@ interface nsIExpatSink : nsISupports
* present in aAtts. * present in aAtts.
* @param aAttsCount the number of elements in aAtts. * @param aAttsCount the number of elements in aAtts.
* @param aLineNumber the line number of the start tag in the data stream. * @param aLineNumber the line number of the start tag in the data stream.
* @param aColumnNumber the column number of the start tag in the data stream.
*/ */
void HandleStartElement(in wstring aName, void HandleStartElement(in wstring aName,
[array, size_is(aAttsCount)] in wstring aAtts, [array, size_is(aAttsCount)] in wstring aAtts,
in unsigned long aAttsCount, in unsigned long aAttsCount,
in unsigned long aLineNumber); in unsigned long aLineNumber,
in unsigned long aColumnNumber);
/** /**
* Called to handle the closing tag of an element. * Called to handle the closing tag of an element.

View file

@ -82,7 +82,8 @@ NS_IMETHODIMP
nsSAXXMLReader::HandleStartElement(const char16_t *aName, nsSAXXMLReader::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
if (!mContentHandler) if (!mContentHandler)
return NS_OK; return NS_OK;

View file

@ -389,7 +389,8 @@ NS_IMETHODIMP
RDFContentSinkImpl::HandleStartElement(const char16_t *aName, RDFContentSinkImpl::HandleStartElement(const char16_t *aName,
const char16_t **aAtts, const char16_t **aAtts,
uint32_t aAttsCount, uint32_t aAttsCount,
uint32_t aLineNumber) uint32_t aLineNumber,
uint32_t aColumnNumber)
{ {
FlushText(); FlushText();