Commit 256e2495 authored by Christoph Kerschbaumer's avatar Christoph Kerschbaumer
Browse files

Bug 1381761 - Treating 'data:' documents as unique, opaque origins should...

Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP. r=smaug,dveditz
parent 7ec4d944
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ LOCAL_INCLUDES += [
    '/docshell/base',
    '/dom/base',
    '/js/xpconnect/src',
    '/netwerk/base',
]

if CONFIG['ENABLE_TESTS']:
+61 −35
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "nsIWindowWatcher.h"
#include "nsIConsoleService.h"
#include "nsIObserverService.h"
#include "nsIOService.h"
#include "nsIContent.h"
#include "nsDOMJSUtils.h"
#include "nsAboutProtocolUtils.h"
@@ -265,6 +266,61 @@ nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(nsIChannel* aCh
                                   /*aIgnoreSandboxing*/ true);
}

static void
InheritAndSetCSPOnPrincipalIfNeeded(nsIChannel* aChannel, nsIPrincipal* aPrincipal)
{
  // loading a data: URI into an iframe, or loading frame[srcdoc] need
  // to inherit the CSP (see Bug 1073952, 1381761).
  MOZ_ASSERT(aChannel && aPrincipal, "need a valid channel and principal");
  if (!aChannel) {
    return;
  }

  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
  if (!loadInfo ||
      loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_SUBDOCUMENT) {
    return;
  }

  nsCOMPtr<nsIURI> uri;
  nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
  NS_ENSURE_SUCCESS_VOID(rv);
  nsAutoCString URISpec;
  rv = uri->GetSpec(URISpec);
  NS_ENSURE_SUCCESS_VOID(rv);

  bool isSrcDoc = URISpec.EqualsLiteral("about:srcdoc");
  bool isData = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData);

  if (!isSrcDoc && !isData) {
    return;
  }

  nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
  if (!principalToInherit) {
    principalToInherit = loadInfo->TriggeringPrincipal();
  }
  nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
  principalToInherit->GetCsp(getter_AddRefs(originalCSP));
  if (!originalCSP) {
    return;
  }

  // if the principalToInherit had a CSP, add it to the before
  // created NullPrincipal (unless it already has one)
  MOZ_ASSERT(aPrincipal->GetIsNullPrincipal(),
             "inheriting the CSP only valid for NullPrincipal");
  nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
  aPrincipal->GetCsp(getter_AddRefs(nullPrincipalCSP));
  if (nullPrincipalCSP) {
    MOZ_ASSERT(nullPrincipalCSP == originalCSP,
               "There should be no other CSP here.");
    // CSPs are equal, no need to set it again.
    return;
  }
  aPrincipal->SetCsp(originalCSP);
}

nsresult
nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
                                                   nsIPrincipal** aPrincipal,
@@ -295,40 +351,7 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
        if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
          MOZ_ALWAYS_TRUE(NS_SUCCEEDED(loadInfo->GetSandboxedLoadingPrincipal(aPrincipal)));
          MOZ_ASSERT(*aPrincipal);
            // if the new NullPrincipal (above) loads an iframe[srcdoc], we
            // need to inherit an existing CSP to avoid bypasses (bug 1073952).
            // We continue inheriting for nested frames with e.g., data: URLs.
            if (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT) {
              nsCOMPtr<nsIURI> uri;
              aChannel->GetURI(getter_AddRefs(uri));
              nsAutoCString URISpec;
              uri->GetSpec(URISpec);
              bool isData = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData);
              if (URISpec.EqualsLiteral("about:srcdoc") || isData) {
                nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
                if (!principalToInherit) {
                  principalToInherit = loadInfo->TriggeringPrincipal();
                }
                nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
                principalToInherit->GetCsp(getter_AddRefs(originalCSP));
                if (originalCSP) {
                  // if the principalToInherit had a CSP,
                  // add it to the newly created NullPrincipal
                  // (unless it already has one)
                  nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
                  (*aPrincipal)->GetCsp(getter_AddRefs(nullPrincipalCSP));
                  if (nullPrincipalCSP) {
                    MOZ_ASSERT(nullPrincipalCSP == originalCSP,
                              "There should be no other CSP here.");
                    // CSPs are equal, no need to set it again.
                    return NS_OK;
                  } else {
                    nsresult rv = (*aPrincipal)->SetCsp(originalCSP);
                    NS_ENSURE_SUCCESS(rv, rv);
                  }
                }
              }
            }
          InheritAndSetCSPOnPrincipalIfNeeded(aChannel, *aPrincipal);
          return NS_OK;
        }

@@ -376,7 +399,10 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
      }
    }
  }
  return GetChannelURIPrincipal(aChannel, aPrincipal);
  nsresult rv = GetChannelURIPrincipal(aChannel, aPrincipal);
  NS_ENSURE_SUCCESS(rv, rv);
  InheritAndSetCSPOnPrincipalIfNeeded(aChannel, *aPrincipal);
  return NS_OK;
}

/* The principal of the URI that this channel is loading. This is never