Bug 1260931 - Part 3: Propagate firstPartyDomain. r=smaug
☠☠ backed out by 39cff1d988fd ☠ ☠
authorYoshi Huang <allstars.chh@mozilla.com>
Fri, 26 Aug 2016 12:41:37 +0800
changeset 312385 10da0eca7bbb18830dedacddf5460fe3aa780204
parent 312384 2de0e171f15b38ab134d153d776a207d19afbcc4
child 312386 51b6694efc8fda1d2e0674aeadc78564a3509c4d
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1260931
milestone51.0a1
Bug 1260931 - Part 3: Propagate firstPartyDomain. r=smaug
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/nsScriptSecurityManager.cpp
docshell/base/nsDocShell.cpp
dom/base/nsFrameLoader.cpp
netwerk/ipc/NeckoParent.cpp
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/BasePrincipal.h"
 
 #include "nsDocShell.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 #include "nsIAddonPolicyService.h"
 #include "nsIContentSecurityPolicy.h"
+#include "nsIEffectiveTLDService.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 
 #include "nsPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsIURIWithPrincipal.h"
 #include "nsNullPrincipal.h"
 #include "nsScriptSecurityManager.h"
@@ -95,30 +96,49 @@ NeckoOriginAttributes::InheritFromDocToN
   // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit
   // mSignedPkg accordingly by mSignedPkgInBrowser
 
   mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
   mFirstPartyDomain = aAttrs.mFirstPartyDomain;
 }
 
 void
-NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs)
+NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs,
+                                                  const bool aIsTopLevelDocument,
+                                                  nsIURI* aURI)
 {
   mAppId = aAttrs.mAppId;
   mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
 
   // TODO:
   // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit
   // mSignedPkg accordingly by mSignedPkgInBrowser
 
   mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
-  mFirstPartyDomain = aAttrs.mFirstPartyDomain;
+
+  bool isFirstPartyEnabled = IsFirstPartyEnabled();
+
+  // When the pref is on, we also compute the firstPartyDomain attribute
+  // if this is for top-level document.
+  if (isFirstPartyEnabled && aIsTopLevelDocument) {
+    nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
+    MOZ_ASSERT(tldService);
+    if (!tldService) {
+      return;
+    }
+
+    nsAutoCString baseDomain;
+    tldService->GetBaseDomain(aURI, 0, baseDomain);
+    mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
+  } else {
+    mFirstPartyDomain = aAttrs.mFirstPartyDomain;
+  }
 }
 
 void
 OriginAttributes::CreateSuffix(nsACString& aStr) const
 {
   UniquePtr<URLParams> params(new URLParams());
   nsAutoString value;
 
@@ -321,16 +341,30 @@ OriginAttributes::SetFromGenericAttribut
   mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
   mAddonId = aAttrs.mAddonId;
   mUserContextId = aAttrs.mUserContextId;
   mSignedPkg = aAttrs.mSignedPkg;
   mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
   mFirstPartyDomain = aAttrs.mFirstPartyDomain;
 }
 
+bool
+OriginAttributes::IsFirstPartyEnabled()
+{
+  // Cache the privacy.firstparty.isolate pref.
+  static bool sFirstPartyIsolation = false;
+  static bool sCachedFirstPartyPref = false;
+  if (!sCachedFirstPartyPref) {
+    sCachedFirstPartyPref = true;
+    Preferences::AddBoolVarCache(&sFirstPartyIsolation, "privacy.firstparty.isolate");
+  }
+
+  return sFirstPartyIsolation;
+}
+
 BasePrincipal::BasePrincipal()
 {}
 
 BasePrincipal::~BasePrincipal()
 {}
 
 NS_IMETHODIMP
 BasePrincipal::GetOrigin(nsACString& aOrigin)
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -61,16 +61,19 @@ public:
   void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
 
   void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
 
 protected:
   OriginAttributes() {}
   explicit OriginAttributes(const OriginAttributesDictionary& aOther)
     : OriginAttributesDictionary(aOther) {}
+
+  // check if "privacy.firstparty.isolate" is enabled.
+  bool IsFirstPartyEnabled();
 };
 
 class PrincipalOriginAttributes;
 class DocShellOriginAttributes;
 class NeckoOriginAttributes;
 
 // Various classes in Gecko contain OriginAttributes members, and those
 // OriginAttributes get propagated to other classes according to certain rules.
@@ -132,17 +135,21 @@ public:
     mAppId = aAppId;
     mInIsolatedMozBrowser = aInIsolatedMozBrowser;
   }
 
   // Inheriting OriginAttributes from document to necko when a network request
   // is made.
   void InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs);
 
-  void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs);
+  // Inheriting OriginAttributes from a docshell when loading a top-level
+  // document.
+  void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs,
+                                  const bool aIsTopLevelDocument = false,
+                                  nsIURI* aURI = nullptr);
 };
 
 // For operating on OriginAttributes not associated with any data structure.
 class GenericOriginAttributes : public OriginAttributes
 {
 public:
   GenericOriginAttributes() {}
   explicit GenericOriginAttributes(const OriginAttributesDictionary& aOther)
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -432,47 +432,30 @@ nsScriptSecurityManager::GetChannelURIPr
     NS_PRECONDITION(aChannel, "Must have channel!");
 
     // Get the principal from the URI.  Make sure this does the same thing
     // as nsDocument::Reset and XULDocument::StartDocumentLoad.
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr<nsILoadContext> loadContext;
-    NS_QueryNotificationCallbacks(aChannel, loadContext);
-
     nsCOMPtr<nsILoadInfo> loadInfo;
     aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
-    nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_INVALID;
-    if (loadInfo) {
-      contentPolicyType = loadInfo->GetExternalContentPolicyType();
-    }
 
+    // Inherit the origin attributes from loadInfo.
+    // If this is a top-level document load, the origin attributes of the
+    // loadInfo will be set from nsDocShell::DoURILoad.
+    // For subresource loading, the origin attributes of the loadInfo is from
+    // its loadingPrincipal.
     PrincipalOriginAttributes attrs;
-    if (nsIContentPolicy::TYPE_DOCUMENT == contentPolicyType ||
-        nsIContentPolicy::TYPE_SUBDOCUMENT == contentPolicyType) {
-      // If it's document or sub-document, inherit originAttributes from
-      // the document.
-      if (loadContext) {
-        DocShellOriginAttributes docShellAttrs;
-        loadContext->GetOriginAttributes(docShellAttrs);
-        attrs.InheritFromDocShellToDoc(docShellAttrs, uri);
-      }
-    } else {
-      // Inherit origin attributes from loading principal if any.
-      nsCOMPtr<nsIPrincipal> loadingPrincipal;
-      if (loadInfo) {
-        loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal));
-      }
-      if (loadingPrincipal) {
-        attrs = BasePrincipal::Cast(loadingPrincipal)->OriginAttributesRef();
-      }
+
+    // For addons loadInfo might be null.
+    if (loadInfo) {
+      attrs.InheritFromNecko(loadInfo->GetOriginAttributes());
     }
-
     rv = MaybeSetAddonIdFromURI(attrs, uri);
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
     prin.forget(aPrincipal);
     return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10807,17 +10807,20 @@ nsDocShell::DoURILoad(nsIURI* aURI,
                    securityFlags) :
       new LoadInfo(loadingPrincipal, triggeringPrincipal, loadingNode,
                    securityFlags, aContentPolicyType);
 
   // We have to do this in case our OriginAttributes are different from the
   // OriginAttributes of the parent document. Or in case there isn't a
   // parent document.
   NeckoOriginAttributes neckoAttrs;
-  neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes());
+  bool isTopLevelDoc = aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT &&
+                       mItemType == typeContent &&
+                       !GetIsMozBrowserOrApp();
+  neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes(), isTopLevelDoc, aURI);
   rv = loadInfo->SetOriginAttributes(neckoAttrs);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!isSrcdoc) {
     rv = NS_NewChannelInternal(getter_AddRefs(channel),
                                aURI,
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2093,16 +2093,48 @@ nsFrameLoader::MaybeCreateDocShell()
     webNav->SetSessionHistory(sessionHistory);
   }
 
   DocShellOriginAttributes attrs;
   if (docShell->ItemType() == mDocShell->ItemType()) {
     attrs = nsDocShell::Cast(docShell)->GetOriginAttributes();
   }
 
+  // Inherit origin attributes from parent document if
+  // 1. It's in a content docshell.
+  // 2. its nodePrincipal is not a SystemPrincipal.
+  // 3. It's not a mozbrowser nor mozapp frame.
+  //
+  // For example, firstPartyDomain is computed from top-level document, it
+  // doesn't exist in the top-level docshell.
+  if (parentType == nsIDocShellTreeItem::typeContent &&
+      !nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) &&
+      !OwnerIsMozBrowserOrAppFrame()) {
+    PrincipalOriginAttributes poa = BasePrincipal::Cast(doc->NodePrincipal())->OriginAttributesRef();
+
+    // Assert on the firstPartyDomain from top-level docshell should be empty
+    if (mIsTopLevelContent) {
+      MOZ_ASSERT(attrs.mFirstPartyDomain.IsEmpty(),
+                 "top-level docshell shouldn't have firstPartyDomain attribute.");
+    }
+
+    // So far we want to make sure InheritFromDocToChildDocShell doesn't override
+    // any other origin attribute than firstPartyDomain.
+    MOZ_ASSERT(attrs.mAppId == poa.mAppId,
+              "docshell and document should have the same appId attribute.");
+    MOZ_ASSERT(attrs.mUserContextId == poa.mUserContextId,
+              "docshell and document should have the same userContextId attribute.");
+    MOZ_ASSERT(attrs.mInIsolatedMozBrowser == poa.mInIsolatedMozBrowser,
+              "docshell and document should have the same inIsolatedMozBrowser attribute.");
+    MOZ_ASSERT(attrs.mPrivateBrowsingId == poa.mPrivateBrowsingId,
+              "docshell and document should have the same privateBrowsingId attribute.");
+
+    attrs.InheritFromDocToChildDocShell(poa);
+  }
+
   if (OwnerIsAppFrame()) {
     // You can't be both an app and a browser frame.
     MOZ_ASSERT(!OwnerIsMozBrowserFrame());
 
     nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
     MOZ_ASSERT(ownApp);
     uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
     if (ownApp) {
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -143,16 +143,17 @@ NeckoParent::GetValidatedAppInfo(const S
       continue;
     }
     aAttrs = DocShellOriginAttributes();
     aAttrs.mAppId = appId;
     aAttrs.mInIsolatedMozBrowser = inBrowserElement;
     aAttrs.mSignedPkg = aSerialized.mOriginAttributes.mSignedPkg;
     aAttrs.mUserContextId = aSerialized.mOriginAttributes.mUserContextId;
     aAttrs.mPrivateBrowsingId = aSerialized.mOriginAttributes.mPrivateBrowsingId;
+    aAttrs.mFirstPartyDomain = aSerialized.mOriginAttributes.mFirstPartyDomain;
 
     return nullptr;
   }
 
   if (contextArray.Length() != 0) {
     return "App does not have permission";
   }