Bug 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 2 - AntiTracking, r=Ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 08 Mar 2019 09:00:24 +0000
changeset 520981 c08a35a9c0d6482a7dd85f00ee0d3b1b685c9a84
parent 520980 ccb173c2766838a1ef52bbf590947565398928fb
child 520982 bfab5b97ae49984ad48ae2e99dec041b43064067
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1525245
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1525245 - Stabilize cookiePolicy/cookiePermission for live documents - part 2 - AntiTracking, r=Ehsan Depends on D18949 Differential Revision: https://phabricator.services.mozilla.com/D18950
toolkit/components/antitracking/AntiTrackingCommon.cpp
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -151,82 +151,93 @@ void CreatePermissionKey(const nsCString
   aPermissionKey.Append(prefix);
   aPermissionKey.Append(aTrackingOrigin);
   aPermissionKey.AppendLiteral("^");
   aPermissionKey.Append(aGrantedOrigin);
 }
 
 // This internal method returns ACCESS_DENY if the access is denied,
 // ACCESS_DEFAULT if unknown, some other access code if granted.
-nsCookieAccess CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal) {
-  nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
+uint32_t CheckCookiePermissionForPrincipal(nsICookieSettings* aCookieSettings,
+                                           nsIPrincipal* aPrincipal) {
+  MOZ_ASSERT(aCookieSettings);
+  MOZ_ASSERT(aPrincipal);
+
+  uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
   if (!aPrincipal->GetIsCodebasePrincipal()) {
-    return access;
+    return cookiePermission;
   }
 
-  nsCOMPtr<nsICookiePermission> cps = nsCookiePermission::GetOrCreate();
-
-  nsresult rv = cps->CanAccess(aPrincipal, &access);
+  nsresult rv =
+      aCookieSettings->CookiePermission(aPrincipal, &cookiePermission);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nsICookiePermission::ACCESS_DEFAULT;
   }
 
   // If we have a custom cookie permission, let's use it.
-  return access;
+  return cookiePermission;
 }
 
-// This internal method returns ACCESS_DENY if the access is denied,
-// ACCESS_DEFAULT if unknown, some other access code if granted.
-nsCookieAccess CheckCookiePermissionForURI(nsIURI* aURI) {
-  nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
-
-  nsCOMPtr<nsICookiePermission> cps = nsCookiePermission::GetOrCreate();
+int32_t CookiesBehavior(Document* aTopLevelDocument,
+                        Document* a3rdPartyDocument) {
+  MOZ_ASSERT(aTopLevelDocument);
+  MOZ_ASSERT(a3rdPartyDocument);
 
-  nsresult rv = cps->CanAccessURI(aURI, &access);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nsICookiePermission::ACCESS_DEFAULT;
-  }
-
-  // If we have a custom cookie permission, let's use it.
-  return access;
-}
-
-int32_t CookiesBehavior(nsIPrincipal* aTopLevelPrincipal,
-                        nsIPrincipal* a3rdPartyPrincipal) {
   // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
   // (See Bug 1406675 for rationale).
-  if (BasePrincipal::Cast(aTopLevelPrincipal)->AddonPolicy()) {
+  if (BasePrincipal::Cast(aTopLevelDocument->NodePrincipal())->AddonPolicy()) {
     return nsICookieService::BEHAVIOR_ACCEPT;
   }
 
-  if (a3rdPartyPrincipal &&
-      BasePrincipal::Cast(a3rdPartyPrincipal)->AddonPolicy()) {
+  if (BasePrincipal::Cast(a3rdPartyDocument->NodePrincipal())->AddonPolicy()) {
     return nsICookieService::BEHAVIOR_ACCEPT;
   }
 
-  return StaticPrefs::network_cookie_cookieBehavior();
+  return a3rdPartyDocument->CookieSettings()->GetCookieBehavior();
 }
 
-int32_t CookiesBehavior(nsIPrincipal* aTopLevelPrincipal,
+int32_t CookiesBehavior(nsILoadInfo* aLoadInfo,
+                        nsIPrincipal* aTopLevelPrincipal,
                         nsIURI* a3rdPartyURI) {
+  MOZ_ASSERT(aLoadInfo);
+  MOZ_ASSERT(aTopLevelPrincipal);
+  MOZ_ASSERT(a3rdPartyURI);
+
   // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
   // (See Bug 1406675 for rationale).
   if (BasePrincipal::Cast(aTopLevelPrincipal)->AddonPolicy()) {
     return nsICookieService::BEHAVIOR_ACCEPT;
   }
 
   // This is semantically equivalent to the principal having a AddonPolicy().
   bool is3rdPartyMozExt = false;
-  if (a3rdPartyURI &&
-      NS_SUCCEEDED(
+  if (NS_SUCCEEDED(
           a3rdPartyURI->SchemeIs("moz-extension", &is3rdPartyMozExt)) &&
       is3rdPartyMozExt) {
     return nsICookieService::BEHAVIOR_ACCEPT;
   }
 
+  nsCOMPtr<nsICookieSettings> cookieSettings;
+  nsresult rv = aLoadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nsICookieService::BEHAVIOR_REJECT;
+  }
+
+  return cookieSettings->GetCookieBehavior();
+}
+
+int32_t CookiesBehavior(nsIPrincipal* aPrincipal) {
+  MOZ_ASSERT(aPrincipal);
+
+  // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
+  // (See Bug 1406675 for rationale).
+  if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
+    return nsICookieService::BEHAVIOR_ACCEPT;
+  }
+
   return StaticPrefs::network_cookie_cookieBehavior();
 }
 
 struct ContentBlockingAllowListKey {
   ContentBlockingAllowListKey() : mHash(mozilla::HashGeneric(uintptr_t(0))) {}
 
   // Ensure that we compute a different hash for window and channel pointers of
   // the same numeric value, in the off chance that we get unlucky and encounter
@@ -1061,50 +1072,69 @@ bool AntiTrackingCommon::IsFirstPartySto
   if (!aRejectedReason) {
     aRejectedReason = &rejectedReason;
   }
 
   LOG_SPEC(("Computing whether window %p has access to URI %s", aWindow, _spec),
            aURI);
 
   nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
-  nsIPrincipal* windowPrincipal = innerWindow->GetPrincipal();
-  if (!windowPrincipal) {
-    LOG(("Our window has no principal"));
+  Document* document = innerWindow->GetExtantDoc();
+  if (!document) {
+    LOG(("Our window has no document"));
+    return false;
+  }
+
+  nsGlobalWindowOuter* outerWindow =
+      nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
+  if (!outerWindow) {
+    LOG(("Our window has no outer window"));
+    return false;
+  }
+
+  nsCOMPtr<nsPIDOMWindowOuter> topOuterWindow = outerWindow->GetTop();
+  nsGlobalWindowOuter* topWindow = nsGlobalWindowOuter::Cast(topOuterWindow);
+  if (NS_WARN_IF(!topWindow)) {
+    LOG(("No top outer window"));
     return false;
   }
 
-  nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal();
-  if (!toplevelPrincipal) {
-    // We are already the top-level principal. Let's use the window's principal.
-    LOG(
-        ("Our inner window lacks a top-level principal, use the window's "
-         "principal instead"));
-    toplevelPrincipal = windowPrincipal;
+  nsPIDOMWindowInner* topInnerWindow = topWindow->GetCurrentInnerWindow();
+  if (NS_WARN_IF(!topInnerWindow)) {
+    LOG(("No top inner window."));
+    return false;
   }
 
-  MOZ_ASSERT(toplevelPrincipal);
+  Document* toplevelDocument = topInnerWindow->GetExtantDoc();
+  if (!toplevelDocument) {
+    LOG(("No top level document."));
+    return false;
+  }
 
-  nsCookieAccess access = CheckCookiePermissionForPrincipal(windowPrincipal);
-  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+  MOZ_ASSERT(toplevelDocument);
+
+  uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
+      document->CookieSettings(), document->NodePrincipal());
+  if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
     LOG(
         ("CheckCookiePermissionForPrincipal() returned a non-default access "
          "code (%d) for window's principal, returning %s",
-         int(access),
-         access != nsICookiePermission::ACCESS_DENY ? "success" : "failure"));
-    if (access != nsICookiePermission::ACCESS_DENY) {
+         int(cookiePermission),
+         cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
+                                                              : "failure"));
+    if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
       return true;
     }
 
     *aRejectedReason =
         nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
     return false;
   }
 
-  int32_t behavior = CookiesBehavior(toplevelPrincipal, windowPrincipal);
+  int32_t behavior = CookiesBehavior(toplevelDocument, document);
   if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
     LOG(("The cookie behavior pref mandates accepting all cookies!"));
     return true;
   }
 
   if (CheckContentBlockingAllowList(aWindow)) {
     return true;
   }
@@ -1173,53 +1203,32 @@ bool AntiTrackingCommon::IsFirstPartySto
 
   nsAutoCString grantedOrigin;
   nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, grantedOrigin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
     return false;
   }
 
-  nsGlobalWindowOuter* outerWindow =
-      nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
-  if (NS_WARN_IF(!outerWindow)) {
-    LOG(("No outer window."));
-    return false;
-  }
-
-  nsCOMPtr<nsPIDOMWindowOuter> topOuterWindow = outerWindow->GetTop();
-  nsGlobalWindowOuter* topWindow = nsGlobalWindowOuter::Cast(topOuterWindow);
-  if (NS_WARN_IF(!topWindow)) {
-    LOG(("No top outer window."));
-    return false;
-  }
-
-  nsPIDOMWindowInner* topInnerWindow = topWindow->GetCurrentInnerWindow();
-  if (NS_WARN_IF(!topInnerWindow)) {
-    LOG(("No top inner window."));
-    return false;
-  }
-
   nsAutoCString type;
   CreatePermissionKey(trackingOrigin, grantedOrigin, type);
 
   if (topInnerWindow->HasStorageAccessGranted(type)) {
     LOG(("Permission stored in the window. All good."));
     return true;
   }
 
   nsPermissionManager* permManager = nsPermissionManager::GetInstance();
   if (NS_WARN_IF(!permManager)) {
     LOG(("Failed to obtain the permission manager"));
     return false;
   }
 
   uint32_t result = 0;
-  rv = permManager->TestPermissionWithoutDefaultsFromPrincipal(parentPrincipal,
-                                                               type, &result);
+  rv = permManager->TestPermissionFromPrincipal(parentPrincipal, type, &result);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     LOG(("Failed to test the permission"));
     return false;
   }
 
   LOG_SPEC(
       ("Testing permission type %s for %s resulted in %d (%s)", type.get(),
        _spec, int(result),
@@ -1240,16 +1249,20 @@ bool AntiTrackingCommon::IsFirstPartySto
   MOZ_ASSERT(aChannel);
 
   // Let's avoid a null check on aRejectedReason everywhere else.
   uint32_t rejectedReason = 0;
   if (!aRejectedReason) {
     aRejectedReason = &rejectedReason;
   }
 
+  nsIScriptSecurityManager* ssm =
+      nsScriptSecurityManager::GetScriptSecurityManager();
+  MOZ_ASSERT(ssm);
+
   nsCOMPtr<nsIURI> channelURI;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
   if (NS_FAILED(rv)) {
     LOG(("Failed to get the channel final URI, bail out early"));
     return true;
   }
   LOG_SPEC(
       ("Computing whether channel %p has access to URI %s", aChannel, _spec),
@@ -1275,18 +1288,16 @@ bool AntiTrackingCommon::IsFirstPartySto
   if (!toplevelPrincipal) {
     LOG(
         ("We don't have a loading principal, let's see if this is a document "
          "channel"
          " that belongs to a top-level window"));
     bool isDocument = false;
     rv = aChannel->GetIsMainDocumentChannel(&isDocument);
     if (NS_SUCCEEDED(rv) && isDocument) {
-      nsIScriptSecurityManager* ssm =
-          nsScriptSecurityManager::GetScriptSecurityManager();
       rv = ssm->GetChannelResultPrincipal(aChannel,
                                           getter_AddRefs(toplevelPrincipal));
       if (NS_SUCCEEDED(rv)) {
         LOG(("Yes, we guessed right!"));
       } else {
         LOG(
             ("Yes, we guessed right, but minting the channel result principal "
              "failed"));
@@ -1304,38 +1315,57 @@ bool AntiTrackingCommon::IsFirstPartySto
     toplevelPrincipal = loadInfo->TriggeringPrincipal();
   }
 
   if (NS_WARN_IF(!toplevelPrincipal)) {
     LOG(("No top-level principal! Bail out early"));
     return false;
   }
 
-  if (NS_WARN_IF(NS_FAILED(rv) || !channelURI)) {
+  nsCOMPtr<nsICookieSettings> cookieSettings;
+  rv = loadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    LOG(
+        ("Failed to get the cookie settings from the loadinfo, bail out "
+         "early"));
+    return true;
+  }
+
+  nsCOMPtr<nsIPrincipal> channelPrincipal;
+  rv = ssm->GetChannelResultPrincipal(aChannel,
+                                      getter_AddRefs(channelPrincipal));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     LOG(("No channel principal, bail out early"));
     return false;
   }
 
-  nsCookieAccess access = CheckCookiePermissionForURI(channelURI);
-  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+  uint32_t cookiePermission =
+      CheckCookiePermissionForPrincipal(cookieSettings, channelPrincipal);
+  if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
     LOG(
         ("CheckCookiePermissionForPrincipal() returned a non-default access "
          "code (%d) for channel's principal, returning %s",
-         int(access),
-         access != nsICookiePermission::ACCESS_DENY ? "success" : "failure"));
-    if (access != nsICookiePermission::ACCESS_DENY) {
+         int(cookiePermission),
+         cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
+                                                              : "failure"));
+    if (cookiePermission != nsICookiePermission::ACCESS_DENY) {
       return true;
     }
 
     *aRejectedReason =
         nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
     return false;
   }
 
-  int32_t behavior = CookiesBehavior(toplevelPrincipal, channelURI);
+  if (!channelURI) {
+    LOG(("No channel uri, bail out early"));
+    return false;
+  }
+
+  int32_t behavior = CookiesBehavior(loadInfo, toplevelPrincipal, channelURI);
   if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
     LOG(("The cookie behavior pref mandates accepting all cookies!"));
     return true;
   }
 
   if (CheckContentBlockingAllowList(aChannel)) {
     return true;
   }
@@ -1460,69 +1490,75 @@ bool AntiTrackingCommon::IsFirstPartySto
 
   return true;
 }
 
 bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
     nsIPrincipal* aPrincipal) {
   MOZ_ASSERT(aPrincipal);
 
-  nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal);
+  nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
+  if (aPrincipal->GetIsCodebasePrincipal()) {
+    nsCOMPtr<nsICookiePermission> cps = nsCookiePermission::GetOrCreate();
+    Unused << NS_WARN_IF(NS_FAILED(cps->CanAccess(aPrincipal, &access)));
+  }
+
   if (access != nsICookiePermission::ACCESS_DEFAULT) {
     return access != nsICookiePermission::ACCESS_DENY;
   }
 
-  int32_t behavior =
-      CookiesBehavior(aPrincipal, static_cast<nsIPrincipal*>(nullptr));
+  int32_t behavior = CookiesBehavior(aPrincipal);
   return behavior != nsICookieService::BEHAVIOR_REJECT;
 }
 
 /* static */
 bool AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(
     nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) {
   MOZ_ASSERT(aFirstPartyWindow);
   MOZ_ASSERT(aURI);
 
   LOG_SPEC(
       ("Computing a best guess as to whether window %p has access to URI %s",
        aFirstPartyWindow, _spec),
       aURI);
 
-  if (StaticPrefs::network_cookie_cookieBehavior() !=
+  Document* parentDocument =
+      nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetExtantDoc();
+  if (NS_WARN_IF(!parentDocument)) {
+    LOG(("Failed to get the first party window's document"));
+    return false;
+  }
+
+  if (parentDocument->CookieSettings()->GetCookieBehavior() !=
       nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     LOG(("Disabled by the pref (%d), bail out early",
          StaticPrefs::network_cookie_cookieBehavior()));
     return true;
   }
 
   if (CheckContentBlockingAllowList(aFirstPartyWindow)) {
     return true;
   }
 
   if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow, nullptr,
                                                    aURI)) {
     LOG(("Our window isn't a third-party window"));
     return true;
   }
 
-  nsCOMPtr<nsIPrincipal> parentPrincipal =
-      nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetPrincipal();
-  if (NS_WARN_IF(!parentPrincipal)) {
-    LOG(("Failed to get the first party window's principal"));
-    return false;
-  }
-
-  nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal);
-  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+  uint32_t cookiePermission = CheckCookiePermissionForPrincipal(
+      parentDocument->CookieSettings(), parentDocument->NodePrincipal());
+  if (cookiePermission != nsICookiePermission::ACCESS_DEFAULT) {
     LOG(
         ("CheckCookiePermissionForPrincipal() returned a non-default access "
          "code (%d), returning %s",
-         int(access),
-         access != nsICookiePermission::ACCESS_DENY ? "success" : "failure"));
-    return access != nsICookiePermission::ACCESS_DENY;
+         int(cookiePermission),
+         cookiePermission != nsICookiePermission::ACCESS_DENY ? "success"
+                                                              : "failure"));
+    return cookiePermission != nsICookiePermission::ACCESS_DENY;
   }
 
   nsAutoCString origin;
   nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     LOG_SPEC(("Failed to compute the origin from %s", _spec), aURI);
     return false;
   }
@@ -1532,26 +1568,27 @@ bool AntiTrackingCommon::MaybeIsFirstPar
 
   nsPermissionManager* permManager = nsPermissionManager::GetInstance();
   if (NS_WARN_IF(!permManager)) {
     LOG(("Failed to obtain the permission manager"));
     return false;
   }
 
   uint32_t result = 0;
-  rv = permManager->TestPermissionWithoutDefaultsFromPrincipal(parentPrincipal,
-                                                               type, &result);
+  rv = permManager->TestPermissionWithoutDefaultsFromPrincipal(
+      parentDocument->NodePrincipal(), type, &result);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     LOG(("Failed to test the permission"));
     return false;
   }
 
   if (MOZ_LOG_TEST(gAntiTrackingLog, LogLevel::Debug)) {
     nsCOMPtr<nsIURI> parentPrincipalURI;
-    Unused << parentPrincipal->GetURI(getter_AddRefs(parentPrincipalURI));
+    Unused << parentDocument->NodePrincipal()->GetURI(
+        getter_AddRefs(parentPrincipalURI));
     LOG_SPEC(
         ("Testing permission type %s for %s resulted in %d (%s)", type.get(),
          _spec, int(result),
          result == nsIPermissionManager::ALLOW_ACTION ? "success" : "failure"),
         parentPrincipalURI);
   }
 
   return result == nsIPermissionManager::ALLOW_ACTION;