LCOV - code coverage report
Current view: top level - dom/security - nsCSPContext.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 600 0.2 %
Date: 2017-07-14 16:53:18 Functions: 0 62 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsCOMPtr.h"
       8             : #include "nsContentPolicyUtils.h"
       9             : #include "nsContentUtils.h"
      10             : #include "nsCSPContext.h"
      11             : #include "nsCSPParser.h"
      12             : #include "nsCSPService.h"
      13             : #include "nsError.h"
      14             : #include "nsIAsyncVerifyRedirectCallback.h"
      15             : #include "nsIClassInfoImpl.h"
      16             : #include "nsIDocShell.h"
      17             : #include "nsIDocShellTreeItem.h"
      18             : #include "nsIDOMHTMLDocument.h"
      19             : #include "nsIDOMHTMLElement.h"
      20             : #include "nsIDOMNode.h"
      21             : #include "nsIHttpChannel.h"
      22             : #include "nsIInterfaceRequestor.h"
      23             : #include "nsIInterfaceRequestorUtils.h"
      24             : #include "nsIObjectInputStream.h"
      25             : #include "nsIObjectOutputStream.h"
      26             : #include "nsIObserver.h"
      27             : #include "nsIObserverService.h"
      28             : #include "nsIStringStream.h"
      29             : #include "nsIUploadChannel.h"
      30             : #include "nsIScriptError.h"
      31             : #include "nsIWebNavigation.h"
      32             : #include "nsMimeTypes.h"
      33             : #include "nsNetUtil.h"
      34             : #include "nsIContentPolicy.h"
      35             : #include "nsSupportsPrimitives.h"
      36             : #include "nsThreadUtils.h"
      37             : #include "nsString.h"
      38             : #include "nsScriptSecurityManager.h"
      39             : #include "nsStringStream.h"
      40             : #include "mozilla/Logging.h"
      41             : #include "mozilla/dom/CSPReportBinding.h"
      42             : #include "mozilla/dom/CSPDictionariesBinding.h"
      43             : #include "mozilla/net/ReferrerPolicy.h"
      44             : #include "nsINetworkInterceptController.h"
      45             : #include "nsSandboxFlags.h"
      46             : #include "nsIScriptElement.h"
      47             : #include "nsIEventTarget.h"
      48             : #include "mozilla/dom/DocGroup.h"
      49             : #include "nsXULAppAPI.h"
      50             : 
      51             : using namespace mozilla;
      52             : 
      53             : static LogModule*
      54           0 : GetCspContextLog()
      55             : {
      56             :   static LazyLogModule gCspContextPRLog("CSPContext");
      57           0 :   return gCspContextPRLog;
      58             : }
      59             : 
      60             : #define CSPCONTEXTLOG(args) MOZ_LOG(GetCspContextLog(), mozilla::LogLevel::Debug, args)
      61             : #define CSPCONTEXTLOGENABLED() MOZ_LOG_TEST(GetCspContextLog(), mozilla::LogLevel::Debug)
      62             : 
      63             : static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512;
      64             : 
      65             : /**
      66             :  * Creates a key for use in the ShouldLoad cache.
      67             :  * Looks like: <uri>!<nsIContentPolicy::LOAD_TYPE>
      68             :  */
      69             : nsresult
      70           0 : CreateCacheKey_Internal(nsIURI* aContentLocation,
      71             :                         nsContentPolicyType aContentType,
      72             :                         nsACString& outCacheKey)
      73             : {
      74           0 :   if (!aContentLocation) {
      75           0 :     return NS_ERROR_FAILURE;
      76             :   }
      77             : 
      78           0 :   bool isDataScheme = false;
      79           0 :   nsresult rv = aContentLocation->SchemeIs("data", &isDataScheme);
      80           0 :   NS_ENSURE_SUCCESS(rv, rv);
      81             : 
      82           0 :   outCacheKey.Truncate();
      83           0 :   if (aContentType != nsIContentPolicy::TYPE_SCRIPT && isDataScheme) {
      84             :     // For non-script data: URI, use ("data:", aContentType) as the cache key.
      85           0 :     outCacheKey.Append(NS_LITERAL_CSTRING("data:"));
      86           0 :     outCacheKey.AppendInt(aContentType);
      87           0 :     return NS_OK;
      88             :   }
      89             : 
      90           0 :   nsAutoCString spec;
      91           0 :   rv = aContentLocation->GetSpec(spec);
      92           0 :   NS_ENSURE_SUCCESS(rv, rv);
      93             : 
      94             :   // Don't cache for a URI longer than the cutoff size.
      95           0 :   if (spec.Length() <= CSP_CACHE_URI_CUTOFF_SIZE) {
      96           0 :     outCacheKey.Append(spec);
      97           0 :     outCacheKey.Append(NS_LITERAL_CSTRING("!"));
      98           0 :     outCacheKey.AppendInt(aContentType);
      99             :   }
     100             : 
     101           0 :   return NS_OK;
     102             : }
     103             : 
     104             : /* =====  nsIContentSecurityPolicy impl ====== */
     105             : 
     106             : NS_IMETHODIMP
     107           0 : nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
     108             :                          nsIURI*             aContentLocation,
     109             :                          nsIURI*             aRequestOrigin,
     110             :                          nsISupports*        aRequestContext,
     111             :                          const nsACString&   aMimeTypeGuess,
     112             :                          nsISupports*        aExtra,
     113             :                          int16_t*            outDecision)
     114             : {
     115           0 :   if (CSPCONTEXTLOGENABLED()) {
     116           0 :     CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
     117             :                    aContentLocation->GetSpecOrDefault().get()));
     118           0 :     CSPCONTEXTLOG((">>>>                      aContentType: %d", aContentType));
     119             :   }
     120             : 
     121           0 :   bool isPreload = nsContentUtils::IsPreloadType(aContentType);
     122             : 
     123             :   // Since we know whether we are dealing with a preload, we have to convert
     124             :   // the internal policytype ot the external policy type before moving on.
     125             :   // We still need to know if this is a worker so child-src can handle that
     126             :   // case correctly.
     127           0 :   aContentType = nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(aContentType);
     128             : 
     129           0 :   nsresult rv = NS_OK;
     130             : 
     131             :   // This ShouldLoad function is called from nsCSPService::ShouldLoad,
     132             :   // which already checked a number of things, including:
     133             :   // * aContentLocation is not null; we can consume this without further checks
     134             :   // * scheme is not a whitelisted scheme (about: chrome:, etc).
     135             :   // * CSP is enabled
     136             :   // * Content Type is not whitelisted (CSP Reports, TYPE_DOCUMENT, etc).
     137             :   // * Fast Path for Apps
     138             : 
     139           0 :   nsAutoCString cacheKey;
     140           0 :   rv = CreateCacheKey_Internal(aContentLocation, aContentType, cacheKey);
     141           0 :   NS_ENSURE_SUCCESS(rv, rv);
     142             : 
     143           0 :   bool isCached = mShouldLoadCache.Get(cacheKey, outDecision);
     144           0 :   if (isCached && cacheKey.Length() > 0) {
     145             :     // this is cached, use the cached value.
     146           0 :     return NS_OK;
     147             :   }
     148             : 
     149             :   // Default decision, CSP can revise it if there's a policy to enforce
     150           0 :   *outDecision = nsIContentPolicy::ACCEPT;
     151             : 
     152             :   // If the content type doesn't map to a CSP directive, there's nothing for
     153             :   // CSP to do.
     154           0 :   CSPDirective dir = CSP_ContentTypeToDirective(aContentType);
     155           0 :   if (dir == nsIContentSecurityPolicy::NO_DIRECTIVE) {
     156           0 :     return NS_OK;
     157             :   }
     158             : 
     159           0 :   nsAutoString nonce;
     160           0 :   bool parserCreated = false;
     161           0 :   if (!isPreload) {
     162           0 :     if (aContentType == nsIContentPolicy::TYPE_SCRIPT ||
     163             :         aContentType == nsIContentPolicy::TYPE_STYLESHEET) {
     164           0 :       nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
     165           0 :       if (htmlElement) {
     166           0 :         rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
     167           0 :         NS_ENSURE_SUCCESS(rv, rv);
     168             :       }
     169             :     }
     170             : 
     171           0 :     nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
     172           0 :     if (script && script->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER) {
     173           0 :       parserCreated = true;
     174             :     }
     175             :   }
     176             : 
     177             :   // aExtra holds the original URI of the channel if the
     178             :   // channel got redirected (until we fix Bug 1332422).
     179           0 :   nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
     180           0 :   bool wasRedirected = originalURI;
     181             : 
     182           0 :   bool permitted = permitsInternal(dir,
     183             :                                    aContentLocation,
     184             :                                    originalURI,
     185             :                                    nonce,
     186             :                                    wasRedirected,
     187             :                                    isPreload,
     188             :                                    false,     // allow fallback to default-src
     189             :                                    true,      // send violation reports
     190             :                                    true,     // send blocked URI in violation reports
     191           0 :                                    parserCreated);
     192             : 
     193           0 :   *outDecision = permitted ? nsIContentPolicy::ACCEPT
     194           0 :                            : nsIContentPolicy::REJECT_SERVER;
     195             : 
     196             :   // Done looping, cache any relevant result
     197           0 :   if (cacheKey.Length() > 0 && !isPreload) {
     198           0 :     mShouldLoadCache.Put(cacheKey, *outDecision);
     199             :   }
     200             : 
     201           0 :   if (CSPCONTEXTLOGENABLED()) {
     202           0 :     CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
     203             :                    "aContentLocation: %s",
     204             :                    *outDecision > 0 ? "load" : "deny",
     205             :                    aContentLocation->GetSpecOrDefault().get()));
     206             :   }
     207           0 :   return NS_OK;
     208             : }
     209             : 
     210             : bool
     211           0 : nsCSPContext::permitsInternal(CSPDirective aDir,
     212             :                               nsIURI* aContentLocation,
     213             :                               nsIURI* aOriginalURI,
     214             :                               const nsAString& aNonce,
     215             :                               bool aWasRedirected,
     216             :                               bool aIsPreload,
     217             :                               bool aSpecific,
     218             :                               bool aSendViolationReports,
     219             :                               bool aSendContentLocationInViolationReports,
     220             :                               bool aParserCreated)
     221             : {
     222           0 :   bool permits = true;
     223             : 
     224           0 :   nsAutoString violatedDirective;
     225           0 :   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
     226             : 
     227             :     // According to the W3C CSP spec, frame-ancestors checks are ignored for
     228             :     // report-only policies (when "monitoring").
     229           0 :     if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE &&
     230           0 :         mPolicies[p]->getReportOnlyFlag()) {
     231           0 :       continue;
     232             :     }
     233             : 
     234           0 :     if (!mPolicies[p]->permits(aDir,
     235             :                                aContentLocation,
     236             :                                aNonce,
     237             :                                aWasRedirected,
     238             :                                aSpecific,
     239             :                                aParserCreated,
     240             :                                violatedDirective)) {
     241             :       // If the policy is violated and not report-only, reject the load and
     242             :       // report to the console
     243           0 :       if (!mPolicies[p]->getReportOnlyFlag()) {
     244           0 :         CSPCONTEXTLOG(("nsCSPContext::permitsInternal, false"));
     245           0 :         permits = false;
     246             :       }
     247             : 
     248             :       // Do not send a report or notify observers if this is a preload - the
     249             :       // decision may be wrong due to the inability to get the nonce, and will
     250             :       // incorrectly fail the unit tests.
     251           0 :       if (!aIsPreload && aSendViolationReports) {
     252           0 :         this->AsyncReportViolation((aSendContentLocationInViolationReports ?
     253             :                                     aContentLocation : nullptr),
     254             :                                    aOriginalURI,  /* in case of redirect originalURI is not null */
     255             :                                    violatedDirective,
     256             :                                    p,             /* policy index        */
     257           0 :                                    EmptyString(), /* no observer subject */
     258           0 :                                    EmptyString(), /* no source file      */
     259           0 :                                    EmptyString(), /* no script sample    */
     260           0 :                                    0);            /* no line number      */
     261             :       }
     262             :     }
     263             :   }
     264             : 
     265           0 :   return permits;
     266             : }
     267             : 
     268             : 
     269             : 
     270             : /* ===== nsISupports implementation ========== */
     271             : 
     272           3 : NS_IMPL_CLASSINFO(nsCSPContext,
     273             :                   nullptr,
     274             :                   nsIClassInfo::MAIN_THREAD_ONLY,
     275             :                   NS_CSPCONTEXT_CID)
     276             : 
     277           0 : NS_IMPL_ISUPPORTS_CI(nsCSPContext,
     278             :                      nsIContentSecurityPolicy,
     279             :                      nsISerializable)
     280             : 
     281           0 : nsCSPContext::nsCSPContext()
     282             :   : mInnerWindowID(0)
     283             :   , mLoadingContext(nullptr)
     284             :   , mLoadingPrincipal(nullptr)
     285           0 :   , mQueueUpMessages(true)
     286             : {
     287           0 :   CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
     288           0 : }
     289             : 
     290           0 : nsCSPContext::~nsCSPContext()
     291             : {
     292           0 :   CSPCONTEXTLOG(("nsCSPContext::~nsCSPContext"));
     293           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     294           0 :     delete mPolicies[i];
     295             :   }
     296           0 :   mShouldLoadCache.Clear();
     297           0 : }
     298             : 
     299             : NS_IMETHODIMP
     300           0 : nsCSPContext::GetPolicyString(uint32_t aIndex, nsAString& outStr)
     301             : {
     302           0 :   if (aIndex >= mPolicies.Length()) {
     303           0 :     return NS_ERROR_ILLEGAL_VALUE;
     304             :   }
     305           0 :   mPolicies[aIndex]->toString(outStr);
     306           0 :   return NS_OK;
     307             : }
     308             : 
     309             : const nsCSPPolicy*
     310           0 : nsCSPContext::GetPolicy(uint32_t aIndex)
     311             : {
     312           0 :   if (aIndex >= mPolicies.Length()) {
     313           0 :     return nullptr;
     314             :   }
     315           0 :   return mPolicies[aIndex];
     316             : }
     317             : 
     318             : NS_IMETHODIMP
     319           0 : nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
     320             : {
     321           0 :   *outPolicyCount = mPolicies.Length();
     322           0 :   return NS_OK;
     323             : }
     324             : 
     325             : NS_IMETHODIMP
     326           0 : nsCSPContext::GetUpgradeInsecureRequests(bool *outUpgradeRequest)
     327             : {
     328           0 :   *outUpgradeRequest = false;
     329           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     330           0 :     if (mPolicies[i]->hasDirective(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
     331           0 :       *outUpgradeRequest = true;
     332           0 :       return NS_OK;
     333             :     }
     334             :   }
     335           0 :   return NS_OK;
     336             : }
     337             : 
     338             : NS_IMETHODIMP
     339           0 : nsCSPContext::GetBlockAllMixedContent(bool *outBlockAllMixedContent)
     340             : {
     341           0 :   *outBlockAllMixedContent = false;
     342           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     343           0 :      if (!mPolicies[i]->getReportOnlyFlag() &&
     344           0 :         mPolicies[i]->hasDirective(nsIContentSecurityPolicy::BLOCK_ALL_MIXED_CONTENT)) {
     345           0 :       *outBlockAllMixedContent = true;
     346           0 :       return NS_OK;
     347             :     }
     348             :   }
     349           0 :   return NS_OK;
     350             : }
     351             : 
     352             : NS_IMETHODIMP
     353           0 : nsCSPContext::GetEnforcesFrameAncestors(bool *outEnforcesFrameAncestors)
     354             : {
     355           0 :   *outEnforcesFrameAncestors = false;
     356           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     357           0 :     if (!mPolicies[i]->getReportOnlyFlag() &&
     358           0 :         mPolicies[i]->hasDirective(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) {
     359           0 :       *outEnforcesFrameAncestors = true;
     360           0 :       return NS_OK;
     361             :     }
     362             :   }
     363           0 :   return NS_OK;
     364             : }
     365             : 
     366             : NS_IMETHODIMP
     367           0 : nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
     368             : {
     369           0 :   *outIsSet = false;
     370           0 :   *outPolicy = mozilla::net::RP_Unset;
     371           0 :   nsAutoString refpol;
     372           0 :   mozilla::net::ReferrerPolicy previousPolicy = mozilla::net::RP_Unset;
     373           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     374           0 :     mPolicies[i]->getReferrerPolicy(refpol);
     375             :     // only set the referrer policy if not delievered through a CSPRO and
     376             :     // note that and an empty string in refpol means it wasn't set
     377             :     // (that's the default in nsCSPPolicy).
     378           0 :     if (!mPolicies[i]->getReportOnlyFlag() && !refpol.IsEmpty()) {
     379             :       // Referrer Directive in CSP is no more used and going to be replaced by
     380             :       // Referrer-Policy HTTP header. But we still keep using referrer directive,
     381             :       // and would remove it later.
     382             :       // Referrer Directive specs is not fully compliant with new referrer policy
     383             :       // specs. What we are using here:
     384             :       // - If the value of the referrer directive is invalid, the user agent
     385             :       // should set the referrer policy to no-referrer.
     386             :       // - If there are two policies that specify a referrer policy, then they
     387             :       // must agree or the employed policy is no-referrer.
     388           0 :       if (!mozilla::net::IsValidReferrerPolicy(refpol)) {
     389           0 :         *outPolicy = mozilla::net::RP_No_Referrer;
     390           0 :         *outIsSet = true;
     391           0 :         return NS_OK;
     392             :       }
     393             : 
     394           0 :       uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
     395           0 :       if (*outIsSet && previousPolicy != currentPolicy) {
     396           0 :         *outPolicy = mozilla::net::RP_No_Referrer;
     397           0 :         return NS_OK;
     398             :       }
     399             : 
     400           0 :       *outPolicy = currentPolicy;
     401           0 :       *outIsSet = true;
     402             :     }
     403             :   }
     404             : 
     405           0 :   return NS_OK;
     406             : }
     407             : 
     408             : NS_IMETHODIMP
     409           0 : nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
     410             :                            bool aReportOnly,
     411             :                            bool aDeliveredViaMetaTag)
     412             : {
     413           0 :   CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
     414             :                  NS_ConvertUTF16toUTF8(aPolicyString).get()));
     415             : 
     416             :   // Use the mSelfURI from setRequestContext, see bug 991474
     417           0 :   NS_ASSERTION(mSelfURI, "mSelfURI required for AppendPolicy, but not set");
     418           0 :   nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI,
     419             :                                                                 aReportOnly, this,
     420           0 :                                                                 aDeliveredViaMetaTag);
     421           0 :   if (policy) {
     422           0 :     mPolicies.AppendElement(policy);
     423             :     // reset cache since effective policy changes
     424           0 :     mShouldLoadCache.Clear();
     425             :   }
     426           0 :   return NS_OK;
     427             : }
     428             : 
     429             : NS_IMETHODIMP
     430           0 : nsCSPContext::GetAllowsEval(bool* outShouldReportViolation,
     431             :                             bool* outAllowsEval)
     432             : {
     433           0 :   *outShouldReportViolation = false;
     434           0 :   *outAllowsEval = true;
     435             : 
     436           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     437           0 :     if (!mPolicies[i]->allows(nsIContentPolicy::TYPE_SCRIPT,
     438             :                               CSP_UNSAFE_EVAL,
     439           0 :                               EmptyString(),
     440             :                               false)) {
     441             :       // policy is violated: must report the violation and allow the inline
     442             :       // script if the policy is report-only.
     443           0 :       *outShouldReportViolation = true;
     444           0 :       if (!mPolicies[i]->getReportOnlyFlag()) {
     445           0 :         *outAllowsEval = false;
     446             :       }
     447             :     }
     448             :   }
     449           0 :   return NS_OK;
     450             : }
     451             : 
     452             : // Helper function to report inline violations
     453             : void
     454           0 : nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
     455             :                                     const nsAString& aNonce,
     456             :                                     const nsAString& aContent,
     457             :                                     const nsAString& aViolatedDirective,
     458             :                                     uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
     459             :                                     uint32_t aLineNumber)
     460             : {
     461           0 :   nsString observerSubject;
     462             :   // if the nonce is non empty, then we report the nonce error, otherwise
     463             :   // let's report the hash error; no need to report the unsafe-inline error
     464             :   // anymore.
     465           0 :   if (!aNonce.IsEmpty()) {
     466             :     observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
     467           0 :                       ? NS_LITERAL_STRING(SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC)
     468           0 :                       : NS_LITERAL_STRING(STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
     469             :   }
     470             :   else {
     471             :     observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
     472           0 :                       ? NS_LITERAL_STRING(SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC)
     473           0 :                       : NS_LITERAL_STRING(STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
     474             :   }
     475             : 
     476           0 :   nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
     477           0 :   if (selfICString) {
     478           0 :     selfICString->SetData(nsDependentCString("self"));
     479             :   }
     480           0 :   nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
     481             : 
     482             :   // use selfURI as the sourceFile
     483           0 :   nsAutoCString sourceFile;
     484           0 :   if (mSelfURI) {
     485           0 :     mSelfURI->GetSpec(sourceFile);
     486             :   }
     487             : 
     488           0 :   nsAutoString codeSample(aContent);
     489             :   // cap the length of the script sample at 40 chars
     490           0 :   if (codeSample.Length() > 40) {
     491           0 :     codeSample.Truncate(40);
     492           0 :     codeSample.AppendLiteral("...");
     493             :   }
     494           0 :   AsyncReportViolation(selfISupports,                      // aBlockedContentSource
     495             :                        mSelfURI,                           // aOriginalURI
     496             :                        aViolatedDirective,                 // aViolatedDirective
     497             :                        aViolatedPolicyIndex,               // aViolatedPolicyIndex
     498             :                        observerSubject,                    // aObserverSubject
     499           0 :                        NS_ConvertUTF8toUTF16(sourceFile),  // aSourceFile
     500             :                        codeSample,                         // aScriptSample
     501           0 :                        aLineNumber);                       // aLineNum
     502           0 : }
     503             : 
     504             : NS_IMETHODIMP
     505           0 : nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
     506             :                               const nsAString& aNonce,
     507             :                               bool aParserCreated,
     508             :                               const nsAString& aContent,
     509             :                               uint32_t aLineNumber,
     510             :                               bool* outAllowsInline)
     511             : {
     512           0 :   *outAllowsInline = true;
     513             : 
     514           0 :   MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
     515             :              "We should only see external content policy types here.");
     516             : 
     517           0 :   if (aContentType != nsIContentPolicy::TYPE_SCRIPT &&
     518             :       aContentType != nsIContentPolicy::TYPE_STYLESHEET) {
     519           0 :     MOZ_ASSERT(false, "can only allow inline for script or style");
     520             :     return NS_OK;
     521             :   }
     522             : 
     523             :   // always iterate all policies, otherwise we might not send out all reports
     524           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     525             :     bool allowed =
     526           0 :       mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
     527           0 :       mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
     528           0 :       mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
     529             : 
     530           0 :     if (!allowed) {
     531             :       // policy is violoated: deny the load unless policy is report only and
     532             :       // report the violation.
     533           0 :       if (!mPolicies[i]->getReportOnlyFlag()) {
     534           0 :         *outAllowsInline = false;
     535             :       }
     536           0 :       nsAutoString violatedDirective;
     537           0 :       mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
     538             :       reportInlineViolation(aContentType,
     539             :                             aNonce,
     540             :                             aContent,
     541             :                             violatedDirective,
     542             :                             i,
     543           0 :                             aLineNumber);
     544             :     }
     545             :   }
     546           0 :   return NS_OK;
     547             : }
     548             : 
     549             : 
     550             : /**
     551             :  * Reduces some code repetition for the various logging situations in
     552             :  * LogViolationDetails.
     553             :  *
     554             :  * Call-sites for the eval/inline checks recieve two return values: allows
     555             :  * and violates.  Based on those, they must choose whether to call
     556             :  * LogViolationDetails or not.  Policies that are report-only allow the
     557             :  * loads/compilations but violations should still be reported.  Not all
     558             :  * policies in this nsIContentSecurityPolicy instance will be violated,
     559             :  * which is why we must check allows() again here.
     560             :  *
     561             :  * Note: This macro uses some parameters from its caller's context:
     562             :  * p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, selfISupports
     563             :  *
     564             :  * @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
     565             :  *                 such as INLINE_SCRIPT
     566             :  * @param contentPolicyType: a constant from nsIContentPolicy such as TYPE_STYLESHEET
     567             :  * @param nonceOrHash: for NONCE and HASH violations, it's the nonce or content
     568             :  *               string. For other violations, it is an empty string.
     569             :  * @param keyword: the keyword corresponding to violation (UNSAFE_INLINE for most)
     570             :  * @param observerTopic: the observer topic string to send with the CSP
     571             :  *                 observer notifications.
     572             :  *
     573             :  * Please note that inline violations for scripts are reported within
     574             :  * GetAllowsInline() and do not call this macro, hence we can pass 'false'
     575             :  * as the argument _aParserCreated_ to allows().
     576             :  */
     577             : #define CASE_CHECK_AND_REPORT(violationType, contentPolicyType, nonceOrHash,   \
     578             :                               keyword, observerTopic)                          \
     579             :   case nsIContentSecurityPolicy::VIOLATION_TYPE_ ## violationType :            \
     580             :     PR_BEGIN_MACRO                                                             \
     581             :     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
     582             :                               keyword, nonceOrHash, false))                    \
     583             :     {                                                                          \
     584             :       nsAutoString violatedDirective;                                          \
     585             :       mPolicies[p]->getDirectiveStringForContentType(                          \
     586             :                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
     587             :                         violatedDirective);                                    \
     588             :       this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
     589             :                                  NS_LITERAL_STRING(observerTopic),             \
     590             :                                  aSourceFile, aScriptSample, aLineNum);        \
     591             :     }                                                                          \
     592             :     PR_END_MACRO;                                                              \
     593             :     break
     594             : 
     595             : /**
     596             :  * For each policy, log any violation on the Error Console and send a report
     597             :  * if a report-uri is present in the policy
     598             :  *
     599             :  * @param aViolationType
     600             :  *     one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
     601             :  * @param aSourceFile
     602             :  *     name of the source file containing the violation (if available)
     603             :  * @param aContentSample
     604             :  *     sample of the violating content (to aid debugging)
     605             :  * @param aLineNum
     606             :  *     source line number of the violation (if available)
     607             :  * @param aNonce
     608             :  *     (optional) If this is a nonce violation, include the nonce so we can
     609             :  *     recheck to determine which policies were violated and send the
     610             :  *     appropriate reports.
     611             :  * @param aContent
     612             :  *     (optional) If this is a hash violation, include contents of the inline
     613             :  *     resource in the question so we can recheck the hash in order to
     614             :  *     determine which policies were violated and send the appropriate
     615             :  *     reports.
     616             :  */
     617             : NS_IMETHODIMP
     618           0 : nsCSPContext::LogViolationDetails(uint16_t aViolationType,
     619             :                                   const nsAString& aSourceFile,
     620             :                                   const nsAString& aScriptSample,
     621             :                                   int32_t aLineNum,
     622             :                                   const nsAString& aNonce,
     623             :                                   const nsAString& aContent)
     624             : {
     625           0 :   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
     626           0 :     NS_ASSERTION(mPolicies[p], "null pointer in nsTArray<nsCSPPolicy>");
     627             : 
     628           0 :     nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
     629           0 :     if (selfICString) {
     630           0 :       selfICString->SetData(nsDependentCString("self"));
     631             :     }
     632           0 :     nsCOMPtr<nsISupports> selfISupports(do_QueryInterface(selfICString));
     633             : 
     634           0 :     switch (aViolationType) {
     635           0 :       CASE_CHECK_AND_REPORT(EVAL,              SCRIPT,     NS_LITERAL_STRING(""),
     636             :                             CSP_UNSAFE_EVAL,   EVAL_VIOLATION_OBSERVER_TOPIC);
     637           0 :       CASE_CHECK_AND_REPORT(INLINE_STYLE,      STYLESHEET, NS_LITERAL_STRING(""),
     638             :                             CSP_UNSAFE_INLINE, INLINE_STYLE_VIOLATION_OBSERVER_TOPIC);
     639           0 :       CASE_CHECK_AND_REPORT(INLINE_SCRIPT,     SCRIPT,     NS_LITERAL_STRING(""),
     640             :                             CSP_UNSAFE_INLINE, INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC);
     641           0 :       CASE_CHECK_AND_REPORT(NONCE_SCRIPT,      SCRIPT,     aNonce,
     642             :                             CSP_UNSAFE_INLINE, SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC);
     643           0 :       CASE_CHECK_AND_REPORT(NONCE_STYLE,       STYLESHEET, aNonce,
     644             :                             CSP_UNSAFE_INLINE, STYLE_NONCE_VIOLATION_OBSERVER_TOPIC);
     645           0 :       CASE_CHECK_AND_REPORT(HASH_SCRIPT,       SCRIPT,     aContent,
     646             :                             CSP_UNSAFE_INLINE, SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC);
     647           0 :       CASE_CHECK_AND_REPORT(HASH_STYLE,        STYLESHEET, aContent,
     648             :                             CSP_UNSAFE_INLINE, STYLE_HASH_VIOLATION_OBSERVER_TOPIC);
     649           0 :       CASE_CHECK_AND_REPORT(REQUIRE_SRI_FOR_STYLE,   STYLESHEET, NS_LITERAL_STRING(""),
     650             :                             CSP_REQUIRE_SRI_FOR, REQUIRE_SRI_STYLE_VIOLATION_OBSERVER_TOPIC);
     651           0 :       CASE_CHECK_AND_REPORT(REQUIRE_SRI_FOR_SCRIPT,   SCRIPT, NS_LITERAL_STRING(""),
     652             :                             CSP_REQUIRE_SRI_FOR, REQUIRE_SRI_SCRIPT_VIOLATION_OBSERVER_TOPIC);
     653             : 
     654             : 
     655             :       default:
     656           0 :         NS_ASSERTION(false, "LogViolationDetails with invalid type");
     657           0 :         break;
     658             :     }
     659             :   }
     660           0 :   return NS_OK;
     661             : }
     662             : 
     663             : #undef CASE_CHECK_AND_REPORT
     664             : 
     665             : NS_IMETHODIMP
     666           0 : nsCSPContext::SetRequestContext(nsIDOMDocument* aDOMDocument,
     667             :                                 nsIPrincipal* aPrincipal)
     668             : {
     669           0 :   NS_PRECONDITION(aDOMDocument || aPrincipal,
     670             :                   "Can't set context without doc or principal");
     671           0 :   NS_ENSURE_ARG(aDOMDocument || aPrincipal);
     672             : 
     673           0 :   if (aDOMDocument) {
     674           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDocument);
     675           0 :     mLoadingContext = do_GetWeakReference(doc);
     676           0 :     mSelfURI = doc->GetDocumentURI();
     677           0 :     mLoadingPrincipal = doc->NodePrincipal();
     678           0 :     doc->GetReferrer(mReferrer);
     679           0 :     mInnerWindowID = doc->InnerWindowID();
     680             :     // the innerWindowID is not available for CSPs delivered through the
     681             :     // header at the time setReqeustContext is called - let's queue up
     682             :     // console messages until it becomes available, see flushConsoleMessages
     683           0 :     mQueueUpMessages = !mInnerWindowID;
     684           0 :     mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
     685             : 
     686             :     // set the flag on the document for CSP telemetry
     687           0 :     doc->SetHasCSP(true);
     688           0 :     mEventTarget = doc->EventTargetFor(TaskCategory::Other);
     689             :   }
     690             :   else {
     691           0 :     CSPCONTEXTLOG(("No Document in SetRequestContext; can not query loadgroup; sending reports may fail."));
     692           0 :     mLoadingPrincipal = aPrincipal;
     693           0 :     mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
     694             :     // if no document is available, then it also does not make sense to queue console messages
     695             :     // sending messages to the browser conolse instead of the web console in that case.
     696           0 :     mQueueUpMessages = false;
     697             :   }
     698             : 
     699           0 :   NS_ASSERTION(mSelfURI, "mSelfURI not available, can not translate 'self' into actual URI");
     700           0 :   return NS_OK;
     701             : }
     702             : 
     703             : NS_IMETHODIMP
     704           0 : nsCSPContext::EnsureEventTarget(nsIEventTarget* aEventTarget)
     705             : {
     706           0 :   NS_ENSURE_ARG(aEventTarget);
     707             :   // Don't bother if we did have a valid event target (if the csp object is
     708             :   // tied to a document in SetRequestContext)
     709           0 :   if (mEventTarget) {
     710           0 :     return NS_OK;
     711             :   }
     712             : 
     713           0 :   mEventTarget = aEventTarget;
     714           0 :   return NS_OK;
     715             : }
     716             : 
     717           0 : struct ConsoleMsgQueueElem {
     718             :   nsXPIDLString mMsg;
     719             :   nsString      mSourceName;
     720             :   nsString      mSourceLine;
     721             :   uint32_t      mLineNumber;
     722             :   uint32_t      mColumnNumber;
     723             :   uint32_t      mSeverityFlag;
     724             : };
     725             : 
     726             : void
     727           0 : nsCSPContext::flushConsoleMessages()
     728             : {
     729             :   // should flush messages even if doc is not available
     730           0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
     731           0 :   if (doc) {
     732           0 :     mInnerWindowID = doc->InnerWindowID();
     733             :   }
     734           0 :   mQueueUpMessages = false;
     735             : 
     736           0 :   for (uint32_t i = 0; i < mConsoleMsgQueue.Length(); i++) {
     737           0 :     ConsoleMsgQueueElem &elem = mConsoleMsgQueue[i];
     738           0 :     CSP_LogMessage(elem.mMsg, elem.mSourceName, elem.mSourceLine,
     739             :                    elem.mLineNumber, elem.mColumnNumber,
     740           0 :                    elem.mSeverityFlag, "CSP", mInnerWindowID);
     741             :   }
     742           0 :   mConsoleMsgQueue.Clear();
     743           0 : }
     744             : 
     745             : void
     746           0 : nsCSPContext::logToConsole(const char16_t* aName,
     747             :                            const char16_t** aParams,
     748             :                            uint32_t aParamsLength,
     749             :                            const nsAString& aSourceName,
     750             :                            const nsAString& aSourceLine,
     751             :                            uint32_t aLineNumber,
     752             :                            uint32_t aColumnNumber,
     753             :                            uint32_t aSeverityFlag)
     754             : {
     755             :   // let's check if we have to queue up console messages
     756           0 :   if (mQueueUpMessages) {
     757           0 :     nsXPIDLString msg;
     758           0 :     CSP_GetLocalizedStr(aName, aParams, aParamsLength, getter_Copies(msg));
     759           0 :     ConsoleMsgQueueElem &elem = *mConsoleMsgQueue.AppendElement();
     760           0 :     elem.mMsg = msg;
     761           0 :     elem.mSourceName = PromiseFlatString(aSourceName);
     762           0 :     elem.mSourceLine = PromiseFlatString(aSourceLine);
     763           0 :     elem.mLineNumber = aLineNumber;
     764           0 :     elem.mColumnNumber = aColumnNumber;
     765           0 :     elem.mSeverityFlag = aSeverityFlag;
     766           0 :     return;
     767             :   }
     768           0 :   CSP_LogLocalizedStr(aName, aParams, aParamsLength, aSourceName,
     769             :                       aSourceLine, aLineNumber, aColumnNumber,
     770           0 :                       aSeverityFlag, "CSP", mInnerWindowID);
     771             : }
     772             : 
     773             : /**
     774             :  * Strip URI for reporting according to:
     775             :  * http://www.w3.org/TR/CSP/#violation-reports
     776             :  *
     777             :  * @param aURI
     778             :  *        The uri to be stripped for reporting
     779             :  * @param aSelfURI
     780             :  *        The uri of the protected resource
     781             :  *        which is needed to enforce the SOP.
     782             :  * @return ASCII serialization of the uri to be reported.
     783             :  */
     784             : void
     785           0 : StripURIForReporting(nsIURI* aURI,
     786             :                      nsIURI* aSelfURI,
     787             :                      nsACString& outStrippedURI)
     788             : {
     789             :   // 1) If the origin of uri is a globally unique identifier (for example,
     790             :   // aURI has a scheme of data, blob, or filesystem), then return the
     791             :   // ASCII serialization of uri’s scheme.
     792             :   bool isHttpOrFtp =
     793           0 :     (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) ||
     794           0 :     (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) ||
     795           0 :     (NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
     796             : 
     797           0 :   if (!isHttpOrFtp) {
     798             :     // not strictly spec compliant, but what we really care about is
     799             :     // http/https and also ftp. If it's not http/https or ftp, then treat aURI
     800             :     // as if it's a globally unique identifier and just return the scheme.
     801           0 :     aURI->GetScheme(outStrippedURI);
     802           0 :     return;
     803             :   }
     804             : 
     805             :   // 2) If the origin of uri is not the same as the origin of the protected
     806             :   // resource, then return the ASCII serialization of uri’s origin.
     807           0 :   if (!NS_SecurityCompareURIs(aSelfURI, aURI, false)) {
     808             :     // cross origin redirects also fall into this category, see:
     809             :     // http://www.w3.org/TR/CSP/#violation-reports
     810           0 :     aURI->GetPrePath(outStrippedURI);
     811           0 :     return;
     812             :   }
     813             : 
     814             :   // 3) Return uri, with any fragment component removed.
     815           0 :   aURI->GetSpecIgnoringRef(outStrippedURI);
     816             : }
     817             : 
     818             : /**
     819             :  * Sends CSP violation reports to all sources listed under report-uri.
     820             :  *
     821             :  * @param aBlockedContentSource
     822             :  *        Either a CSP Source (like 'self', as string) or nsIURI: the source
     823             :  *        of the violation.
     824             :  * @param aOriginalUri
     825             :  *        The original URI if the blocked content is a redirect, else null
     826             :  * @param aViolatedDirective
     827             :  *        the directive that was violated (string).
     828             :  * @param aSourceFile
     829             :  *        name of the file containing the inline script violation
     830             :  * @param aScriptSample
     831             :  *        a sample of the violating inline script
     832             :  * @param aLineNum
     833             :  *        source line number of the violation (if available)
     834             :  */
     835             : nsresult
     836           0 : nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
     837             :                           nsIURI* aOriginalURI,
     838             :                           nsAString& aViolatedDirective,
     839             :                           uint32_t aViolatedPolicyIndex,
     840             :                           nsAString& aSourceFile,
     841             :                           nsAString& aScriptSample,
     842             :                           uint32_t aLineNum)
     843             : {
     844           0 :   NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
     845             : 
     846             : #ifdef MOZ_B2G
     847             :   // load group information (on process-split necko implementations like b2g).
     848             :   // (fix this in bug 1011086)
     849             :   if (!mCallingChannelLoadGroup) {
     850             :     NS_WARNING("Load group required but not present for report sending; cannot send CSP violation reports");
     851             :     return NS_ERROR_FAILURE;
     852             :   }
     853             : #endif
     854             : 
     855           0 :   dom::CSPReport report;
     856             :   nsresult rv;
     857             : 
     858             :   // blocked-uri
     859           0 :   if (aBlockedContentSource) {
     860           0 :     nsAutoCString reportBlockedURI;
     861           0 :     nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
     862             :     // could be a string or URI
     863           0 :     if (uri) {
     864           0 :       StripURIForReporting(uri, mSelfURI, reportBlockedURI);
     865             :     } else {
     866           0 :       nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
     867           0 :       if (cstr) {
     868           0 :         cstr->GetData(reportBlockedURI);
     869             :       }
     870             :     }
     871           0 :     if (reportBlockedURI.IsEmpty()) {
     872             :       // this can happen for frame-ancestors violation where the violating
     873             :       // ancestor is cross-origin.
     874           0 :       NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
     875             :     }
     876           0 :     report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
     877             :   }
     878             : 
     879             :   // document-uri
     880           0 :   nsAutoCString reportDocumentURI;
     881           0 :   StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
     882           0 :   report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
     883             : 
     884             :   // original-policy
     885           0 :   nsAutoString originalPolicy;
     886           0 :   rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy);
     887           0 :   NS_ENSURE_SUCCESS(rv, rv);
     888           0 :   report.mCsp_report.mOriginal_policy = originalPolicy;
     889             : 
     890             :   // referrer
     891           0 :   if (!mReferrer.IsEmpty()) {
     892           0 :     report.mCsp_report.mReferrer = mReferrer;
     893             :   }
     894             : 
     895             :   // violated-directive
     896           0 :   report.mCsp_report.mViolated_directive = aViolatedDirective;
     897             : 
     898             :   // source-file
     899           0 :   if (!aSourceFile.IsEmpty()) {
     900             :     // if aSourceFile is a URI, we have to make sure to strip fragments
     901           0 :     nsCOMPtr<nsIURI> sourceURI;
     902           0 :     NS_NewURI(getter_AddRefs(sourceURI), aSourceFile);
     903           0 :     if (sourceURI) {
     904           0 :       nsAutoCString spec;
     905           0 :       sourceURI->GetSpecIgnoringRef(spec);
     906           0 :       aSourceFile = NS_ConvertUTF8toUTF16(spec);
     907             :     }
     908           0 :     report.mCsp_report.mSource_file.Construct();
     909           0 :     report.mCsp_report.mSource_file.Value() = aSourceFile;
     910             :   }
     911             : 
     912             :   // script-sample
     913           0 :   if (!aScriptSample.IsEmpty()) {
     914           0 :     report.mCsp_report.mScript_sample.Construct();
     915           0 :     report.mCsp_report.mScript_sample.Value() = aScriptSample;
     916             :   }
     917             : 
     918             :   // line-number
     919           0 :   if (aLineNum != 0) {
     920           0 :     report.mCsp_report.mLine_number.Construct();
     921           0 :     report.mCsp_report.mLine_number.Value() = aLineNum;
     922             :   }
     923             : 
     924           0 :   nsString csp_report;
     925           0 :   if (!report.ToJSON(csp_report)) {
     926           0 :     return NS_ERROR_FAILURE;
     927             :   }
     928             : 
     929             :   // ---------- Assembled, now send it to all the report URIs ----------- //
     930             : 
     931           0 :   nsTArray<nsString> reportURIs;
     932           0 :   mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
     933             : 
     934             : 
     935           0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
     936           0 :   nsCOMPtr<nsIURI> reportURI;
     937           0 :   nsCOMPtr<nsIChannel> reportChannel;
     938             : 
     939           0 :   for (uint32_t r = 0; r < reportURIs.Length(); r++) {
     940           0 :     nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
     941             :     // try to create a new uri from every report-uri string
     942           0 :     rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
     943           0 :     if (NS_FAILED(rv)) {
     944           0 :       const char16_t* params[] = { reportURIs[r].get() };
     945           0 :       CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
     946             :                      reportURICstring.get()));
     947           0 :       logToConsole(u"triedToSendReport", params, ArrayLength(params),
     948           0 :                    aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
     949           0 :       continue; // don't return yet, there may be more URIs
     950             :     }
     951             : 
     952             :     // try to create a new channel for every report-uri
     953           0 :     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
     954           0 :     if (doc) {
     955           0 :       rv = NS_NewChannel(getter_AddRefs(reportChannel),
     956             :                          reportURI,
     957             :                          doc,
     958             :                          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     959             :                          nsIContentPolicy::TYPE_CSP_REPORT,
     960             :                          nullptr, // aLoadGroup
     961             :                          nullptr, // aCallbacks
     962           0 :                          loadFlags);
     963             :     }
     964             :     else {
     965           0 :       rv = NS_NewChannel(getter_AddRefs(reportChannel),
     966             :                          reportURI,
     967             :                          mLoadingPrincipal,
     968             :                          nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     969             :                          nsIContentPolicy::TYPE_CSP_REPORT,
     970             :                          nullptr, // aLoadGroup
     971             :                          nullptr, // aCallbacks
     972           0 :                          loadFlags);
     973             :     }
     974             : 
     975           0 :     if (NS_FAILED(rv)) {
     976           0 :       CSPCONTEXTLOG(("Could not create new channel for report URI %s",
     977             :                      reportURICstring.get()));
     978           0 :       continue; // don't return yet, there may be more URIs
     979             :     }
     980             : 
     981             :     // log a warning to console if scheme is not http or https
     982             :     bool isHttpScheme =
     983           0 :       (NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) ||
     984           0 :       (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
     985             : 
     986           0 :     if (!isHttpScheme) {
     987           0 :       const char16_t* params[] = { reportURIs[r].get() };
     988           0 :       logToConsole(u"reportURInotHttpsOrHttp2", params, ArrayLength(params),
     989           0 :                    aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
     990           0 :       continue;
     991             :     }
     992             : 
     993             :     // make sure this is an anonymous request (no cookies) so in case the
     994             :     // policy URI is injected, it can't be abused for CSRF.
     995             :     nsLoadFlags flags;
     996           0 :     rv = reportChannel->GetLoadFlags(&flags);
     997           0 :     NS_ENSURE_SUCCESS(rv, rv);
     998           0 :     flags |= nsIRequest::LOAD_ANONYMOUS;
     999           0 :     rv = reportChannel->SetLoadFlags(flags);
    1000           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1001             : 
    1002             :     // we need to set an nsIChannelEventSink on the channel object
    1003             :     // so we can tell it to not follow redirects when posting the reports
    1004           0 :     RefPtr<CSPReportRedirectSink> reportSink = new CSPReportRedirectSink();
    1005           0 :     if (doc && doc->GetDocShell()) {
    1006             :       nsCOMPtr<nsINetworkInterceptController> interceptController =
    1007           0 :         do_QueryInterface(doc->GetDocShell());
    1008           0 :       reportSink->SetInterceptController(interceptController);
    1009             :     }
    1010           0 :     reportChannel->SetNotificationCallbacks(reportSink);
    1011             : 
    1012             :     // apply the loadgroup from the channel taken by setRequestContext.  If
    1013             :     // there's no loadgroup, AsyncOpen will fail on process-split necko (since
    1014             :     // the channel cannot query the iTabChild).
    1015           0 :     rv = reportChannel->SetLoadGroup(mCallingChannelLoadGroup);
    1016           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1017             : 
    1018             :     // wire in the string input stream to send the report
    1019           0 :     nsCOMPtr<nsIStringInputStream> sis(do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID));
    1020           0 :     NS_ASSERTION(sis, "nsIStringInputStream is needed but not available to send CSP violation reports");
    1021           0 :     nsAutoCString utf8CSPReport = NS_ConvertUTF16toUTF8(csp_report);
    1022           0 :     rv = sis->SetData(utf8CSPReport.get(), utf8CSPReport.Length());
    1023           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1024             : 
    1025           0 :     nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(reportChannel));
    1026           0 :     if (!uploadChannel) {
    1027             :       // It's possible the URI provided can't be uploaded to, in which case
    1028             :       // we skip this one. We'll already have warned about a non-HTTP URI earlier.
    1029           0 :       continue;
    1030             :     }
    1031             : 
    1032           0 :     rv = uploadChannel->SetUploadStream(sis, NS_LITERAL_CSTRING("application/csp-report"), -1);
    1033           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1034             : 
    1035             :     // if this is an HTTP channel, set the request method to post
    1036           0 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(reportChannel));
    1037           0 :     if (httpChannel) {
    1038           0 :       rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
    1039           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
    1040             :     }
    1041             : 
    1042           0 :     RefPtr<CSPViolationReportListener> listener = new CSPViolationReportListener();
    1043           0 :     rv = reportChannel->AsyncOpen2(listener);
    1044             : 
    1045             :     // AsyncOpen should not fail, but could if there's no load group (like if
    1046             :     // SetRequestContext is not given a channel).  This should fail quietly and
    1047             :     // not return an error since it's really ok if reports don't go out, but
    1048             :     // it's good to log the error locally.
    1049             : 
    1050           0 :     if (NS_FAILED(rv)) {
    1051           0 :       const char16_t* params[] = { reportURIs[r].get() };
    1052           0 :       CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", NS_ConvertUTF16toUTF8(params[0]).get()));
    1053           0 :       logToConsole(u"triedToSendReport", params, ArrayLength(params),
    1054           0 :                    aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
    1055             :     } else {
    1056           0 :       CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
    1057             :     }
    1058             :   }
    1059           0 :   return NS_OK;
    1060             : }
    1061             : 
    1062             : /**
    1063             :  * Dispatched from the main thread to send reports for one CSP violation.
    1064             :  */
    1065           0 : class CSPReportSenderRunnable final : public Runnable
    1066             : {
    1067             :   public:
    1068           0 :     CSPReportSenderRunnable(nsISupports* aBlockedContentSource,
    1069             :                             nsIURI* aOriginalURI,
    1070             :                             uint32_t aViolatedPolicyIndex,
    1071             :                             bool aReportOnlyFlag,
    1072             :                             const nsAString& aViolatedDirective,
    1073             :                             const nsAString& aObserverSubject,
    1074             :                             const nsAString& aSourceFile,
    1075             :                             const nsAString& aScriptSample,
    1076             :                             uint32_t aLineNum,
    1077             :                             nsCSPContext* aCSPContext)
    1078           0 :       : mozilla::Runnable("CSPReportSenderRunnable")
    1079             :       , mBlockedContentSource(aBlockedContentSource)
    1080             :       , mOriginalURI(aOriginalURI)
    1081             :       , mViolatedPolicyIndex(aViolatedPolicyIndex)
    1082             :       , mReportOnlyFlag(aReportOnlyFlag)
    1083             :       , mViolatedDirective(aViolatedDirective)
    1084             :       , mSourceFile(aSourceFile)
    1085             :       , mScriptSample(aScriptSample)
    1086             :       , mLineNum(aLineNum)
    1087           0 :       , mCSPContext(aCSPContext)
    1088             :     {
    1089           0 :       NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
    1090             :       // the observer subject is an nsISupports: either an nsISupportsCString
    1091             :       // from the arg passed in directly, or if that's empty, it's the blocked
    1092             :       // source.
    1093           0 :       if (aObserverSubject.IsEmpty()) {
    1094           0 :         mObserverSubject = aBlockedContentSource;
    1095             :       } else {
    1096             :         nsCOMPtr<nsISupportsCString> supportscstr =
    1097           0 :           do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
    1098           0 :         NS_ASSERTION(supportscstr, "Couldn't allocate nsISupportsCString");
    1099           0 :         supportscstr->SetData(NS_ConvertUTF16toUTF8(aObserverSubject));
    1100           0 :         mObserverSubject = do_QueryInterface(supportscstr);
    1101             :       }
    1102           0 :     }
    1103             : 
    1104           0 :     NS_IMETHOD Run() override
    1105             :     {
    1106           0 :       MOZ_ASSERT(NS_IsMainThread());
    1107             : 
    1108             :       // 1) notify observers
    1109           0 :       nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
    1110           0 :       NS_ASSERTION(observerService, "needs observer service");
    1111           0 :       nsresult rv = observerService->NotifyObservers(mObserverSubject,
    1112             :                                                      CSP_VIOLATION_TOPIC,
    1113           0 :                                                      mViolatedDirective.get());
    1114           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1115             : 
    1116             :       // 2) send reports for the policy that was violated
    1117           0 :       mCSPContext->SendReports(mBlockedContentSource, mOriginalURI,
    1118             :                                mViolatedDirective, mViolatedPolicyIndex,
    1119           0 :                                mSourceFile, mScriptSample, mLineNum);
    1120             : 
    1121             :       // 3) log to console (one per policy violation)
    1122             :       // mBlockedContentSource could be a URI or a string.
    1123           0 :       nsCOMPtr<nsIURI> blockedURI = do_QueryInterface(mBlockedContentSource);
    1124             :       // if mBlockedContentSource is not a URI, it could be a string
    1125           0 :       nsCOMPtr<nsISupportsCString> blockedString = do_QueryInterface(mBlockedContentSource);
    1126             : 
    1127           0 :       nsCString blockedDataStr;
    1128             : 
    1129           0 :       if (blockedURI) {
    1130           0 :         blockedURI->GetSpec(blockedDataStr);
    1131           0 :         bool isData = false;
    1132           0 :         rv = blockedURI->SchemeIs("data", &isData);
    1133           0 :         if (NS_SUCCEEDED(rv) && isData) {
    1134           0 :           blockedDataStr.Truncate(40);
    1135           0 :           blockedDataStr.AppendASCII("...");
    1136             :         }
    1137           0 :       } else if (blockedString) {
    1138           0 :         blockedString->GetData(blockedDataStr);
    1139             :       }
    1140             : 
    1141           0 :       if (blockedDataStr.Length() > 0) {
    1142           0 :         nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
    1143           0 :         const char16_t* params[] = { mViolatedDirective.get(),
    1144           0 :                                      blockedDataChar16.get() };
    1145           0 :         mCSPContext->logToConsole(mReportOnlyFlag ? u"CSPROViolationWithURI" :
    1146             :                                                     u"CSPViolationWithURI",
    1147           0 :                                   params, ArrayLength(params), mSourceFile, mScriptSample,
    1148           0 :                                   mLineNum, 0, nsIScriptError::errorFlag);
    1149             :       }
    1150           0 :       return NS_OK;
    1151             :     }
    1152             : 
    1153             :   private:
    1154             :     nsCOMPtr<nsISupports>   mBlockedContentSource;
    1155             :     nsCOMPtr<nsIURI>        mOriginalURI;
    1156             :     uint32_t                mViolatedPolicyIndex;
    1157             :     bool                    mReportOnlyFlag;
    1158             :     nsString                mViolatedDirective;
    1159             :     nsCOMPtr<nsISupports>   mObserverSubject;
    1160             :     nsString                mSourceFile;
    1161             :     nsString                mScriptSample;
    1162             :     uint32_t                mLineNum;
    1163             :     RefPtr<nsCSPContext>    mCSPContext;
    1164             : };
    1165             : 
    1166             : /**
    1167             :  * Asynchronously notifies any nsIObservers listening to the CSP violation
    1168             :  * topic that a violation occurred.  Also triggers report sending and console
    1169             :  * logging.  All asynchronous on the main thread.
    1170             :  *
    1171             :  * @param aBlockedContentSource
    1172             :  *        Either a CSP Source (like 'self', as string) or nsIURI: the source
    1173             :  *        of the violation.
    1174             :  * @param aOriginalUri
    1175             :  *        The original URI if the blocked content is a redirect, else null
    1176             :  * @param aViolatedDirective
    1177             :  *        the directive that was violated (string).
    1178             :  * @param aViolatedPolicyIndex
    1179             :  *        the index of the policy that was violated (so we know where to send
    1180             :  *        the reports).
    1181             :  * @param aObserverSubject
    1182             :  *        optional, subject sent to the nsIObservers listening to the CSP
    1183             :  *        violation topic.
    1184             :  * @param aSourceFile
    1185             :  *        name of the file containing the inline script violation
    1186             :  * @param aScriptSample
    1187             :  *        a sample of the violating inline script
    1188             :  * @param aLineNum
    1189             :  *        source line number of the violation (if available)
    1190             :  */
    1191             : nsresult
    1192           0 : nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
    1193             :                                    nsIURI* aOriginalURI,
    1194             :                                    const nsAString& aViolatedDirective,
    1195             :                                    uint32_t aViolatedPolicyIndex,
    1196             :                                    const nsAString& aObserverSubject,
    1197             :                                    const nsAString& aSourceFile,
    1198             :                                    const nsAString& aScriptSample,
    1199             :                                    uint32_t aLineNum)
    1200             : {
    1201           0 :   NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
    1202             : 
    1203             :   nsCOMPtr<nsIRunnable> task =
    1204             :     new CSPReportSenderRunnable(aBlockedContentSource,
    1205             :                                 aOriginalURI,
    1206             :                                 aViolatedPolicyIndex,
    1207           0 :                                 mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
    1208             :                                 aViolatedDirective,
    1209             :                                 aObserverSubject,
    1210             :                                 aSourceFile,
    1211             :                                 aScriptSample,
    1212             :                                 aLineNum,
    1213           0 :                                 this);
    1214             : 
    1215           0 :   if (XRE_IsContentProcess()) {
    1216           0 :     if (mEventTarget) {
    1217           0 :       if (nsCOMPtr<nsINamed> named = do_QueryInterface(task)) {
    1218           0 :         named->SetName("CSPReportSenderRunnable");
    1219             :       }
    1220           0 :       mEventTarget->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
    1221           0 :       return NS_OK;
    1222             :     }
    1223             :   }
    1224             : 
    1225           0 :   NS_DispatchToMainThread(task.forget());
    1226           0 :   return NS_OK;
    1227             : }
    1228             : 
    1229             : NS_IMETHODIMP
    1230           0 : nsCSPContext::RequireSRIForType(nsContentPolicyType aContentType, bool* outRequiresSRIForType)
    1231             : {
    1232           0 :   *outRequiresSRIForType = false;
    1233           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
    1234           0 :     if (mPolicies[i]->hasDirective(REQUIRE_SRI_FOR)) {
    1235           0 :       if (mPolicies[i]->requireSRIForType(aContentType)) {
    1236           0 :         *outRequiresSRIForType = true;
    1237           0 :         return NS_OK;
    1238             :       }
    1239             :     }
    1240             :   }
    1241           0 :   return NS_OK;
    1242             : }
    1243             : 
    1244             : /**
    1245             :  * Based on the given docshell, determines if this CSP context allows the
    1246             :  * ancestry.
    1247             :  *
    1248             :  * In order to determine the URI of the parent document (one causing the load
    1249             :  * of this protected document), this function obtains the docShellTreeItem,
    1250             :  * then walks up the hierarchy until it finds a privileged (chrome) tree item.
    1251             :  * Getting the a tree item's URI looks like this in pseudocode:
    1252             :  *
    1253             :  * nsIDocShellTreeItem->GetDocument()->GetDocumentURI();
    1254             :  *
    1255             :  * aDocShell is the docShell for the protected document.
    1256             :  */
    1257             : NS_IMETHODIMP
    1258           0 : nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
    1259             : {
    1260             :   nsresult rv;
    1261             : 
    1262             :   // Can't check ancestry without a docShell.
    1263           0 :   if (aDocShell == nullptr) {
    1264           0 :     return NS_ERROR_FAILURE;
    1265             :   }
    1266             : 
    1267           0 :   *outPermitsAncestry = true;
    1268             : 
    1269             :   // extract the ancestry as an array
    1270           0 :   nsCOMArray<nsIURI> ancestorsArray;
    1271             : 
    1272           0 :   nsCOMPtr<nsIInterfaceRequestor> ir(do_QueryInterface(aDocShell));
    1273           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_GetInterface(ir));
    1274           0 :   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
    1275           0 :   nsCOMPtr<nsIURI> currentURI;
    1276           0 :   nsCOMPtr<nsIURI> uriClone;
    1277             : 
    1278             :   // iterate through each docShell parent item
    1279           0 :   while (NS_SUCCEEDED(treeItem->GetParent(getter_AddRefs(parentTreeItem))) &&
    1280           0 :          parentTreeItem != nullptr) {
    1281             :     // stop when reaching chrome
    1282           0 :     if (parentTreeItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
    1283           0 :       break;
    1284             :     }
    1285             : 
    1286           0 :     nsIDocument* doc = parentTreeItem->GetDocument();
    1287           0 :     NS_ASSERTION(doc, "Could not get nsIDocument from nsIDocShellTreeItem in nsCSPContext::PermitsAncestry");
    1288           0 :     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    1289             : 
    1290           0 :     currentURI = doc->GetDocumentURI();
    1291             : 
    1292           0 :     if (currentURI) {
    1293             :       // delete the userpass from the URI.
    1294           0 :       rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
    1295           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1296             : 
    1297             :       // We don't care if this succeeds, just want to delete a userpass if
    1298             :       // there was one.
    1299           0 :       uriClone->SetUserPass(EmptyCString());
    1300             : 
    1301           0 :       if (CSPCONTEXTLOGENABLED()) {
    1302           0 :         CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s",
    1303             :                        uriClone->GetSpecOrDefault().get()));
    1304             :       }
    1305           0 :       ancestorsArray.AppendElement(uriClone);
    1306             :     }
    1307             : 
    1308             :     // next ancestor
    1309           0 :     treeItem = parentTreeItem;
    1310             :   }
    1311             : 
    1312           0 :   nsAutoString violatedDirective;
    1313             : 
    1314             :   // Now that we've got the ancestry chain in ancestorsArray, time to check
    1315             :   // them against any CSP.
    1316             :   // NOTE:  the ancestors are not allowed to be sent cross origin; this is a
    1317             :   // restriction not placed on subresource loads.
    1318             : 
    1319           0 :   for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
    1320           0 :     if (CSPCONTEXTLOGENABLED()) {
    1321           0 :       CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s",
    1322             :                      ancestorsArray[a]->GetSpecOrDefault().get()));
    1323             :     }
    1324             :     // omit the ancestor URI in violation reports if cross-origin as per spec
    1325             :     // (it is a violation of the same-origin policy).
    1326           0 :     bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
    1327             : 
    1328             : 
    1329           0 :     bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
    1330             :                                    ancestorsArray[a],
    1331             :                                    nullptr, // no redirect here.
    1332           0 :                                    EmptyString(), // no nonce
    1333             :                                    false,   // no redirect here.
    1334             :                                    false,   // not a preload.
    1335             :                                    true,    // specific, do not use default-src
    1336             :                                    true,    // send violation reports
    1337             :                                    okToSendAncestor,
    1338           0 :                                    false);  // not parser created
    1339           0 :     if (!permits) {
    1340           0 :       *outPermitsAncestry = false;
    1341             :     }
    1342             :   }
    1343           0 :   return NS_OK;
    1344             : }
    1345             : 
    1346             : NS_IMETHODIMP
    1347           0 : nsCSPContext::Permits(nsIURI* aURI,
    1348             :                       CSPDirective aDir,
    1349             :                       bool aSpecific,
    1350             :                       bool* outPermits)
    1351             : {
    1352             :   // Can't perform check without aURI
    1353           0 :   if (aURI == nullptr) {
    1354           0 :     return NS_ERROR_FAILURE;
    1355             :   }
    1356             : 
    1357           0 :   *outPermits = permitsInternal(aDir,
    1358             :                                 aURI,
    1359             :                                 nullptr,  // no original (pre-redirect) URI
    1360           0 :                                 EmptyString(),  // no nonce
    1361             :                                 false,    // not redirected.
    1362             :                                 false,    // not a preload.
    1363             :                                 aSpecific,
    1364             :                                 true,     // send violation reports
    1365             :                                 true,     // send blocked URI in violation reports
    1366             :                                 false);   // not parser created
    1367             : 
    1368           0 :   if (CSPCONTEXTLOGENABLED()) {
    1369           0 :       CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
    1370             :                      aURI->GetSpecOrDefault().get(), aDir,
    1371             :                      *outPermits ? "allow" : "deny"));
    1372             :   }
    1373             : 
    1374           0 :   return NS_OK;
    1375             : }
    1376             : 
    1377             : NS_IMETHODIMP
    1378           0 : nsCSPContext::ToJSON(nsAString& outCSPinJSON)
    1379             : {
    1380           0 :   outCSPinJSON.Truncate();
    1381           0 :   dom::CSPPolicies jsonPolicies;
    1382           0 :   jsonPolicies.mCsp_policies.Construct();
    1383             : 
    1384           0 :   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
    1385           0 :     dom::CSP jsonCSP;
    1386           0 :     mPolicies[p]->toDomCSPStruct(jsonCSP);
    1387           0 :     jsonPolicies.mCsp_policies.Value().AppendElement(jsonCSP, fallible);
    1388             :   }
    1389             : 
    1390             :   // convert the gathered information to JSON
    1391           0 :   if (!jsonPolicies.ToJSON(outCSPinJSON)) {
    1392           0 :     return NS_ERROR_FAILURE;
    1393             :   }
    1394           0 :   return NS_OK;
    1395             : }
    1396             : 
    1397             : NS_IMETHODIMP
    1398           0 : nsCSPContext::GetCSPSandboxFlags(uint32_t* aOutSandboxFlags)
    1399             : {
    1400           0 :   if (!aOutSandboxFlags) {
    1401           0 :     return NS_ERROR_FAILURE;
    1402             :   }
    1403           0 :   *aOutSandboxFlags = SANDBOXED_NONE;
    1404             : 
    1405           0 :   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
    1406           0 :     uint32_t flags = mPolicies[i]->getSandboxFlags();
    1407             : 
    1408             :     // current policy doesn't have sandbox flag, check next policy
    1409           0 :     if (!flags) {
    1410           0 :       continue;
    1411             :     }
    1412             : 
    1413             :     // current policy has sandbox flags, if the policy is in enforcement-mode
    1414             :     // (i.e. not report-only) set these flags and check for policies with more
    1415             :     // restrictions
    1416           0 :     if (!mPolicies[i]->getReportOnlyFlag()) {
    1417           0 :       *aOutSandboxFlags |= flags;
    1418             :     } else {
    1419             :       // sandbox directive is ignored in report-only mode, warn about it and
    1420             :       // continue the loop checking for an enforcement policy.
    1421           0 :       nsAutoString policy;
    1422           0 :       mPolicies[i]->toString(policy);
    1423             : 
    1424           0 :       CSPCONTEXTLOG(("nsCSPContext::GetCSPSandboxFlags, report only policy, ignoring sandbox in: %s",
    1425             :                      NS_ConvertUTF16toUTF8(policy).get()));
    1426             : 
    1427           0 :       const char16_t* params[] = { policy.get() };
    1428           0 :       logToConsole(u"ignoringReportOnlyDirective", params, ArrayLength(params),
    1429           0 :                    EmptyString(), EmptyString(), 0, 0, nsIScriptError::warningFlag);
    1430             :     }
    1431             :   }
    1432             : 
    1433           0 :   return NS_OK;
    1434             : }
    1435             : 
    1436             : /* ========== CSPViolationReportListener implementation ========== */
    1437             : 
    1438           0 : NS_IMPL_ISUPPORTS(CSPViolationReportListener, nsIStreamListener, nsIRequestObserver, nsISupports);
    1439             : 
    1440           0 : CSPViolationReportListener::CSPViolationReportListener()
    1441             : {
    1442           0 : }
    1443             : 
    1444           0 : CSPViolationReportListener::~CSPViolationReportListener()
    1445             : {
    1446           0 : }
    1447             : 
    1448             : nsresult
    1449           0 : AppendSegmentToString(nsIInputStream* aInputStream,
    1450             :                       void* aClosure,
    1451             :                       const char* aRawSegment,
    1452             :                       uint32_t aToOffset,
    1453             :                       uint32_t aCount,
    1454             :                       uint32_t* outWrittenCount)
    1455             : {
    1456           0 :   nsCString* decodedData = static_cast<nsCString*>(aClosure);
    1457           0 :   decodedData->Append(aRawSegment, aCount);
    1458           0 :   *outWrittenCount = aCount;
    1459           0 :   return NS_OK;
    1460             : }
    1461             : 
    1462             : NS_IMETHODIMP
    1463           0 : CSPViolationReportListener::OnDataAvailable(nsIRequest* aRequest,
    1464             :                                             nsISupports* aContext,
    1465             :                                             nsIInputStream* aInputStream,
    1466             :                                             uint64_t aOffset,
    1467             :                                             uint32_t aCount)
    1468             : {
    1469             :   uint32_t read;
    1470           0 :   nsCString decodedData;
    1471             :   return aInputStream->ReadSegments(AppendSegmentToString,
    1472             :                                     &decodedData,
    1473             :                                     aCount,
    1474           0 :                                     &read);
    1475             : }
    1476             : 
    1477             : NS_IMETHODIMP
    1478           0 : CSPViolationReportListener::OnStopRequest(nsIRequest* aRequest,
    1479             :                                           nsISupports* aContext,
    1480             :                                           nsresult aStatus)
    1481             : {
    1482           0 :   return NS_OK;
    1483             : }
    1484             : 
    1485             : NS_IMETHODIMP
    1486           0 : CSPViolationReportListener::OnStartRequest(nsIRequest* aRequest,
    1487             :                                            nsISupports* aContext)
    1488             : {
    1489           0 :   return NS_OK;
    1490             : }
    1491             : 
    1492             : /* ========== CSPReportRedirectSink implementation ========== */
    1493             : 
    1494           0 : NS_IMPL_ISUPPORTS(CSPReportRedirectSink, nsIChannelEventSink, nsIInterfaceRequestor);
    1495             : 
    1496           0 : CSPReportRedirectSink::CSPReportRedirectSink()
    1497             : {
    1498           0 : }
    1499             : 
    1500           0 : CSPReportRedirectSink::~CSPReportRedirectSink()
    1501             : {
    1502           0 : }
    1503             : 
    1504             : NS_IMETHODIMP
    1505           0 : CSPReportRedirectSink::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
    1506             :                                               nsIChannel* aNewChannel,
    1507             :                                               uint32_t aRedirFlags,
    1508             :                                               nsIAsyncVerifyRedirectCallback* aCallback)
    1509             : {
    1510             :   // cancel the old channel so XHR failure callback happens
    1511           0 :   nsresult rv = aOldChannel->Cancel(NS_ERROR_ABORT);
    1512           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1513             : 
    1514             :   // notify an observer that we have blocked the report POST due to a redirect,
    1515             :   // used in testing, do this async since we're in an async call now to begin with
    1516           0 :   nsCOMPtr<nsIURI> uri;
    1517           0 :   rv = aOldChannel->GetURI(getter_AddRefs(uri));
    1518           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1519             : 
    1520           0 :   nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
    1521           0 :   NS_ASSERTION(observerService, "Observer service required to log CSP violations");
    1522           0 :   observerService->NotifyObservers(uri,
    1523             :                                    CSP_VIOLATION_TOPIC,
    1524           0 :                                    u"denied redirect while sending violation report");
    1525             : 
    1526           0 :   return NS_BINDING_REDIRECTED;
    1527             : }
    1528             : 
    1529             : NS_IMETHODIMP
    1530           0 : CSPReportRedirectSink::GetInterface(const nsIID& aIID, void** aResult)
    1531             : {
    1532           0 :   if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
    1533           0 :       mInterceptController) {
    1534           0 :     nsCOMPtr<nsINetworkInterceptController> copy(mInterceptController);
    1535           0 :     *aResult = copy.forget().take();
    1536             : 
    1537           0 :     return NS_OK;
    1538             :   }
    1539             : 
    1540           0 :   return QueryInterface(aIID, aResult);
    1541             : }
    1542             : 
    1543             : void
    1544           0 : CSPReportRedirectSink::SetInterceptController(nsINetworkInterceptController* aInterceptController)
    1545             : {
    1546           0 :   mInterceptController = aInterceptController;
    1547           0 : }
    1548             : 
    1549             : /* ===== nsISerializable implementation ====== */
    1550             : 
    1551             : NS_IMETHODIMP
    1552           0 : nsCSPContext::Read(nsIObjectInputStream* aStream)
    1553             : {
    1554             :   nsresult rv;
    1555           0 :   nsCOMPtr<nsISupports> supports;
    1556             : 
    1557           0 :   rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
    1558           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1559             : 
    1560           0 :   mSelfURI = do_QueryInterface(supports);
    1561           0 :   NS_ASSERTION(mSelfURI, "need a self URI to de-serialize");
    1562             : 
    1563             :   uint32_t numPolicies;
    1564           0 :   rv = aStream->Read32(&numPolicies);
    1565           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1566             : 
    1567           0 :   nsAutoString policyString;
    1568             : 
    1569           0 :   while (numPolicies > 0) {
    1570           0 :     numPolicies--;
    1571             : 
    1572           0 :     rv = aStream->ReadString(policyString);
    1573           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1574             : 
    1575           0 :     bool reportOnly = false;
    1576           0 :     rv = aStream->ReadBoolean(&reportOnly);
    1577           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1578             : 
    1579             :     // @param deliveredViaMetaTag:
    1580             :     // when parsing the CSP policy string initially we already remove directives
    1581             :     // that should not be processed when delivered via the meta tag. Such directives
    1582             :     // will not be present at this point anymore.
    1583           0 :     nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(policyString,
    1584             :                                                                   mSelfURI,
    1585             :                                                                   reportOnly,
    1586             :                                                                   this,
    1587           0 :                                                                   false);
    1588           0 :     if (policy) {
    1589           0 :       mPolicies.AppendElement(policy);
    1590             :     }
    1591             :   }
    1592             : 
    1593           0 :   return NS_OK;
    1594             : }
    1595             : 
    1596             : NS_IMETHODIMP
    1597           0 : nsCSPContext::Write(nsIObjectOutputStream* aStream)
    1598             : {
    1599             :   nsresult rv = NS_WriteOptionalCompoundObject(aStream,
    1600             :                                                mSelfURI,
    1601             :                                                NS_GET_IID(nsIURI),
    1602           0 :                                                true);
    1603           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1604             : 
    1605             :   // Serialize all the policies.
    1606           0 :   aStream->Write32(mPolicies.Length());
    1607             : 
    1608           0 :   nsAutoString polStr;
    1609           0 :   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
    1610           0 :     polStr.Truncate();
    1611           0 :     mPolicies[p]->toString(polStr);
    1612           0 :     aStream->WriteWStringZ(polStr.get());
    1613           0 :     aStream->WriteBoolean(mPolicies[p]->getReportOnlyFlag());
    1614             :   }
    1615           0 :   return NS_OK;
    1616             : }

Generated by: LCOV version 1.13