diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 48245a1f7c..3b74aea09c 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -3,6 +3,9 @@ * 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 +#include + #include "nsCOMPtr.h" #include "nsContentPolicyUtils.h" #include "nsContentUtils.h" @@ -58,6 +61,29 @@ GetCspContextLog() 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 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. * Looks like: ! @@ -812,6 +838,8 @@ nsCSPContext::GatherSecurityPolicyViolationEventData( { NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1); + MOZ_ASSERT(ValidateDirectiveName(aViolatedDirective), "Invalid directive name"); + if (!CSPService::sCSPReportingEnabled) { // Reporting is pref-disabled. Don't do any actual work and return success. nsContentUtils::ReportToConsoleNonLocalized( @@ -853,12 +881,15 @@ nsCSPContext::GatherSecurityPolicyViolationEventData( aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(reportBlockedURI); } - // violated-directive - aViolationEventInit.mViolatedDirective = aViolatedDirective; - // 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 nsAutoString originalPolicy; rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy); @@ -1163,20 +1194,23 @@ class CSPReportSenderRunnable final : public Runnable { MOZ_ASSERT(NS_IsMainThread()); + nsresult rv; + // 0) prepare violation data mozilla::dom::SecurityPolicyViolationEventInit init; - mCSPContext->GatherSecurityPolicyViolationEventData( + rv = mCSPContext->GatherSecurityPolicyViolationEventData( mBlockedContentSource, mOriginalURI, mViolatedDirective, mViolatedPolicyIndex, mSourceFile, mScriptSample, mLineNum, init); - + NS_ENSURE_SUCCESS(rv, rv); + // 1) notify observers nsCOMPtr observerService = mozilla::services::GetObserverService(); NS_ASSERTION(observerService, "needs observer service"); - nsresult rv = observerService->NotifyObservers(mObserverSubject, - CSP_VIOLATION_TOPIC, - mViolatedDirective.get()); + rv = observerService->NotifyObservers(mObserverSubject, + CSP_VIOLATION_TOPIC, + mViolatedDirective.get()); NS_ENSURE_SUCCESS(rv, rv); // 2) send reports for the policy that was violated diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index b73bea30a5..f17faddb70 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -1264,6 +1264,12 @@ bool nsCSPDirective::equals(CSPDirective aDirective) const return (mDirective == aDirective); } +void +nsCSPDirective::getDirName(nsAString& outStr) const +{ + outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective)); +} + /* =============== nsCSPChildSrcDirective ============= */ nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective) @@ -1349,6 +1355,13 @@ nsBlockAllMixedContentDirective::toString(nsAString& outStr) const nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)); } +void +nsBlockAllMixedContentDirective::getDirName(nsAString& outStr) const +{ + outStr.AppendASCII(CSP_CSPDirectiveToString( + nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)); +} + /* =============== nsUpgradeInsecureDirective ============= */ nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective) @@ -1367,6 +1380,13 @@ nsUpgradeInsecureDirective::toString(nsAString& outStr) const nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)); } +void +nsUpgradeInsecureDirective::getDirName(nsAString& outStr) const +{ + outStr.AppendASCII(CSP_CSPDirectiveToString( + nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)); +} + /* ===== nsRequireSRIForDirective ========================= */ nsRequireSRIForDirective::nsRequireSRIForDirective(CSPDirective aDirective) @@ -1418,6 +1438,13 @@ nsRequireSRIForDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHas return (aKeyword != CSP_REQUIRE_SRI_FOR); } +void +nsRequireSRIForDirective::getDirName(nsAString& outStr) const +{ + outStr.AppendASCII(CSP_CSPDirectiveToString( + nsIContentSecurityPolicy::REQUIRE_SRI_FOR)); +} + /* ===== nsCSPPolicy ========================= */ nsCSPPolicy::nsCSPPolicy() @@ -1471,7 +1498,7 @@ nsCSPPolicy::permits(CSPDirective aDir, if (mDirectives[i]->equals(aDir)) { if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir, aParserCreated)) { - mDirectives[i]->toString(outViolatedDirective); + mDirectives[i]->getDirName(outViolatedDirective); return false; } return true; @@ -1486,7 +1513,7 @@ nsCSPPolicy::permits(CSPDirective aDir, if (!aSpecific && defaultDir) { if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir, aParserCreated)) { - defaultDir->toString(outViolatedDirective); + defaultDir->getDirName(outViolatedDirective); return false; } return true; @@ -1612,7 +1639,7 @@ nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType, nsCSPDirective* defaultDir = nullptr; for (uint32_t i = 0; i < mDirectives.Length(); i++) { if (mDirectives[i]->restrictsContentType(aContentType)) { - mDirectives[i]->toString(outDirective); + mDirectives[i]->getDirName(outDirective); return; } if (mDirectives[i]->isDefaultDirective()) { @@ -1622,7 +1649,7 @@ nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType, // if we haven't found a matching directive yet, // the contentType must be restricted by the default directive if (defaultDir) { - defaultDir->toString(outDirective); + defaultDir->getDirName(outDirective); return; } NS_ASSERTION(false, "Can not query directive string for contentType!"); diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h index b4c48fb42d..9b9ff46c90 100644 --- a/dom/security/nsCSPUtils.h +++ b/dom/security/nsCSPUtils.h @@ -494,6 +494,8 @@ class nsCSPDirective { bool visitSrcs(nsCSPSrcVisitor* aVisitor) const; + virtual void getDirName(nsAString& outStr) const; + protected: CSPDirective mDirective; nsTArray mSrcs; @@ -572,6 +574,8 @@ class nsBlockAllMixedContentDirective : public nsCSPDirective { void addSrcs(const nsTArray& aSrcs) { MOZ_ASSERT(false, "block-all-mixed-content does not hold any srcs"); } + + void getDirName(nsAString& outStr) const override; }; /* =============== nsUpgradeInsecureDirective === */ @@ -625,6 +629,8 @@ class nsUpgradeInsecureDirective : public nsCSPDirective { void addSrcs(const nsTArray& aSrcs) { MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); } + + void getDirName(nsAString& outStr) const override; }; /* ===== nsRequireSRIForDirective ========================= */ @@ -642,6 +648,7 @@ class nsRequireSRIForDirective : public nsCSPDirective { bool restrictsContentType(nsContentPolicyType aType) const; bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce, bool aParserCreated) const; + void getDirName(nsAString& outStr) const override; private: nsTArray mTypes;