mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 05:46:58 +00:00
Issue #2402 - CSP Violation events should have the correct sample for inline contexts. https://bugzilla.mozilla.org/show_bug.cgi?id=1473587 Add preference to increase max length of CSP report source sample. https://bugzilla.mozilla.org/show_bug.cgi?id=1415352 Return valid columnNumber value in CSP violation events. https://bugzilla.mozilla.org/show_bug.cgi?id=1418246
This commit is contained in:
@@ -535,7 +535,8 @@ NS_IMPL_ISUPPORTS(nsScriptSecurityManager,
|
||||
///////////////// Security Checks /////////////////
|
||||
|
||||
bool
|
||||
nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
|
||||
nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx,
|
||||
JS::HandleValue aValue)
|
||||
{
|
||||
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
|
||||
@@ -558,12 +559,23 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
|
||||
}
|
||||
|
||||
if (reportViolation) {
|
||||
nsAutoString fileName;
|
||||
unsigned lineNum = 0;
|
||||
NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
|
||||
JS::Rooted<JSString*> jsString(cx, JS::ToString(cx, aValue));
|
||||
if (NS_WARN_IF(!jsString)) {
|
||||
JS_ClearPendingException(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoJSString scriptSample;
|
||||
if (NS_WARN_IF(!scriptSample.init(cx, jsString))) {
|
||||
JS_ClearPendingException(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
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()) {
|
||||
CopyUTF8toUTF16(nsDependentCString(file), fileName);
|
||||
}
|
||||
@@ -574,6 +586,7 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
|
||||
fileName,
|
||||
scriptSample,
|
||||
lineNum,
|
||||
columnNum,
|
||||
EmptyString(),
|
||||
EmptyString());
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ private:
|
||||
|
||||
// Decides, based on CSP, whether or not eval() and stuff can be executed.
|
||||
static bool
|
||||
ContentSecurityPolicyPermitsJSAction(JSContext *cx);
|
||||
ContentSecurityPolicyPermitsJSAction(JSContext *cx, JS::HandleValue aValue);
|
||||
|
||||
static bool
|
||||
JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second);
|
||||
|
||||
@@ -11910,6 +11910,7 @@ nsIDocument::InlineScriptAllowedByCSP()
|
||||
true, // aParserCreated
|
||||
EmptyString(), // FIXME get script sample (bug 1314567)
|
||||
0, // aLineNumber
|
||||
0, // aColumnNumber
|
||||
&allowsInlineScript);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,19 @@ public:
|
||||
* was set
|
||||
*/
|
||||
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,
|
||||
|
||||
@@ -40,6 +40,7 @@ nsStyleLinkElement::nsStyleLinkElement()
|
||||
: mDontLoadStyle(false)
|
||||
, mUpdatesEnabled(true)
|
||||
, mLineNumber(1)
|
||||
, mColumnNumber(1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -127,6 +128,18 @@ nsStyleLinkElement::GetLineNumber()
|
||||
return mLineNumber;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsStyleLinkElement::SetColumnNumber(uint32_t aColumnNumber)
|
||||
{
|
||||
mColumnNumber = aColumnNumber;
|
||||
}
|
||||
|
||||
/* virtual */ uint32_t
|
||||
nsStyleLinkElement::GetColumnNumber()
|
||||
{
|
||||
return mColumnNumber;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsStyleLinkElement::IsImportEnabled()
|
||||
{
|
||||
@@ -412,8 +425,10 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
|
||||
thisContent->NodePrincipal(),
|
||||
doc->GetDocumentURI(),
|
||||
mLineNumber, text, &rv))
|
||||
mLineNumber, mColumnNumber, text,
|
||||
&rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Parse the style sheet.
|
||||
rv = doc->CSSLoader()->
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
|
||||
virtual void SetLineNumber(uint32_t aLineNumber) override;
|
||||
virtual uint32_t GetLineNumber() override;
|
||||
void SetColumnNumber(uint32_t aColumnNumber) override;
|
||||
uint32_t GetColumnNumber() override;
|
||||
|
||||
enum RelValue {
|
||||
ePREFETCH = 0x00000001,
|
||||
@@ -140,6 +142,7 @@ protected:
|
||||
bool mDontLoadStyle;
|
||||
bool mUpdatesEnabled;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumnNumber;
|
||||
};
|
||||
|
||||
#endif /* nsStyleLinkElement_h___ */
|
||||
|
||||
@@ -191,7 +191,7 @@ nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
|
||||
|
||||
if (!isNativeAnon &&
|
||||
!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(),
|
||||
doc->GetDocumentURI(), 0, aValue,
|
||||
doc->GetDocumentURI(), 0, 0, aValue,
|
||||
nullptr))
|
||||
return;
|
||||
|
||||
|
||||
@@ -786,28 +786,22 @@ EventListenerManager::SetEventHandler(nsIAtom* aName,
|
||||
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (csp) {
|
||||
// let's generate a script sample and pass it as aContent,
|
||||
// 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");
|
||||
unsigned lineNum = 0;
|
||||
unsigned columnNum = 0;
|
||||
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
if (cx && !JS::DescribeScriptedCaller(cx, nullptr, &lineNum, &columnNum)) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
|
||||
if (csp) {
|
||||
bool allowsInlineScript = true;
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
EmptyString(), // aNonce
|
||||
true, // aParserCreated (true because attribute event handler)
|
||||
scriptSample,
|
||||
0, // aLineNumber
|
||||
aBody,
|
||||
lineNum, // aLineNumber
|
||||
columnNum, // aColumnNumber
|
||||
&allowsInlineScript);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
@@ -140,6 +140,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
* (and compare to the hashes listed in the policy)
|
||||
* @param aLineNumber The line number of the inline resource
|
||||
* (used for reporting)
|
||||
* @param aColumnNumber The column number of the inline resource
|
||||
* (used for reporting)
|
||||
* @return
|
||||
* Whether or not the effects of the inline style should be allowed
|
||||
* (block the rules if false).
|
||||
@@ -148,7 +150,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
in AString aNonce,
|
||||
in boolean aParserCreated,
|
||||
in AString aContent,
|
||||
in unsigned long aLineNumber);
|
||||
in unsigned long aLineNumber,
|
||||
in unsigned long aColumnNumber);
|
||||
|
||||
/**
|
||||
* whether this policy allows eval and eval-like functions
|
||||
@@ -188,6 +191,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
* sample of the violating content (to aid debugging)
|
||||
* @param lineNum
|
||||
* source line number of the violation (if available)
|
||||
* @param columnNum
|
||||
* source column number of the violation (if available)
|
||||
* @param aNonce
|
||||
* (optional) If this is a nonce violation, include the nonce so we can
|
||||
* recheck to determine which policies were violated and send the
|
||||
@@ -202,6 +207,7 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
in AString sourceFile,
|
||||
in AString scriptSample,
|
||||
in int32_t lineNum,
|
||||
in int32_t columnNum,
|
||||
[optional] in AString nonce,
|
||||
[optional] in AString content);
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
||||
true, // aParserCreated
|
||||
EmptyString(), // aContent
|
||||
0, // aLineNumber
|
||||
0, // aColumnNumber
|
||||
&allowsInlineScript);
|
||||
|
||||
//return early if inline scripts are not allowed
|
||||
|
||||
@@ -1474,6 +1474,7 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
nonce, parserCreated, scriptText,
|
||||
aElement->GetScriptLineNumber(),
|
||||
aElement->GetScriptColumnNumber(),
|
||||
&allowInlineScript);
|
||||
return allowInlineScript;
|
||||
}
|
||||
@@ -2695,10 +2696,11 @@ ScriptLoader::VerifySRI(ScriptLoadRequest* aRequest,
|
||||
nsAutoCString violationURISpec;
|
||||
mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
|
||||
uint32_t lineNo = aRequest->Element() ? aRequest->Element()->GetScriptLineNumber() : 0;
|
||||
uint32_t columnNo = aRequest->Element() ? aRequest->Element()->GetScriptColumnNumber() : 0;
|
||||
csp->LogViolationDetails(
|
||||
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
|
||||
NS_ConvertUTF8toUTF16(violationURISpec),
|
||||
EmptyString(), lineNo, EmptyString(), EmptyString());
|
||||
EmptyString(), lineNo, columnNo, EmptyString(), EmptyString());
|
||||
rv = NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
|
||||
explicit nsIScriptElement(mozilla::dom::FromParser aFromParser)
|
||||
: mLineNumber(1),
|
||||
mColumnNumber(1),
|
||||
mAlreadyStarted(false),
|
||||
mMalformed(false),
|
||||
mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
|
||||
@@ -138,6 +139,16 @@ public:
|
||||
return mLineNumber;
|
||||
}
|
||||
|
||||
void SetScriptColumnNumber(uint32_t aColumnNumber)
|
||||
{
|
||||
mColumnNumber = aColumnNumber;
|
||||
}
|
||||
|
||||
uint32_t GetScriptColumnNumber()
|
||||
{
|
||||
return mColumnNumber;
|
||||
}
|
||||
|
||||
void SetIsMalformed()
|
||||
{
|
||||
mMalformed = true;
|
||||
@@ -281,6 +292,11 @@ protected:
|
||||
*/
|
||||
uint32_t mLineNumber;
|
||||
|
||||
/**
|
||||
* The start column number of the script.
|
||||
*/
|
||||
uint32_t mColumnNumber;
|
||||
|
||||
/**
|
||||
* The "already started" flag per HTML5.
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ CheckInternal(nsIContentSecurityPolicy* aCSP,
|
||||
if (reportViolation) {
|
||||
aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
|
||||
aFileNameString, aExpression, aLineNum,
|
||||
EmptyString(), EmptyString());
|
||||
aColumnNum, EmptyString(), EmptyString());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/CSPReportBinding.h"
|
||||
#include "mozilla/dom/CSPDictionariesBinding.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
@@ -271,7 +272,8 @@ nsCSPContext::permitsInternal(CSPDirective aDir,
|
||||
EmptyString(), /* no observer subject */
|
||||
EmptyString(), /* no source file */
|
||||
EmptyString(), /* no script sample */
|
||||
0); /* no line number */
|
||||
0, /* no line number */
|
||||
0); /* no column number */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,6 +300,14 @@ nsCSPContext::nsCSPContext()
|
||||
, mLoadingPrincipal(nullptr)
|
||||
, mQueueUpMessages(true)
|
||||
{
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized) {
|
||||
Preferences::AddIntVarCache(&sScriptSampleMaxLength,
|
||||
"security.csp.reporting.script-sample.max-length",
|
||||
40);
|
||||
sInitialized = true;
|
||||
}
|
||||
|
||||
CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
|
||||
}
|
||||
|
||||
@@ -470,7 +480,8 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
|
||||
const nsAString& aContent,
|
||||
const nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
nsString observerSubject;
|
||||
// if the nonce is non empty, then we report the nonce error, otherwise
|
||||
@@ -500,9 +511,9 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
|
||||
}
|
||||
|
||||
nsAutoString codeSample(aContent);
|
||||
// cap the length of the script sample at 40 chars
|
||||
if (codeSample.Length() > 40) {
|
||||
codeSample.Truncate(40);
|
||||
// cap the length of the script sample
|
||||
if (codeSample.Length() > ScriptSampleMaxLength()) {
|
||||
codeSample.Truncate(ScriptSampleMaxLength());
|
||||
codeSample.AppendLiteral("...");
|
||||
}
|
||||
AsyncReportViolation(selfISupports, // aBlockedContentSource
|
||||
@@ -512,7 +523,8 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
|
||||
observerSubject, // aObserverSubject
|
||||
NS_ConvertUTF8toUTF16(sourceFile), // aSourceFile
|
||||
codeSample, // aScriptSample
|
||||
aLineNumber); // aLineNum
|
||||
aLineNumber, // aLineNum
|
||||
aColumnNumber); // aColumnNum
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -521,6 +533,7 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
||||
bool aParserCreated,
|
||||
const nsAString& aContent,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
bool* outAllowsInline)
|
||||
{
|
||||
*outAllowsInline = true;
|
||||
@@ -565,7 +578,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
||||
aContent,
|
||||
violatedDirective,
|
||||
i,
|
||||
aLineNumber);
|
||||
aLineNumber,
|
||||
aColumnNumber);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@@ -584,7 +598,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
||||
* which is why we must check allows() again here.
|
||||
*
|
||||
* 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)
|
||||
* such as INLINE_SCRIPT
|
||||
@@ -611,8 +626,8 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
||||
nsIContentPolicy::TYPE_ ## contentPolicyType, \
|
||||
violatedDirective); \
|
||||
this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
|
||||
NS_LITERAL_STRING(observerTopic), \
|
||||
aSourceFile, aScriptSample, aLineNum); \
|
||||
NS_LITERAL_STRING(observerTopic), aSourceFile,\
|
||||
aScriptSample, aLineNum, aColumnNum); \
|
||||
} \
|
||||
PR_END_MACRO; \
|
||||
break
|
||||
@@ -644,6 +659,7 @@ nsCSPContext::LogViolationDetails(uint16_t aViolationType,
|
||||
const nsAString& aSourceFile,
|
||||
const nsAString& aScriptSample,
|
||||
int32_t aLineNum,
|
||||
int32_t aColumnNum,
|
||||
const nsAString& aNonce,
|
||||
const nsAString& aContent)
|
||||
{
|
||||
@@ -844,6 +860,7 @@ nsCSPContext::GatherSecurityPolicyViolationEventData(
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum,
|
||||
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
|
||||
{
|
||||
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
||||
@@ -907,8 +924,19 @@ nsCSPContext::GatherSecurityPolicyViolationEventData(
|
||||
aViolationEventInit.mSourceFile = aSourceFile;
|
||||
}
|
||||
|
||||
// sample
|
||||
// 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()
|
||||
@@ -936,8 +964,7 @@ nsCSPContext::GatherSecurityPolicyViolationEventData(
|
||||
aViolationEventInit.mLineNumber = aLineNum;
|
||||
|
||||
// column-number
|
||||
// TODO: Set correct column number.
|
||||
aViolationEventInit.mColumnNumber = 0;
|
||||
aViolationEventInit.mColumnNumber = aColumnNum;
|
||||
|
||||
aViolationEventInit.mBubbles = true;
|
||||
aViolationEventInit.mComposed = true;
|
||||
@@ -1012,7 +1039,8 @@ nsCSPContext::SendReports(
|
||||
reportURICstring.get()));
|
||||
logToConsole(u"triedToSendReport", params, ArrayLength(params),
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
|
||||
nsIScriptError::errorFlag);
|
||||
continue; // don't return yet, there may be more URIs
|
||||
}
|
||||
|
||||
@@ -1054,7 +1082,8 @@ nsCSPContext::SendReports(
|
||||
const char16_t* params[] = { reportURIs[r].get() };
|
||||
logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params),
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
|
||||
nsIScriptError::errorFlag);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1119,7 +1148,8 @@ nsCSPContext::SendReports(
|
||||
CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0]));
|
||||
logToConsole(u"triedToSendReport", params, ArrayLength(params),
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mLineNumber, aViolationEventInit.mColumnNumber,
|
||||
nsIScriptError::errorFlag);
|
||||
} else {
|
||||
CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
|
||||
}
|
||||
@@ -1162,6 +1192,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
const nsAString& aSourceFile,
|
||||
const nsAString& aScriptSample,
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum,
|
||||
nsCSPContext* aCSPContext)
|
||||
: mBlockedContentSource(aBlockedContentSource)
|
||||
, mOriginalURI(aOriginalURI)
|
||||
@@ -1171,6 +1202,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
, mSourceFile(aSourceFile)
|
||||
, mScriptSample(aScriptSample)
|
||||
, mLineNum(aLineNum)
|
||||
, mColumnNum(aColumnNum)
|
||||
, mCSPContext(aCSPContext)
|
||||
{
|
||||
NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
|
||||
@@ -1208,7 +1240,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
blockedURI, blockedDataStr, mOriginalURI,
|
||||
mViolatedDirective, mViolatedPolicyIndex,
|
||||
mSourceFile, mScriptSample, mLineNum,
|
||||
init);
|
||||
mColumnNum, init);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 1) notify observers
|
||||
@@ -1223,15 +1255,22 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
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) {
|
||||
blockedURI->GetSpec(blockedDataStr);
|
||||
bool isData = false;
|
||||
rv = blockedURI->SchemeIs("data", &isData);
|
||||
if (NS_SUCCEEDED(rv) && isData) {
|
||||
blockedDataStr.Truncate(40);
|
||||
blockedDataStr.AppendASCII("...");
|
||||
if (blockedDataStr.Length() > nsCSPContext::ScriptSampleMaxLength()) {
|
||||
bool isData = false;
|
||||
rv = blockedURI->SchemeIs("data", &isData);
|
||||
if (NS_SUCCEEDED(rv) && isData &&
|
||||
blockedDataStr.Length() > nsCSPContext::ScriptSampleMaxLength()) {
|
||||
blockedDataStr.Truncate(nsCSPContext::ScriptSampleMaxLength());
|
||||
blockedDataStr.Append(NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis()));
|
||||
}
|
||||
}
|
||||
} else if (blockedString) {
|
||||
blockedString->GetData(blockedDataStr);
|
||||
}
|
||||
|
||||
if (blockedDataStr.Length() > 0) {
|
||||
@@ -1241,7 +1280,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" :
|
||||
u"CSPViolationWithURI",
|
||||
params, ArrayLength(params), mSourceFile, mScriptSample,
|
||||
mLineNum, 0, nsIScriptError::errorFlag);
|
||||
mLineNum, mColumnNum, nsIScriptError::errorFlag);
|
||||
}
|
||||
|
||||
// 4) fire violation event
|
||||
@@ -1260,6 +1299,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
nsString mSourceFile;
|
||||
nsString mScriptSample;
|
||||
uint32_t mLineNum;
|
||||
uint32_t mColumnNum;
|
||||
RefPtr<nsCSPContext> mCSPContext;
|
||||
};
|
||||
|
||||
@@ -1287,6 +1327,8 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
* a sample of the violating inline script
|
||||
* @param aLineNum
|
||||
* source line number of the violation (if available)
|
||||
* @param aColumnNum
|
||||
* source column number of the violation (if available)
|
||||
*/
|
||||
nsresult
|
||||
nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
|
||||
@@ -1296,7 +1338,8 @@ nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
|
||||
const nsAString& aObserverSubject,
|
||||
const nsAString& aSourceFile,
|
||||
const nsAString& aScriptSample,
|
||||
uint32_t aLineNum)
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum)
|
||||
{
|
||||
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
||||
|
||||
@@ -1309,6 +1352,7 @@ nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
|
||||
aSourceFile,
|
||||
aScriptSample,
|
||||
aLineNum,
|
||||
aColumnNum,
|
||||
this));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum,
|
||||
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
|
||||
|
||||
nsresult SendReports(
|
||||
@@ -101,7 +102,8 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
const nsAString& aObserverSubject,
|
||||
const nsAString& aSourceFile,
|
||||
const nsAString& aScriptSample,
|
||||
uint32_t aLineNum);
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum);
|
||||
|
||||
// Hands off! Don't call this method unless you know what you
|
||||
// are doing. It's only supposed to be called from within
|
||||
@@ -110,10 +112,14 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
mLoadingPrincipal = nullptr;
|
||||
}
|
||||
|
||||
nsWeakPtr GetLoadingContext(){
|
||||
nsWeakPtr GetLoadingContext() {
|
||||
return mLoadingContext;
|
||||
}
|
||||
|
||||
static uint32_t ScriptSampleMaxLength() {
|
||||
return std::max(sScriptSampleMaxLength, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
bool permitsInternal(CSPDirective aDir,
|
||||
nsIURI* aContentLocation,
|
||||
@@ -132,7 +138,10 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
const nsAString& aContent,
|
||||
const nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex,
|
||||
uint32_t aLineNumber);
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber);
|
||||
|
||||
static int32_t sScriptSampleMaxLength;
|
||||
|
||||
nsString mReferrer;
|
||||
uint64_t mInnerWindowID; // used for web console logging
|
||||
|
||||
@@ -405,7 +405,7 @@ nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
|
||||
if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
|
||||
doc->NodePrincipal(),
|
||||
doc->GetDocumentURI(),
|
||||
0, aString, nullptr)) {
|
||||
0, 0, aString, nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ dictionary CSPReportProperties {
|
||||
DOMString source-file;
|
||||
DOMString script-sample;
|
||||
long line-number;
|
||||
long column-number;
|
||||
};
|
||||
|
||||
dictionary CSPReport {
|
||||
|
||||
@@ -547,14 +547,21 @@ class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
nsString mFileName;
|
||||
uint32_t mLineNum;
|
||||
uint32_t mColumnNum;
|
||||
nsString mScriptSample;
|
||||
|
||||
public:
|
||||
LogViolationDetailsRunnable(WorkerPrivate* aWorker,
|
||||
const nsString& aFileName,
|
||||
uint32_t aLineNum)
|
||||
uint32_t aLineNum,
|
||||
uint32_t aColumnNum,
|
||||
const nsAString& aScriptSample)
|
||||
: WorkerMainThreadRunnable(aWorker,
|
||||
NS_LITERAL_CSTRING("RuntimeService :: LogViolationDetails"))
|
||||
, mFileName(aFileName), mLineNum(aLineNum)
|
||||
, mFileName(aFileName)
|
||||
, mLineNum(aLineNum)
|
||||
, mColumnNum(aColumnNum)
|
||||
, mScriptSample(aScriptSample)
|
||||
{
|
||||
MOZ_ASSERT(aWorker);
|
||||
}
|
||||
@@ -566,24 +573,38 @@ private:
|
||||
};
|
||||
|
||||
bool
|
||||
ContentSecurityPolicyAllows(JSContext* aCx)
|
||||
ContentSecurityPolicyAllows(JSContext* aCx, JS::HandleValue aValue)
|
||||
{
|
||||
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
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;
|
||||
uint32_t lineNum = 0;
|
||||
uint32_t columnNum = 0;
|
||||
|
||||
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());
|
||||
} else {
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||
}
|
||||
|
||||
RefPtr<LogViolationDetailsRunnable> runnable =
|
||||
new LogViolationDetailsRunnable(worker, fileName, lineNum);
|
||||
new LogViolationDetailsRunnable(worker, fileName, lineNum, columnNum,
|
||||
scriptSample);
|
||||
|
||||
ErrorResult rv;
|
||||
runnable->Dispatch(Killing, rv);
|
||||
@@ -2698,11 +2719,9 @@ LogViolationDetailsRunnable::MainThreadRun()
|
||||
|
||||
nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
|
||||
if (csp) {
|
||||
NS_NAMED_LITERAL_STRING(scriptSample,
|
||||
"Call to eval() or related function blocked by CSP.");
|
||||
if (mWorkerPrivate->GetReportCSPViolations()) {
|
||||
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
|
||||
mFileName, scriptSample, mLineNum,
|
||||
mFileName, mScriptSample, mLineNum, mColumnNum,
|
||||
EmptyString(), EmptyString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1167,7 +1167,7 @@ private:
|
||||
if (wcsp) {
|
||||
wcsp->LogViolationDetails(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -248,10 +248,11 @@ NS_IMETHODIMP
|
||||
nsXBLContentSink::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount,
|
||||
aLineNumber);
|
||||
aLineNumber, aColumnNumber);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@@ -850,7 +851,8 @@ nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
|
||||
|
||||
nsresult
|
||||
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,
|
||||
FromParser aFromParser)
|
||||
{
|
||||
@@ -858,7 +860,7 @@ nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
|
||||
if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
|
||||
#endif
|
||||
return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
|
||||
aLineNumber, aResult,
|
||||
aLineNumber, aColumnNumber, aResult,
|
||||
aAppendContent, aFromParser);
|
||||
#ifdef MOZ_XUL
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ public:
|
||||
NS_IMETHOD HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber) override;
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber) override;
|
||||
|
||||
NS_IMETHOD HandleEndElement(const char16_t *aName) override;
|
||||
|
||||
@@ -89,7 +90,8 @@ protected:
|
||||
bool NotifyForDocElement() override { return false; }
|
||||
|
||||
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,
|
||||
mozilla::dom::FromParser aFromParser) override;
|
||||
|
||||
|
||||
@@ -446,7 +446,8 @@ nsXMLContentSink::SetParser(nsParserBase* aParser)
|
||||
|
||||
nsresult
|
||||
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,
|
||||
FromParser aFromParser)
|
||||
{
|
||||
@@ -466,6 +467,7 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
|
||||
) {
|
||||
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
|
||||
sele->SetScriptLineNumber(aLineNumber);
|
||||
sele->SetScriptColumnNumber(aColumnNumber);
|
||||
sele->SetCreatorParser(GetParser());
|
||||
}
|
||||
|
||||
@@ -500,6 +502,7 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
|
||||
}
|
||||
if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
|
||||
ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
|
||||
ssle->SetColumnNumber(aFromParser ? aColumnNumber : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -918,10 +921,11 @@ NS_IMETHODIMP
|
||||
nsXMLContentSink::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
|
||||
true);
|
||||
aColumnNumber, true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -929,6 +933,7 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
bool aInterruptable)
|
||||
{
|
||||
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
|
||||
@@ -963,7 +968,7 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
|
||||
result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
|
||||
getter_AddRefs(content), &appendContent,
|
||||
aColumnNumber, getter_AddRefs(content), &appendContent,
|
||||
FROM_PARSER_NETWORK);
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
|
||||
@@ -114,7 +114,8 @@ protected:
|
||||
nsIContent *aContent);
|
||||
virtual bool NotifyForDocElement() { return true; }
|
||||
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,
|
||||
mozilla::dom::FromParser aFromParser);
|
||||
|
||||
@@ -161,7 +162,7 @@ protected:
|
||||
|
||||
nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts,
|
||||
uint32_t aAttsCount, uint32_t aLineNumber,
|
||||
bool aInterruptable);
|
||||
uint32_t aColumnNumber, bool aInterruptable);
|
||||
nsresult HandleEndElement(const char16_t *aName, bool aInterruptable);
|
||||
nsresult HandleCharacterData(const char16_t *aData, uint32_t aLength,
|
||||
bool aInterruptable);
|
||||
|
||||
@@ -83,7 +83,8 @@ protected:
|
||||
nsIAtom* aTagName,
|
||||
nsIContent* aContent) override;
|
||||
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,
|
||||
mozilla::dom::FromParser aFromParser) override;
|
||||
virtual nsresult CloseElement(nsIContent* aContent) override;
|
||||
@@ -199,7 +200,8 @@ nsXMLFragmentContentSink::SetDocElement(int32_t aNameSpaceID,
|
||||
|
||||
nsresult
|
||||
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,
|
||||
FromParser /*aFromParser*/)
|
||||
{
|
||||
@@ -207,6 +209,7 @@ nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCo
|
||||
// fancy CloseElement stuff.
|
||||
nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount,
|
||||
aNodeInfo, aLineNumber,
|
||||
aColumnNumber,
|
||||
aResult, aAppendContent,
|
||||
NOT_FROM_PARSER);
|
||||
|
||||
|
||||
@@ -122,7 +122,8 @@ NS_IMETHODIMP
|
||||
txStylesheetSink::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
|
||||
|
||||
|
||||
@@ -437,7 +437,8 @@ NS_IMETHODIMP
|
||||
XULContentSinkImpl::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
// XXX Hopefully the parser will flag this before we get here. If
|
||||
// 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.AppendLiteral("parsererror");
|
||||
|
||||
rv = HandleStartElement(parsererror.get(), noAtts, 0, 0);
|
||||
rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
|
||||
@@ -704,7 +705,7 @@ XULContentSinkImpl::ReportError(const char16_t* aErrorText,
|
||||
sourcetext.Append((char16_t)0xFFFF);
|
||||
sourcetext.AppendLiteral("sourcetext");
|
||||
|
||||
rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0);
|
||||
rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
|
||||
|
||||
@@ -64,10 +64,10 @@ typedef bool
|
||||
|
||||
/*
|
||||
* 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
|
||||
(* JSCSPEvalChecker)(JSContext* cx);
|
||||
(* JSCSPEvalChecker)(JSContext* cx, JS::HandleValue aValue);
|
||||
|
||||
struct JSSecurityCallbacks {
|
||||
JSCSPEvalChecker contentSecurityPolicyAllows;
|
||||
|
||||
@@ -227,7 +227,7 @@ EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr cal
|
||||
AssertInnerizedEnvironmentChain(cx, *env);
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
@@ -330,7 +330,8 @@ js::DirectEvalStringFromIon(JSContext* cx,
|
||||
AssertInnerizedEnvironmentChain(cx, *env);
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
+8
-7
@@ -1625,13 +1625,6 @@ static bool
|
||||
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
|
||||
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 isAsync = asyncKind == AsyncFunction;
|
||||
MOZ_ASSERT(generatorKind != LegacyGenerator);
|
||||
@@ -1733,6 +1726,14 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
||||
if (!functionText)
|
||||
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
|
||||
* anonymous function in the top-level scope that its constructor inhabits.
|
||||
|
||||
@@ -543,17 +543,23 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (v.isUndefined()) {
|
||||
/*
|
||||
* 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;
|
||||
Value boolValue = BooleanValue(!allows || allows(cx));
|
||||
v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue);
|
||||
if (allows)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -803,7 +803,8 @@ class GlobalObject : public NativeObject
|
||||
template<typename T>
|
||||
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
|
||||
// in which |obj| was created, if no prior warning was given.
|
||||
|
||||
@@ -955,7 +955,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
|
||||
csp->LogViolationDetails(
|
||||
nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE,
|
||||
NS_ConvertUTF8toUTF16(spec), EmptyString(),
|
||||
0, EmptyString(), EmptyString());
|
||||
0, 0, EmptyString(), EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -739,6 +739,7 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIURI* aSourceURI,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
const nsSubstring& aStyleText,
|
||||
nsresult* aRv)
|
||||
{
|
||||
@@ -776,7 +777,7 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
|
||||
nonce,
|
||||
false, // aParserCreated only applies to scripts
|
||||
aStyleText, aLineNumber,
|
||||
aStyleText, aLineNumber, aColumnNumber,
|
||||
&allowInlineStyle);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
|
||||
@@ -164,6 +164,9 @@ public:
|
||||
* @param aLineNumber
|
||||
* Line number of inline style element in the containing document (for
|
||||
* reporting violations)
|
||||
* @param aColumnNumber
|
||||
* Column number of inline style element in the containing document (for
|
||||
* reporting violations)
|
||||
* @param aStyleText
|
||||
* Contents of the inline style element (for reporting violations)
|
||||
* @param aRv
|
||||
@@ -175,6 +178,7 @@ public:
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIURI* aSourceURI,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
const nsSubstring& aStyleText,
|
||||
nsresult* aRv);
|
||||
|
||||
|
||||
@@ -394,7 +394,8 @@ nsExpatDriver::HandleStartElement(const char16_t *aValue,
|
||||
|
||||
nsresult rv = mSink->
|
||||
HandleStartElement(aValue, aAtts, attrArrayLength,
|
||||
XML_GetCurrentLineNumber(mExpatParser));
|
||||
XML_GetCurrentLineNumber(mExpatParser),
|
||||
XML_GetCurrentColumnNumber(mExpatParser));
|
||||
MaybeStopParser(rv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,13 @@ interface nsIExpatSink : nsISupports
|
||||
* present in aAtts.
|
||||
* @param aAttsCount the number of elements in aAtts.
|
||||
* @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,
|
||||
[array, size_is(aAttsCount)] in wstring aAtts,
|
||||
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.
|
||||
|
||||
@@ -82,7 +82,8 @@ NS_IMETHODIMP
|
||||
nsSAXXMLReader::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
if (!mContentHandler)
|
||||
return NS_OK;
|
||||
|
||||
@@ -388,8 +388,9 @@ RDFContentSinkImpl::QueryInterface(REFNSIID iid, void** result)
|
||||
NS_IMETHODIMP
|
||||
RDFContentSinkImpl::HandleStartElement(const char16_t *aName,
|
||||
const char16_t **aAtts,
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aAttsCount,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
FlushText();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user