Bug 1474812 - No needs to store granted storage access in nsILoadInfo and in the inner window, r=ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 13 Jul 2018 12:02:19 +0200
changeset 481630 620bc27fbb62bd6f59646b023d105ecfd6087271
parent 481629 76de95da94dd0a6fdb622d9e2705f7be46dc6155
child 481631 36b513077735f95a2e60d8e829edcc9fa6a9bfaf
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1474812
milestone63.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 1474812 - No needs to store granted storage access in nsILoadInfo and in the inner window, r=ehsan
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/base/nsGlobalWindowOuter.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
ipc/glue/BackgroundUtils.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsILoadInfo.idl
netwerk/cookie/CookieServiceChild.cpp
netwerk/cookie/CookieServiceParent.cpp
netwerk/cookie/nsCookieService.cpp
netwerk/ipc/NeckoChannelParams.ipdlh
toolkit/components/antitracking/AntiTrackingCommon.cpp
toolkit/components/antitracking/AntiTrackingCommon.h
toolkit/components/antitracking/moz.build
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -24,16 +24,17 @@
 #include "Layers.h"
 #include "nsAppRunner.h"
 // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h.
 #include "nsNPAPIPluginInstance.h"
 #include "gfxDrawable.h"
 #include "gfxPrefs.h"
 #include "ImageOps.h"
 #include "mozAutoDocUpdate.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/AutoTimelineMarker.h"
 #include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
@@ -8865,31 +8866,20 @@ nsContentUtils::StorageDisabledByAntiTra
   }
 
   // Let's check if this is a 3rd party context.
   if (!IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) {
     return false;
   }
 
   if (aWindow) {
-    nsCOMPtr<nsIHttpChannel> httpChannel;
-    nsIDocument* document = aWindow->GetExtantDoc();
-    if (document) {
-      httpChannel = do_QueryInterface(document->GetChannel());
-    }
-
-    // If this is not a tracking resource, nothing is disabled.
-    if (!httpChannel || !httpChannel->GetIsTrackingResource()) {
-      return false;
-    }
-
-    // Maybe we want to grant this origin.
     nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
     if (documentURI &&
-        nsGlobalWindowInner::Cast(aWindow)->IsFirstPartyStorageAccessGrantedFor(documentURI)) {
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
+                                                                documentURI)) {
       return false;
     }
 
     return true;
   }
 
   // aChannel and aWindow are mutually exclusive.
   MOZ_ASSERT(aChannel);
@@ -8905,23 +8895,18 @@ nsContentUtils::StorageDisabledByAntiTra
   }
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = httpChannel->GetURI(getter_AddRefs(uri));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
-  nsCOMPtr<nsILoadInfo> loadInfo;
-  rv = aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  return !loadInfo->IsFirstPartyStorageAccessGrantedFor(uri);
+  return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                 uri);
 }
 
 // static, private
 nsContentUtils::StorageAccess
 nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
                                                    nsPIDOMWindowInner* aWindow,
                                                    nsIURI* aURI,
                                                    nsIChannel* aChannel)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7,16 +7,17 @@
 /*
  * Base class for all our document implementations.
  */
 
 #include "AudioChannelService.h"
 #include "nsDocument.h"
 #include "nsIDocumentInlines.h"
 #include "mozilla/AnimationComparator.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/CSSEnabledState.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/IntegerRange.h"
@@ -12449,17 +12450,18 @@ nsIDocument::MaybeAllowStorageForOpener(
   }
 
   nsAutoString origin;
   nsresult rv = nsContentUtils::GetUTFOrigin(uri, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  nsGlobalWindowInner::Cast(openerInner)->AddFirstPartyStorageAccessGrantedFor(origin);
+  AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(origin,
+                                                           openerInner);
 }
 
 bool
 nsIDocument::HasBeenUserGestureActivated()
 {
   if (mUserGestureActivated) {
     return true;
   }
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -31,17 +31,16 @@
 #include "mozilla/dom/StorageUtils.h"
 #include "mozilla/dom/Timeout.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/TimeoutManager.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/dom/WindowOrientationObserver.h"
 #endif
-#include "mozilla/StaticPrefs.h"
 #include "nsDOMOfflineResourceList.h"
 #include "nsError.h"
 #include "nsIIdleService.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
@@ -329,20 +328,16 @@ using mozilla::dom::cache::CacheStorage;
 #define MAX_SUCCESSIVE_DIALOG_COUNT 5
 
 // Idle fuzz time upper limit
 #define MAX_IDLE_FUZZ_TIME_MS 90000
 
 // Min idle notification time in seconds.
 #define MIN_IDLE_NOTIFICATION_TIME_S 1
 
-// Anti-tracking permission expiration
-#define ANTITRACKING_EXPIRATION 2592000000 // 30 days.
-#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
-
 static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
 
 static bool                 gIdleObserversAPIFuzzTimeDisabled = false;
 static FILE                *gDumpFile                         = nullptr;
 
 nsGlobalWindowInner::InnerWindowByIdTable *nsGlobalWindowInner::sInnerWindowsById = nullptr;
 
 bool nsGlobalWindowInner::sDragServiceDisabled = false;
@@ -917,18 +912,17 @@ nsGlobalWindowInner::nsGlobalWindowInner
     mSerial(0),
     mIdleRequestCallbackCounter(1),
     mIdleRequestExecutor(nullptr),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
     mObservingDidRefresh(false),
     mIteratingDocumentFlushedResolvers(false),
     mCanSkipCCGeneration(0),
-    mBeforeUnloadListenerCount(0),
-    mStorageGrantedOriginPopulated(false)
+    mBeforeUnloadListenerCount(0)
 {
   mIsInnerWindow = true;
 
   AssertIsOnMainThread();
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
@@ -1236,17 +1230,16 @@ nsGlobalWindowInner::FreeInnerObjects()
   }
 
   if (mIndexedDB) {
     mIndexedDB->DisconnectFromWindow(this);
     mIndexedDB = nullptr;
   }
 
   UnlinkHostObjectURIs();
-  ReleaseFirstPartyStorageAccessGrantedOrigins();
 
   NotifyWindowIDDestroyed("inner-window-destroyed");
 
   CleanupCachedXBLHandlers();
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     mAudioContexts[i]->Shutdown();
   }
@@ -1560,17 +1553,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
 
   tmp->UnlinkHostObjectURIs();
-  tmp->ReleaseFirstPartyStorageAccessGrantedOrigins();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
 
   // Here the IdleRequest list would've been unlinked, but we rely on
   // that IdleRequest objects have been traced and will remove
   // themselves while unlinking.
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource)
@@ -8057,299 +8049,16 @@ nsGlobalWindowInner::GetRegionalPrefsLoc
   AutoTArray<nsCString, 10> rpLocales;
   mozilla::intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales);
 
   for (const auto& loc : rpLocales) {
     aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc));
   }
 }
 
-void
-nsGlobalWindowInner::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
-                                                          bool aOverwritten)
-{
-  MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
-
-  if (aOverwritten) {
-    SaveFirstPartyStorageAccessGrantedFor(aOrigin);
-  }
-
-  for (StorageGrantedOrigin& data : mStorageGrantedOrigins) {
-    if (data.mOrigin == aOrigin) {
-      data.mOverwritten = aOverwritten;
-      return;
-    }
-  }
-
-  bool wasAllowed =
-    nsContentUtils::StorageDisabledByAntiTracking(this, nullptr, nullptr);
-
-  StorageGrantedOrigin* data = mStorageGrantedOrigins.AppendElement();
-  data->mOrigin = aOrigin;
-  data->mOverwritten = aOverwritten;
-
-  if (!wasAllowed &&
-      nsContentUtils::StorageDisabledByAntiTracking(this, nullptr, nullptr)) {
-    PropagateFirstPartyStorageAccessGrantedToWorkers(this);
-  }
-
-  // Let's store the origin in the loadInfo as well.
-  if (mDoc) {
-    nsCOMPtr<nsIChannel> channel = mDoc->GetChannel();
-    if (channel) {
-      nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
-      if (loadInfo) {
-        loadInfo->AddFirstPartyStorageAccessGrantedFor(aOrigin);
-      }
-    }
-  }
-}
-
-void
-nsGlobalWindowInner::GetFirstPartyStorageAccessGrantedOrigins(nsTArray<nsString>& aOrigin)
-{
-  aOrigin.Clear();
-
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
-    return;
-  }
-
-  MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
-  for (const StorageGrantedOrigin& data : mStorageGrantedOrigins) {
-    aOrigin.AppendElement(data.mOrigin);
-  }
-}
-
-bool
-nsGlobalWindowInner::IsFirstPartyStorageAccessGrantedFor(nsIURI* aURI)
-{
-  MOZ_ASSERT(aURI);
-
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
-    return true;
-  }
-
-  MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
-
-  if (mStorageGrantedOrigins.IsEmpty()) {
-    return false;
-  }
-
-  nsAutoString origin;
-  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  for (const StorageGrantedOrigin& data : mStorageGrantedOrigins) {
-    if (data.mOrigin.Equals(origin)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void
-nsGlobalWindowInner::ReleaseFirstPartyStorageAccessGrantedOrigins()
-{
-  mStorageGrantedOriginPopulated = false;
-  mStorageGrantedOrigins.Clear();
-
-}
-
-namespace mozilla {
-namespace dom {
-
-extern void
-SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
-                                                           const nsACString& aParentOrigin,
-                                                           const nsACString& aGrantedOrigin);
-
-} // namespace dom
-} // namespace mozilla
-
-void
-nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin)
-{
-  MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
-
-  // Now we need the principal and the origin of the parent window.
-  nsIPrincipal* parentPrincipal = GetTopLevelStorageAreaPrincipal();
-  if (NS_WARN_IF(!parentPrincipal)) {
-    return;
-  }
-
-  nsAutoCString parentOrigin;
-  nsresult rv = parentPrincipal->GetOriginNoSuffix(parentOrigin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  // Let's take the principal and the origin of the current window.
-  nsIPrincipal* principal = GetPrincipal();
-  if (NS_WARN_IF(!principal)) {
-    return;
-  }
-
-  NS_ConvertUTF16toUTF8 grantedOrigin(aOrigin);
-
-  if (XRE_IsParentProcess()) {
-    SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(principal,
-                                                               parentOrigin,
-                                                               grantedOrigin);
-    return;
-  }
-
-  // We have this external function because ContentChild includes windows.h and
-  // for this reason it cannot be included here.
-  SendFirstPartyStorageAccessGrantedForOriginToParentProcess(principal,
-                                                             parentOrigin,
-                                                             grantedOrigin);
-}
-
-/* static */ void
-nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
-                                                                                const nsCString& aParentOrigin,
-                                                                                const nsCString& aGrantedOrigin)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-
-  if (NS_WARN_IF(!aPrincipal)) {
-    // The child process is sending something wrong. Let's ignore it.
-    return;
-  }
-
-  nsAutoCString origin;
-  nsresult rv = aPrincipal->GetOriginNoSuffix(origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
-  if (NS_WARN_IF(!pm)) {
-    return;
-  }
-
-  int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + ANTITRACKING_EXPIRATION;
-
-  // We store a permission for the 3rd party principal, to know that we grant
-  // the storage permission when loaded by the current parent origin.
-  nsAutoCString type;
-  if (origin == aGrantedOrigin) {
-    type = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s", aParentOrigin.get());
-  } else {
-    type = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s", aParentOrigin.get(),
-                           aGrantedOrigin.get());
-  }
-
-  rv = pm->AddFromPrincipal(aPrincipal, type.get(),
-                            nsIPermissionManager::ALLOW_ACTION,
-                            nsIPermissionManager::EXPIRE_TIME, when);
-  Unused << NS_WARN_IF(NS_FAILED(rv));
-}
-
-void
-nsGlobalWindowInner::MaybeRestoreFirstPartyStorageAccessGrantedOrigins()
-{
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
-    return;
-  }
-
-  if (mStorageGrantedOriginPopulated) {
-    return;
-  }
-
-  mStorageGrantedOriginPopulated = true;
-
-  // Now we need the principal and the origin of the parent window.
-  nsIPrincipal* parentPrincipal = GetTopLevelStorageAreaPrincipal();
-  if (!parentPrincipal) {
-    // No parent window.
-    return;
-  }
-
-  nsAutoCString parentOrigin;
-  nsresult rv = parentPrincipal->GetOriginNoSuffix(parentOrigin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  // Let's take the principal and the origin of the current window.
-  nsIPrincipal* principal = GetPrincipal();
-  if (NS_WARN_IF(!principal)) {
-    return;
-  }
-
-  nsAutoCString origin;
-  rv = principal->GetOriginNoSuffix(origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
-  if (NS_WARN_IF(!pm)) {
-    return;
-  }
-
-  nsCOMPtr<nsISimpleEnumerator> enumerator;
-  rv = pm->GetAllForPrincipal(principal, getter_AddRefs(enumerator));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  bool more = false;
-  nsCOMPtr<nsISupports> iter;
-  nsCOMPtr<nsIPermission> perm;
-  while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
-    rv = enumerator->GetNext(getter_AddRefs(iter));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return;
-    }
-
-    perm = do_QueryInterface(iter);
-    if (NS_WARN_IF(!perm)) {
-      return;
-    }
-
-    nsAutoCString type;
-    rv = perm->GetType(type);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return;
-    }
-
-    if (!StringBeginsWith(type, NS_LITERAL_CSTRING(ANTITRACKING_PERM_KEY "^"))) {
-      continue;
-    }
-
-    nsCCharSeparatedTokenizer token(type, '^');
-    MOZ_ASSERT(token.hasMoreTokens());
-    auto value = token.nextToken();
-    MOZ_ASSERT(value.EqualsLiteral(ANTITRACKING_PERM_KEY));
-
-    nsAutoCString originA;
-    if (token.hasMoreTokens()) {
-      originA = token.nextToken();
-    }
-
-    // This permission was granted for another top-level window.
-    if (originA != parentOrigin) {
-      continue;
-    }
-
-    nsAutoCString originB;
-    if (token.hasMoreTokens()) {
-      originB = token.nextToken();
-    }
-
-    AddFirstPartyStorageAccessGrantedFor(NS_ConvertUTF8toUTF16(originB.IsEmpty() ? origin : originB),
-                                         false /* no overwrite */);
-  }
-}
-
 IntlUtils*
 nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError)
 {
   if (!mIntlUtils) {
     mIntlUtils = new IntlUtils(this);
   }
 
   return mIntlUtils;
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -712,30 +712,16 @@ public:
   GetPaintWorklet(mozilla::ErrorResult& aRv);
 
   void
   GetRegionalPrefsLocales(nsTArray<nsString>& aLocales);
 
   mozilla::dom::IntlUtils*
   GetIntlUtils(mozilla::ErrorResult& aRv);
 
-  void
-  AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin, bool aOverwritten = true);
-
-  void
-  GetFirstPartyStorageAccessGrantedOrigins(nsTArray<nsString>& aOrigins);
-
-  bool
-  IsFirstPartyStorageAccessGrantedFor(nsIURI* aURI);
-
-  static void
-  SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
-                                                             const nsCString& aParentOrigin,
-                                                             const nsCString& aGrantedOrigin);
-
 public:
   void Alert(nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   void Alert(const nsAString& aMessage,
              nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
   bool Confirm(const nsAString& aMessage,
                nsIPrincipal& aSubjectPrincipal,
@@ -1068,25 +1054,16 @@ protected:
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
   int32_t GetOuterHeight(mozilla::dom::CallerType aCallerType,
                          mozilla::ErrorResult& aError);
   void SetOuterHeight(int32_t aOuterHeight,
                       mozilla::dom::CallerType aCallerType,
                       mozilla::ErrorResult& aError);
 
-  void
-  ReleaseFirstPartyStorageAccessGrantedOrigins();
-
-  void
-  SaveFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin);
-
-  void
-  MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
-
   // Array of idle observers that are notified of idle events.
   nsTObserverArray<IdleObserverHolder> mIdleObservers;
 
   // Idle timer used for function callbacks to notify idle observers.
   nsCOMPtr<nsITimer> mIdleTimer;
 
   // Idle fuzz time added to idle timer callbacks.
   uint32_t mIdleFuzzFactor;
@@ -1124,19 +1101,16 @@ protected:
   nsresult ExecutionReady();
 
   // Inner windows only.
   nsresult DefineArgumentsProperty(nsIArray *aArguments);
 
   // Get the parent, returns null if this is a toplevel window
   nsPIDOMWindowOuter* GetParentInternal();
 
-  // Get the parent principal, returns null if this is a toplevel window.
-  nsIPrincipal* GetTopLevelStorageAreaPrincipal();
-
 public:
   // popup tracking
   bool IsPopupSpamWindow();
 
 private:
   // A type that methods called by CallOnChildren can return.  If Stop
   // is returned then CallOnChildren will stop calling further children.
   // If Continue is returned then CallOnChildren will keep calling further
@@ -1244,16 +1218,19 @@ public:
 
   // See PromiseWindowProxy.h for an explanation.
   void AddPendingPromise(mozilla::dom::Promise* aPromise);
   void RemovePendingPromise(mozilla::dom::Promise* aPromise);
 
 public:
   virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() override;
 
+  // Get the parent principal, returns null if this is a toplevel window.
+  nsIPrincipal* GetTopLevelStorageAreaPrincipal();
+
 protected:
   static void NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow);
   void NotifyWindowIDDestroyed(const char* aTopic);
 
   static void NotifyDOMWindowFrozen(nsGlobalWindowInner* aWindow);
   static void NotifyDOMWindowThawed(nsGlobalWindowInner* aWindow);
 
   virtual void UpdateParentTarget() override;
@@ -1497,23 +1474,16 @@ protected:
   RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
 
   mozilla::UniquePtr<mozilla::dom::ClientSource> mClientSource;
 
   nsTArray<RefPtr<mozilla::dom::Promise>> mPendingPromises;
 
   nsTArray<mozilla::UniquePtr<PromiseDocumentFlushedResolver>> mDocumentFlushedResolvers;
 
-  struct StorageGrantedOrigin {
-    nsString mOrigin;
-    bool mOverwritten;
-  };
-  nsTArray<StorageGrantedOrigin> mStorageGrantedOrigins;
-  bool mStorageGrantedOriginPopulated;
-
   static InnerWindowByIdTable* sInnerWindowsById;
 
   // Members in the mChromeFields member should only be used in chrome windows.
   // All accesses to this field should be guarded by a check of mIsChrome.
   struct ChromeFields {
     ChromeFields()
       : mGroupMessageManagers(1)
     {}
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -12,16 +12,17 @@
 
 // Local Includes
 #include "Navigator.h"
 #include "nsContentSecurityManager.h"
 #include "nsScreen.h"
 #include "nsHistory.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsIDOMStorageManager.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/LocalStorage.h"
 #include "mozilla/dom/Storage.h"
 #include "mozilla/dom/IdleRequest.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/StorageEvent.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/StorageNotifierService.h"
@@ -7073,17 +7074,17 @@ nsGlobalWindowOuter::MaybeAllowStorageFo
   }
 
   nsAutoString origin;
   nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  inner->AddFirstPartyStorageAccessGrantedFor(origin, true);
+  AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(origin, inner);
 }
 
 //*****************************************************************************
 // nsGlobalWindowOuter: Helper Functions
 //*****************************************************************************
 
 already_AddRefed<nsIDocShellTreeOwner>
 nsGlobalWindowOuter::GetTreeOwner()
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3301,35 +3301,16 @@ NextWindowID()
   uint64_t windowID = ++gNextWindowID;
 
   MOZ_RELEASE_ASSERT(windowID < (uint64_t(1) << kWindowIDWindowBits));
   uint64_t windowBits = windowID & ((uint64_t(1) << kWindowIDWindowBits) - 1);
 
   return (processBits << kWindowIDWindowBits) | windowBits;
 }
 
-// This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp
-// can't include ContentChild.h since it includes windows.h.
-void
-SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
-                                                           const nsACString& aParentOrigin,
-                                                           const nsACString& aGrantedOrigin)
-{
-  MOZ_ASSERT(!XRE_IsParentProcess());
-
-  ContentChild* cc = ContentChild::GetSingleton();
-  MOZ_ASSERT(cc);
-
-  // This is not really secure, because here we have the content process sending
-  // the request of storing a permission.
-  Unused << cc->SendFirstPartyStorageAccessGrantedForOrigin(IPC::Principal(aPrincipal),
-                                                            nsCString(aParentOrigin),
-                                                            nsCString(aGrantedOrigin));
-}
-
 mozilla::ipc::IPCResult
 ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
                                     const uint32_t& aAction)
 {
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (dragService) {
     dragService->StartDragSession();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -858,17 +858,12 @@ private:
 #endif
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 uint64_t
 NextWindowID();
 
-void
-SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
-                                                           const nsACString& aParentOrigin,
-                                                           const nsACString& aGrantedOrigin);
-
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ContentChild_h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -24,16 +24,17 @@
 #include "GMPServiceParent.h"
 #include "HandlerServiceParent.h"
 #include "IHistory.h"
 #include "imgIContainer.h"
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
 #include "mozilla/a11y/AccessibleWrap.h"
 #include "mozilla/a11y/Compatibility.h"
 #endif
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/DataStorage.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
@@ -112,17 +113,16 @@
 #include "nsCOMPtr.h"
 #include "nsChromeRegistryChrome.h"
 #include "nsConsoleMessage.h"
 #include "nsConsoleService.h"
 #include "nsContentUtils.h"
 #include "nsDebugImpl.h"
 #include "nsFrameLoader.h"
 #include "nsFrameMessageManager.h"
-#include "nsGlobalWindowInner.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsICookie.h"
 #include "nsContentPermissionHelper.h"
 #include "nsIContentProcess.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIDocShellTreeOwner.h"
@@ -5755,17 +5755,17 @@ ContentParent::RecvBHRThreadHang(const H
     nsCOMPtr<nsIHangDetails> hangDetails =
       new nsHangDetails(HangDetails(aDetails));
     obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aPrincipal,
-                                                           const nsCString& aParentOrigin,
+ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aParentPrincipal,
+                                                           const nsCString& aTrackingOrigin,
                                                            const nsCString& aGrantedOrigin)
 {
-  nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(aPrincipal,
-                                                                                  aParentOrigin,
-                                                                                  aGrantedOrigin);
+  AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(aParentPrincipal,
+                                                                                 aTrackingOrigin,
+                                                                                 aGrantedOrigin);
   return IPC_OK();
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1220,18 +1220,18 @@ public:
     nsTArray<ChildEventData>&& events) override;
   virtual mozilla::ipc::IPCResult RecvRecordDiscardedData(
     const DiscardedData& aDiscardedData) override;
 
   virtual mozilla::ipc::IPCResult RecvBHRThreadHang(
     const HangDetails& aHangDetails) override;
 
   virtual mozilla::ipc::IPCResult
-  RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aPrincipal,
-                                              const nsCString& aParentOrigin,
+  RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aParentPrincipal,
+                                              const nsCString& aTrackingOrigin,
                                               const nsCString& aGrantedOrigin) override;
 
   // Notify the ContentChild to enable the input event prioritization when
   // initializing.
   void MaybeEnableRemoteInputEventQueue();
 
 public:
   void SendGetFilesResponseAndForget(const nsID& aID,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1155,21 +1155,21 @@ parent:
 
     async MaybeReloadPlugins();
 
     async BHRThreadHang(HangDetails aHangDetails);
 
     async AddPerformanceMetrics(nsID aID, PerformanceInfo[] aMetrics);
 
     /*
-     * A 3rd party context (aPrincipal) has received the permission granted to
-     * have access to aGrantedOrigin when loaded by aParentOrigin.
+     * A 3rd party tracking origin (aTrackingOrigin) has received the permission
+     * granted to have access to aGrantedOrigin when loaded by aParentPrincipal.
      */
-    async FirstPartyStorageAccessGrantedForOrigin(Principal aPrincipal,
-                                                  nsCString aParentOrigin,
+    async FirstPartyStorageAccessGrantedForOrigin(Principal aParentPrincipal,
+                                                  nsCString aTrackingOrigin,
                                                   nsCString aGrantedOrigin);
 
 both:
      async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                         Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Notify `push-subscription-modified` observers in the parent and child.
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -334,16 +334,25 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
         getter_AddRefs(sandboxedLoadingPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = PrincipalToPrincipalInfo(sandboxedLoadingPrincipal,
                                   &sandboxedLoadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
     sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
   }
 
+  OptionalPrincipalInfo topLevelStorageAreaPrincipalInfo = mozilla::void_t();
+  if (aLoadInfo->TopLevelStorageAreaPrincipal()) {
+    PrincipalInfo topLevelStorageAreaPrincipalInfoTemp;
+    rv = PrincipalToPrincipalInfo(aLoadInfo->TopLevelStorageAreaPrincipal(),
+                                  &topLevelStorageAreaPrincipalInfoTemp);
+    NS_ENSURE_SUCCESS(rv, rv);
+    topLevelStorageAreaPrincipalInfo = topLevelStorageAreaPrincipalInfoTemp;
+  }
+
   OptionalURIParams optionalResultPrincipalURI = mozilla::void_t();
   nsCOMPtr<nsIURI> resultPrincipalURI;
   Unused << aLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
   if (resultPrincipalURI) {
     SerializeURI(resultPrincipalURI, optionalResultPrincipalURI);
   }
 
   nsTArray<RedirectHistoryEntryInfo> redirectChainIncludingInternalRedirects;
@@ -394,21 +403,21 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
   }
 
   *aOptionalLoadInfoArgs =
     LoadInfoArgs(
       loadingPrincipalInfo,
       triggeringPrincipalInfo,
       principalToInheritInfo,
       sandboxedLoadingPrincipalInfo,
+      topLevelStorageAreaPrincipalInfo,
       optionalResultPrincipalURI,
       aLoadInfo->GetSecurityFlags(),
       aLoadInfo->InternalContentPolicyType(),
       static_cast<uint32_t>(aLoadInfo->GetTainting()),
-      aLoadInfo->GetFirstPartyStorageAccessGrantedOrigins(),
       aLoadInfo->GetUpgradeInsecureRequests(),
       aLoadInfo->GetBrowserUpgradeInsecureRequests(),
       aLoadInfo->GetBrowserWouldUpgradeInsecureRequests(),
       aLoadInfo->GetVerifySignedContent(),
       aLoadInfo->GetEnforceSRI(),
       aLoadInfo->GetForceAllowDataURI(),
       aLoadInfo->GetAllowInsecureRedirectToDataURI(),
       aLoadInfo->GetSkipContentPolicyCheckForWebRequest(),
@@ -473,16 +482,23 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
 
   nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal;
   if (loadInfoArgs.sandboxedLoadingPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
     sandboxedLoadingPrincipal =
       PrincipalInfoToPrincipal(loadInfoArgs.sandboxedLoadingPrincipalInfo(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  nsCOMPtr<nsIPrincipal> topLevelStorageAreaPrincipal;
+  if (loadInfoArgs.topLevelStorageAreaPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
+    topLevelStorageAreaPrincipal =
+      PrincipalInfoToPrincipal(loadInfoArgs.topLevelStorageAreaPrincipalInfo(), &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   nsCOMPtr<nsIURI> resultPrincipalURI;
   if (loadInfoArgs.resultPrincipalURI().type() != OptionalURIParams::Tvoid_t) {
     resultPrincipalURI = DeserializeURI(loadInfoArgs.resultPrincipalURI());
     NS_ENSURE_TRUE(resultPrincipalURI, NS_ERROR_UNEXPECTED);
   }
 
   RedirectHistoryArray redirectChainIncludingInternalRedirects;
   for (const RedirectHistoryEntryInfo& entryInfo :
@@ -539,25 +555,25 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
       loadInfoArgs.controller().get_IPCServiceWorkerDescriptor()));
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(loadingPrincipal,
                           triggeringPrincipal,
                           principalToInherit,
                           sandboxedLoadingPrincipal,
+                          topLevelStorageAreaPrincipal,
                           resultPrincipalURI,
                           clientInfo,
                           reservedClientInfo,
                           initialClientInfo,
                           controller,
                           loadInfoArgs.securityFlags(),
                           loadInfoArgs.contentPolicyType(),
                           static_cast<LoadTainting>(loadInfoArgs.tainting()),
-                          loadInfoArgs.firstPartyStorageAccessGrantedOrigins(),
                           loadInfoArgs.upgradeInsecureRequests(),
                           loadInfoArgs.browserUpgradeInsecureRequests(),
                           loadInfoArgs.browserWouldUpgradeInsecureRequests(),
                           loadInfoArgs.verifySignedContent(),
                           loadInfoArgs.enforceSRI(),
                           loadInfoArgs.forceAllowDataURI(),
                           loadInfoArgs.allowInsecureRedirectToDataURI(),
                           loadInfoArgs.skipContentPolicyCheckForWebRequest(),
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -149,17 +149,18 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
       mOuterWindowID = contextOuter->WindowID();
       nsCOMPtr<nsPIDOMWindowOuter> parent = contextOuter->GetScriptableParent();
       mParentOuterWindowID = parent ? parent->WindowID() : mOuterWindowID;
       mTopOuterWindowID = FindTopOuterWindowID(contextOuter);
 
       nsGlobalWindowInner* innerWindow =
         nsGlobalWindowInner::Cast(contextOuter->GetCurrentInnerWindow());
       if (innerWindow) {
-        innerWindow->GetFirstPartyStorageAccessGrantedOrigins(mFirstPartyStorageAccessGrantedOrigins);
+        mTopLevelStorageAreaPrincipal =
+          innerWindow->GetTopLevelStorageAreaPrincipal();
       }
     }
 
     mInnerWindowID = aLoadingContext->OwnerDoc()->InnerWindowID();
     mAncestorPrincipals = aLoadingContext->OwnerDoc()->AncestorPrincipals();
     mAncestorOuterWindowIDs = aLoadingContext->OwnerDoc()->AncestorOuterWindowIDs();
     MOZ_DIAGNOSTIC_ASSERT(mAncestorPrincipals.Length() == mAncestorOuterWindowIDs.Length());
 
@@ -338,17 +339,18 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   // with the hidden window.
   nsCOMPtr<nsPIDOMWindowOuter> parent = aOuterWindow->GetScriptableParent();
   mParentOuterWindowID = parent ? parent->WindowID() : 0;
   mTopOuterWindowID = FindTopOuterWindowID(aOuterWindow);
 
   nsGlobalWindowInner* innerWindow =
     nsGlobalWindowInner::Cast(aOuterWindow->GetCurrentInnerWindow());
   if (innerWindow) {
-    innerWindow->GetFirstPartyStorageAccessGrantedOrigins(mFirstPartyStorageAccessGrantedOrigins);
+    mTopLevelStorageAreaPrincipal =
+      innerWindow->GetTopLevelStorageAreaPrincipal();
   }
 
   // get the docshell from the outerwindow, and then get the originattributes
   nsCOMPtr<nsIDocShell> docShell = aOuterWindow->GetDocShell();
   MOZ_ASSERT(docShell);
   mOriginAttributes = nsDocShell::Cast(docShell)->GetOriginAttributes();
   mAncestorPrincipals = nsDocShell::Cast(docShell)->AncestorPrincipals();
   mAncestorOuterWindowIDs = nsDocShell::Cast(docShell)->AncestorOuterWindowIDs();
@@ -362,16 +364,17 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
 #endif
 }
 
 LoadInfo::LoadInfo(const LoadInfo& rhs)
   : mLoadingPrincipal(rhs.mLoadingPrincipal)
   , mTriggeringPrincipal(rhs.mTriggeringPrincipal)
   , mPrincipalToInherit(rhs.mPrincipalToInherit)
   , mSandboxedLoadingPrincipal(rhs.mSandboxedLoadingPrincipal)
+  , mTopLevelStorageAreaPrincipal(rhs.mTopLevelStorageAreaPrincipal)
   , mResultPrincipalURI(rhs.mResultPrincipalURI)
   , mClientInfo(rhs.mClientInfo)
   // mReservedClientSource must be handled specially during redirect
   // mReservedClientInfo must be handled specially during redirect
   // mInitialClientInfo must be handled specially during redirect
   , mController(rhs.mController)
   , mPerformanceStorage(rhs.mPerformanceStorage)
   , mLoadingContext(rhs.mLoadingContext)
@@ -412,25 +415,25 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mServiceWorkerTaintingSynthesized(false)
 {
 }
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsIPrincipal* aPrincipalToInherit,
                    nsIPrincipal* aSandboxedLoadingPrincipal,
+                   nsIPrincipal* aTopLevelStorageAreaPrincipal,
                    nsIURI* aResultPrincipalURI,
                    const Maybe<ClientInfo>& aClientInfo,
                    const Maybe<ClientInfo>& aReservedClientInfo,
                    const Maybe<ClientInfo>& aInitialClientInfo,
                    const Maybe<ServiceWorkerDescriptor>& aController,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType,
                    LoadTainting aTainting,
-                   const nsTArray<nsString>& aFirstPartyStorageAccessGrantedOrigins,
                    bool aUpgradeInsecureRequests,
                    bool aBrowserUpgradeInsecureRequests,
                    bool aBrowserWouldUpgradeInsecureRequests,
                    bool aVerifySignedContent,
                    bool aEnforceSRI,
                    bool aForceAllowDataURI,
                    bool aAllowInsecureRedirectToDataURI,
                    bool aSkipContentPolicyCheckForWebRequest,
@@ -452,25 +455,25 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    const nsTArray<nsCString>& aCorsUnsafeHeaders,
                    bool aForcePreflight,
                    bool aIsPreflight,
                    bool aLoadTriggeredFromExternal,
                    bool aServiceWorkerTaintingSynthesized)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mPrincipalToInherit(aPrincipalToInherit)
+  , mTopLevelStorageAreaPrincipal(aTopLevelStorageAreaPrincipal)
   , mResultPrincipalURI(aResultPrincipalURI)
   , mClientInfo(aClientInfo)
   , mReservedClientInfo(aReservedClientInfo)
   , mInitialClientInfo(aInitialClientInfo)
   , mController(aController)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(aTainting)
-  , mFirstPartyStorageAccessGrantedOrigins(aFirstPartyStorageAccessGrantedOrigins)
   , mUpgradeInsecureRequests(aUpgradeInsecureRequests)
   , mBrowserUpgradeInsecureRequests(aBrowserUpgradeInsecureRequests)
   , mBrowserWouldUpgradeInsecureRequests(aBrowserWouldUpgradeInsecureRequests)
   , mVerifySignedContent(aVerifySignedContent)
   , mEnforceSRI(aEnforceSRI)
   , mForceAllowDataURI(aForceAllowDataURI)
   , mAllowInsecureRedirectToDataURI(aAllowInsecureRedirectToDataURI)
   , mSkipContentPolicyCheckForWebRequest(aSkipContentPolicyCheckForWebRequest)
@@ -635,16 +638,29 @@ LoadInfo::GetSandboxedLoadingPrincipal(n
   MOZ_ASSERT(mSandboxedLoadingPrincipal);
 
   nsCOMPtr<nsIPrincipal> copy(mSandboxedLoadingPrincipal);
   copy.forget(aPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::GetTopLevelStorageAreaPrincipal(nsIPrincipal** aTopLevelStorageAreaPrincipal)
+{
+  NS_IF_ADDREF(*aTopLevelStorageAreaPrincipal = mTopLevelStorageAreaPrincipal);
+  return NS_OK;
+}
+
+nsIPrincipal*
+LoadInfo::TopLevelStorageAreaPrincipal()
+{
+  return mTopLevelStorageAreaPrincipal;
+}
+
+NS_IMETHODIMP
 LoadInfo::GetLoadingDocument(nsIDocument** aResult)
 {
   nsCOMPtr<nsINode> node = do_QueryReferent(mLoadingContext);
   if (node) {
     nsCOMPtr<nsIDocument> context = node->OwnerDoc();
     context.forget(aResult);
   }
   return NS_OK;
@@ -1401,42 +1417,10 @@ LoadInfo::SetPerformanceStorage(Performa
 }
 
 PerformanceStorage*
 LoadInfo::GetPerformanceStorage()
 {
   return mPerformanceStorage;
 }
 
-const nsTArray<nsString>&
-LoadInfo::GetFirstPartyStorageAccessGrantedOrigins()
-{
-  return mFirstPartyStorageAccessGrantedOrigins;
-}
-
-bool
-LoadInfo::IsFirstPartyStorageAccessGrantedFor(nsIURI* aURI)
-{
-  MOZ_ASSERT(aURI);
-
-  if (mFirstPartyStorageAccessGrantedOrigins.IsEmpty()) {
-    return false;
-  }
-
-  nsAutoString origin;
-  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  return mFirstPartyStorageAccessGrantedOrigins.Contains(origin);
-}
-
-void
-LoadInfo::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin)
-{
-  if (!mFirstPartyStorageAccessGrantedOrigins.Contains(aOrigin)) {
-    mFirstPartyStorageAccessGrantedOrigins.AppendElement(aOrigin);
-  }
-}
-
 } // namespace net
 } // namespace mozilla
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -92,25 +92,25 @@ private:
   // private constructor that is only allowed to be called from within
   // HttpChannelParent and FTPChannelParent declared as friends undeneath.
   // In e10s we can not serialize nsINode, hence we store the innerWindowID.
   // Please note that aRedirectChain uses swapElements.
   LoadInfo(nsIPrincipal* aLoadingPrincipal,
            nsIPrincipal* aTriggeringPrincipal,
            nsIPrincipal* aPrincipalToInherit,
            nsIPrincipal* aSandboxedLoadingPrincipal,
+           nsIPrincipal* aTopLevelStorageAreaPrincipal,
            nsIURI* aResultPrincipalURI,
            const Maybe<mozilla::dom::ClientInfo>& aClientInfo,
            const Maybe<mozilla::dom::ClientInfo>& aReservedClientInfo,
            const Maybe<mozilla::dom::ClientInfo>& aInitialClientInfo,
            const Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
            nsSecurityFlags aSecurityFlags,
            nsContentPolicyType aContentPolicyType,
            LoadTainting aTainting,
-           const nsTArray<nsString>& aFirstPartyStorageAccessGrantedOrigins,
            bool aUpgradeInsecureRequests,
            bool aBrowserUpgradeInsecureRequests,
            bool aBrowserWouldUpgradeInsecureRequests,
            bool aVerifySignedContent,
            bool aEnforceSRI,
            bool aForceAllowDataURI,
            bool aAllowInsecureRedirectToDataURI,
            bool aSkipContentPolicyCheckForWebRequest,
@@ -155,31 +155,31 @@ private:
   friend class mozilla::dom::XMLHttpRequestMainThread;
 
   // if you add a member, please also update the copy constructor and consider if
   // it should be merged from parent channel through ParentLoadInfoForwarderArgs.
   nsCOMPtr<nsIPrincipal>           mLoadingPrincipal;
   nsCOMPtr<nsIPrincipal>           mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal>           mPrincipalToInherit;
   nsCOMPtr<nsIPrincipal>           mSandboxedLoadingPrincipal;
+  nsCOMPtr<nsIPrincipal>           mTopLevelStorageAreaPrincipal;
   nsCOMPtr<nsIURI>                 mResultPrincipalURI;
 
   Maybe<mozilla::dom::ClientInfo>               mClientInfo;
   UniquePtr<mozilla::dom::ClientSource>         mReservedClientSource;
   Maybe<mozilla::dom::ClientInfo>               mReservedClientInfo;
   Maybe<mozilla::dom::ClientInfo>               mInitialClientInfo;
   Maybe<mozilla::dom::ServiceWorkerDescriptor>  mController;
   RefPtr<mozilla::dom::PerformanceStorage>      mPerformanceStorage;
 
   nsWeakPtr                        mLoadingContext;
   nsWeakPtr                        mContextForTopLevelLoad;
   nsSecurityFlags                  mSecurityFlags;
   nsContentPolicyType              mInternalContentPolicyType;
   LoadTainting                     mTainting;
-  nsTArray<nsString>               mFirstPartyStorageAccessGrantedOrigins;
   bool                             mUpgradeInsecureRequests;
   bool                             mBrowserUpgradeInsecureRequests;
   bool                             mBrowserWouldUpgradeInsecureRequests;
   bool                             mVerifySignedContent;
   bool                             mEnforceSRI;
   bool                             mForceAllowDataURI;
   bool                             mAllowInsecureRedirectToDataURI;
   bool                             mSkipContentPolicyCheckForWebRequest;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -873,16 +873,29 @@ interface nsILoadInfo : nsISupports
    * Returns the null principal of the resulting resource if the SEC_SANDBOXED
    * flag is set.  Otherwise returns null.  This is used by
    * GetChannelResultPrincipal() to ensure that the same null principal object
    * is returned every time.
    */
   [noscript] readonly attribute nsIPrincipal sandboxedLoadingPrincipal;
 
   /**
+   * Return the top-level storage area principal, which is the principal of
+   * the top-level window if it's not a 3rd party context, non tracking
+   * resource.
+   */
+  [noscript] readonly attribute nsIPrincipal topLevelStorageAreaPrincipal;
+
+  /**
+   * A C++-friendly version of topLevelStorageAreaPrincipal.
+   */
+  [noscript, notxpcom, nostdcall, binaryname(TopLevelStorageAreaPrincipal)]
+  nsIPrincipal binaryTopLevelStorageAreaPrincipal();
+
+  /**
    * Note which client (i.e. global) initiated this network request.  All
    * nsGlobalWindow and WorkerPrivate can be converted to a ClientInfo to
    * be set here.  While this is being added to support service worker
    * FetchEvent, it can also be used to communicate other information about
    * the source global context in the future.
    */
   [noscript, nostdcall, notxpcom]
   void SetClientInfo(in const_ClientInfoRef aClientInfo);
@@ -1015,20 +1028,9 @@ interface nsILoadInfo : nsISupports
     * exact tainting level of the Response passed to FetchEvent.respondWith().
     * This method allows us to override the tainting level in that case.
     *
     * NOTE: This should not be used outside of service worker code! Use
     *       nsILoadInfo::MaybeIncreaseTainting() instead.
    */
   [noscript, nostdcall, notxpcom]
   void SynthesizeServiceWorkerTainting(in LoadTainting aTainting);
-
-  /**
-   * This is the origin that has access storage granted also if 3rd party and
-   * in the tracking protection list.
-   */
-  [noscript, notxpcom, nostdcall]
-  StringArrayRef getFirstPartyStorageAccessGrantedOrigins();
-  [noscript, notxpcom, nostdcall]
-  bool isFirstPartyStorageAccessGrantedFor(in nsIURI aURI);
-  [noscript, notxpcom, nostdcall]
-  void addFirstPartyStorageAccessGrantedFor(in AString aOrigin);
 };
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/NeckoChannelParams.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/SystemGroup.h"
 #include "nsCookie.h"
@@ -177,24 +178,26 @@ CookieServiceChild::TrackCookieLoad(nsIC
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
   if (RequireThirdPartyCheck()) {
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
   }
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                uri)) {
+      firstPartyStorageAccessGranted = true;
+    }
   }
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   mozilla::OriginAttributes attrs;
   if (loadInfo) {
     attrs = loadInfo->GetOriginAttributes();
-    if (loadInfo->IsFirstPartyStorageAccessGrantedFor(uri)) {
-      firstPartyStorageAccessGranted = true;
-    }
   }
   URIParams uriParams;
   SerializeURI(uri, uriParams);
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
   SendPrepareCookieList(uriParams, isForeign, isTrackingResource,
                         firstPartyStorageAccessGranted, isSafeTopLevelNav,
                         isSameSiteForeign, attrs);
@@ -568,24 +571,25 @@ CookieServiceChild::GetCookieStringInter
   }
 
   // Asynchronously call the parent.
   bool isForeign = true;
   if (RequireThirdPartyCheck())
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   bool isTrackingResource = false;
+  bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
-  }
-
-  bool firstPartyStorageAccessGranted = false;
-  if (loadInfo->IsFirstPartyStorageAccessGrantedFor(aHostURI)) {
-    firstPartyStorageAccessGranted = true;
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                aHostURI)) {
+      firstPartyStorageAccessGranted = true;
+    }
   }
 
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
 
   nsAutoCString result;
   if (!mIPCSync) {
     GetCookieStringFromCookieHashTable(aHostURI, isForeign, isTrackingResource,
@@ -624,43 +628,45 @@ CookieServiceChild::SetCookieStringInter
     return NS_OK;
 
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
   if (RequireThirdPartyCheck())
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   bool isTrackingResource = false;
+  bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                aHostURI)) {
+      firstPartyStorageAccessGranted = true;
+    }
   }
 
   nsDependentCString cookieString(aCookieString);
   nsDependentCString stringServerTime;
   if (aServerTime)
     stringServerTime.Rebind(aServerTime);
 
   URIParams hostURIParams;
   SerializeURI(aHostURI, hostURIParams);
 
   nsCOMPtr<nsIURI> channelURI;
   aChannel->GetURI(getter_AddRefs(channelURI));
   URIParams channelURIParams;
   SerializeURI(channelURI, channelURIParams);
 
-  bool firstPartyStorageAccessGranted = false;
   mozilla::OriginAttributes attrs;
   if (aChannel) {
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     if (loadInfo) {
       attrs = loadInfo->GetOriginAttributes();
-      if (loadInfo->IsFirstPartyStorageAccessGrantedFor(aHostURI)) {
-        firstPartyStorageAccessGranted = true;
-      }
     }
   }
 
   // Asynchronously call the parent.
   if (mIPCOpen) {
     SendSetCookieString(hostURIParams, channelURIParams,
                         isForeign, isTrackingResource,
                         firstPartyStorageAccessGranted, cookieString,
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -152,24 +152,25 @@ CookieServiceParent::TrackCookieLoad(nsI
 
   // Send matching cookies to Child.
   nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
   thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
   bool isForeign = true;
   thirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
 
   bool isTrackingResource = false;
+  bool storageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
-  }
-
-  bool storageAccessGranted = false;
-  if (loadInfo && loadInfo->IsFirstPartyStorageAccessGrantedFor(uri)) {
-    storageAccessGranted = true;
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                uri)) {
+      storageAccessGranted = true;
+    }
   }
 
   nsTArray<nsCookie*> foundCookieList;
   mCookieService->GetCookiesForURI(uri, isForeign, isTrackingResource,
                                    storageAccessGranted, isSafeTopLevelNav,
                                    aIsSameSiteForeign, false, attrs,
                                    foundCookieList);
   nsTArray<CookieStruct> matchingCookiesList;
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Printf.h"
 #include "mozilla/Unused.h"
 
 #include "mozilla/net/CookieServiceChild.h"
@@ -2035,29 +2036,30 @@ nsCookieService::GetCookieStringCommon(n
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG(aCookie);
 
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
   mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   bool isTrackingResource = false;
+  bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
+
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                aHostURI)) {
+      firstPartyStorageAccessGranted = true;
+    }
   }
 
   OriginAttributes attrs;
-  bool firstPartyStorageAccessGranted = false;
   if (aChannel) {
-    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
-    if (loadInfo && loadInfo->IsFirstPartyStorageAccessGrantedFor(aHostURI)) {
-      firstPartyStorageAccessGranted = true;
-    }
-
     NS_GetOriginAttributes(aChannel, attrs);
   }
 
   bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
   bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
   nsAutoCString result;
   GetCookieStringInternal(aHostURI, isForeign, isTrackingResource,
                           firstPartyStorageAccessGranted, isSafeTopLevelNav,
@@ -2141,29 +2143,31 @@ nsCookieService::SetCookieStringCommon(n
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG(aCookieHeader);
 
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
   mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   bool isTrackingResource = false;
+  bool firstPartyStorageAccessGranted = false;
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   if (httpChannel) {
     isTrackingResource = httpChannel->GetIsTrackingResource();
+
+    if (isForeign && isTrackingResource &&
+        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                aHostURI)) {
+      firstPartyStorageAccessGranted = true;
+    }
   }
 
   OriginAttributes attrs;
-  bool firstPartyStorageAccessGranted = false;
   if (aChannel) {
     NS_GetOriginAttributes(aChannel, attrs);
-    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
-    if (loadInfo && loadInfo->IsFirstPartyStorageAccessGrantedFor(aHostURI)) {
-      firstPartyStorageAccessGranted = true;
-    }
   }
 
   nsDependentCString cookieString(aCookieHeader);
   nsDependentCString serverTime(aServerTime ? aServerTime : "");
   SetCookieStringInternal(aHostURI, isForeign, isTrackingResource,
                           firstPartyStorageAccessGranted, cookieString,
                           serverTime, aFromHttp, attrs, aChannel);
   return NS_OK;
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -37,21 +37,21 @@ struct RedirectHistoryEntryInfo
 };
 
 struct LoadInfoArgs
 {
   OptionalPrincipalInfo       requestingPrincipalInfo;
   PrincipalInfo               triggeringPrincipalInfo;
   OptionalPrincipalInfo       principalToInheritInfo;
   OptionalPrincipalInfo       sandboxedLoadingPrincipalInfo;
+  OptionalPrincipalInfo       topLevelStorageAreaPrincipalInfo;
   OptionalURIParams           resultPrincipalURI;
   uint32_t                    securityFlags;
   uint32_t                    contentPolicyType;
   uint32_t                    tainting;
-  nsString[]                  firstPartyStorageAccessGrantedOrigins;
   bool                        upgradeInsecureRequests;
   bool                        browserUpgradeInsecureRequests;
   bool                        browserWouldUpgradeInsecureRequests;
   bool                        verifySignedContent;
   bool                        enforceSRI;
   bool                        forceAllowDataURI;
   bool                        allowInsecureRedirectToDataURI;
   bool                        skipContentPolicyCheckForWebRequest;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AntiTrackingCommon.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/StaticPrefs.h"
+#include "mozIThirdPartyUtil.h"
+#include "nsContentUtils.h"
+#include "nsGlobalWindowInner.h"
+#include "nsIPermissionManager.h"
+#include "nsIPrincipal.h"
+#include "nsIURI.h"
+#include "nsPIDOMWindow.h"
+#include "prtime.h"
+
+// Anti-tracking permission expiration
+#define ANTITRACKING_EXPIRATION 2592000000 // 30 days.
+#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
+
+using namespace mozilla;
+using mozilla::dom::ContentChild;
+
+namespace {
+
+bool
+GetParentPrincipalAndTrackingOrigin(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
+                                    nsIPrincipal** aParentPrincipal,
+                                    nsACString& aTrackingOrigin)
+{
+#ifdef DEBUG
+  MOZ_ASSERT(nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow,
+                                                         nullptr, nullptr));
+  MOZ_ASSERT(nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow));
+#endif
+
+  nsGlobalWindowInner* innerWindow =
+    nsGlobalWindowInner::Cast(a3rdPartyTrackingWindow);
+
+  // Now we need the principal and the origin of the parent window.
+  nsCOMPtr<nsIPrincipal> parentPrincipal =
+    innerWindow->GetTopLevelStorageAreaPrincipal();
+  if (NS_WARN_IF(!parentPrincipal)) {
+    return false;
+  }
+
+  // Let's take the principal and the origin of the tracker.
+  nsIPrincipal* trackingPrincipal = innerWindow->GetPrincipal();
+  if (NS_WARN_IF(!trackingPrincipal)) {
+    return false;
+  }
+
+  nsresult rv = trackingPrincipal->GetOriginNoSuffix(aTrackingOrigin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  parentPrincipal.forget(aParentPrincipal);
+  return true;
+};
+
+void
+CreatePermissionKey(const nsCString& aTrackingOrigin,
+                    const nsCString& aGrantedOrigin,
+                    nsACString& aPermissionKey)
+{
+  if (aTrackingOrigin == aGrantedOrigin) {
+    aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s",
+                                     aTrackingOrigin.get());
+    return;
+  }
+
+  aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s",
+                                   aTrackingOrigin.get(),
+                                   aGrantedOrigin.get());
+}
+
+} // anonymous
+
+/* static */ void
+AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
+                                                         nsPIDOMWindowInner* a3rdPartyTrackingWindow)
+{
+  MOZ_ASSERT(a3rdPartyTrackingWindow);
+
+  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> parentPrincipal;
+  nsAutoCString trackingOrigin;
+  if (!GetParentPrincipalAndTrackingOrigin(a3rdPartyTrackingWindow,
+                                           getter_AddRefs(parentPrincipal),
+                                           trackingOrigin)) {
+    return;
+  }
+
+  NS_ConvertUTF16toUTF8 grantedOrigin(aOrigin);
+
+  if (XRE_IsParentProcess()) {
+    SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(parentPrincipal,
+                                                               trackingOrigin,
+                                                               grantedOrigin);
+    return;
+  }
+
+  ContentChild* cc = ContentChild::GetSingleton();
+  MOZ_ASSERT(cc);
+
+  // This is not really secure, because here we have the content process sending
+  // the request of storing a permission.
+  Unused << cc->SendFirstPartyStorageAccessGrantedForOrigin(IPC::Principal(parentPrincipal),
+                                                            trackingOrigin,
+                                                            grantedOrigin);
+}
+
+/* static */ void
+AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aParentPrincipal,
+                                                                               const nsCString& aTrackingOrigin,
+                                                                               const nsCString& aGrantedOrigin)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (NS_WARN_IF(!aParentPrincipal)) {
+    // The child process is sending something wrong. Let's ignore it.
+    return;
+  }
+
+  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
+  if (NS_WARN_IF(!pm)) {
+    return;
+  }
+
+  int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + ANTITRACKING_EXPIRATION;
+
+  nsAutoCString type;
+  CreatePermissionKey(aTrackingOrigin, aGrantedOrigin, type);
+
+  nsresult rv = pm->AddFromPrincipal(aParentPrincipal, type.get(),
+                                     nsIPermissionManager::ALLOW_ACTION,
+                                     nsIPermissionManager::EXPIRE_TIME, when);
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+}
+
+bool
+AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
+                                                        nsIURI* aURI)
+{
+  MOZ_ASSERT(a3rdPartyTrackingWindow);
+  MOZ_ASSERT(aURI);
+
+  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+    return true;
+  }
+
+  if (!nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow,
+                                                   nullptr, nullptr) ||
+      !nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrincipal> parentPrincipal;
+  nsAutoCString trackingOrigin;
+  if (!GetParentPrincipalAndTrackingOrigin(a3rdPartyTrackingWindow,
+                                           getter_AddRefs(parentPrincipal),
+                                           trackingOrigin)) {
+    return false;
+  }
+
+  nsAutoString origin;
+  nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  nsAutoCString type;
+  CreatePermissionKey(trackingOrigin, NS_ConvertUTF16toUTF8(origin), type);
+
+  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
+  if (NS_WARN_IF(!pm)) {
+    return false;
+  }
+
+  uint32_t result = 0;
+  rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  return result == nsIPermissionManager::ALLOW_ACTION;
+}
+
+bool
+AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel,
+                                                        nsIURI* aURI)
+{
+  MOZ_ASSERT(aURI);
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(aChannel->GetIsTrackingResource());
+
+#ifdef DEBUG
+  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
+  bool is3rdPartyContext = false;
+  thirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &is3rdPartyContext);
+  MOZ_ASSERT(is3rdPartyContext);
+#endif
+
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+  if (!loadInfo) {
+    return true;
+  }
+
+  nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal();
+  if (NS_WARN_IF(!parentPrincipal)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIURI> trackingURI;
+  nsresult rv = aChannel->GetURI(getter_AddRefs(trackingURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return true;
+  }
+
+  nsAutoString trackingOrigin;
+  rv = nsContentUtils::GetUTFOrigin(trackingURI, trackingOrigin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  nsAutoString origin;
+  rv = nsContentUtils::GetUTFOrigin(aURI, origin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  nsAutoCString type;
+  CreatePermissionKey(NS_ConvertUTF16toUTF8(trackingOrigin),
+                      NS_ConvertUTF16toUTF8(origin), type);
+
+  nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
+  if (NS_WARN_IF(!pm)) {
+    return false;
+  }
+
+  uint32_t result = 0;
+  rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  return result == nsIPermissionManager::ALLOW_ACTION;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/AntiTrackingCommon.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_antitrackingservice_h
+#define mozilla_antitrackingservice_h
+
+#include "nsString.h"
+
+class nsIHttpChannel;
+class nsIPrincipal;
+class nsIURI;
+class nsPIDOMWindowInner;
+
+namespace mozilla {
+
+class AntiTrackingCommon final
+{
+public:
+  // This method returns true if the URI has first party storage access when
+  // loaded inside the passed 3rd party context tracking resource window.
+  static bool
+  IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
+                                      nsIURI* aURI);
+
+  // This can be called only if the a3rdPartyTrackingChannel is _really_ a 3rd
+  // party context and marked as tracking resource.
+  // It returns true if the URI has access to the first party storage.
+  static bool
+  IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* a3rdPartyTrackingChannel,
+                                      nsIURI* aURI);
+
+  // Grant the permission for aOrigin to have access to the first party storage
+  // when loaded in that particular 3rd party context.
+  static void
+  AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
+                                       nsPIDOMWindowInner* a3rdPartyTrackingWindow);
+
+  // For IPC only.
+  static void
+  SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
+                                                             const nsCString& aParentOrigin,
+                                                             const nsCString& aGrantedOrigin);
+
+};
+
+} // namespace mozilla
+
+#endif // mozilla_antitrackingservice_h
--- a/toolkit/components/antitracking/moz.build
+++ b/toolkit/components/antitracking/moz.build
@@ -2,9 +2,21 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'DOM: Security')
 
+EXPORTS.mozilla = [
+    'AntiTrackingCommon.h',
+]
+
+UNIFIED_SOURCES += [
+    'AntiTrackingCommon.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']