Bug 1551055 - StoragePrincipal should be supported by localStorage - part 1, r=asuth
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 14 May 2019 05:49:46 +0000
changeset 532556 386a0b72c793860f7b40fdf7383b7a9078f02091
parent 532555 aa14d710b4ccd7ff72693f988c006aff700b9183
child 532557 df4c74e2ecf7f94ea48cb16896d0be1e6c675ae4
push id11270
push userrgurzau@mozilla.com
push dateWed, 15 May 2019 15:07:19 +0000
treeherdermozilla-beta@571bc76da583 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1551055
milestone68.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 1551055 - StoragePrincipal should be supported by localStorage - part 1, r=asuth Differential Revision: https://phabricator.services.mozilla.com/D30801
dom/base/nsGlobalWindowInner.cpp
dom/interfaces/storage/nsIDOMStorageManager.idl
dom/localstorage/ActorsParent.cpp
dom/localstorage/LSObject.cpp
dom/localstorage/LSObject.h
dom/localstorage/LocalStorageManager2.cpp
dom/localstorage/PBackgroundLSSharedTypes.ipdlh
dom/localstorage/test/unit/head.js
dom/quota/test/unit/test_localStorageArchive4upgrade.js
dom/storage/LocalStorage.cpp
dom/storage/LocalStorage.h
dom/storage/LocalStorageManager.cpp
dom/storage/LocalStorageManager.h
dom/storage/PartitionedLocalStorage.cpp
dom/storage/PartitionedLocalStorage.h
dom/storage/SessionStorage.cpp
dom/storage/SessionStorageManager.cpp
dom/storage/Storage.cpp
dom/storage/Storage.h
dom/storage/StorageNotifierService.cpp
dom/storage/StorageNotifierService.h
dom/tests/browser/browser_localStorage_e10s.js
dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
toolkit/components/extensions/Extension.jsm
toolkit/components/sessionstore/SessionStoreUtils.cpp
toolkit/components/windowwatcher/nsWindowWatcher.cpp
toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -384,18 +384,18 @@ class nsGlobalWindowObserver final : pub
                                   const char16_t* aStorageType,
                                   bool aPrivateBrowsing) override {
     if (mWindow) {
       mWindow->ObserveStorageNotification(aEvent, aStorageType,
                                           aPrivateBrowsing);
     }
   }
 
-  nsIPrincipal* GetPrincipal() const override {
-    return mWindow ? mWindow->GetPrincipal() : nullptr;
+  nsIPrincipal* GetEffectiveStoragePrincipal() const override {
+    return mWindow ? mWindow->GetEffectiveStoragePrincipal() : nullptr;
   }
 
   bool IsPrivateBrowsing() const override {
     return mWindow ? mWindow->IsPrivateBrowsing() : false;
   }
 
   nsIEventTarget* GetEventTarget() const override {
     return mWindow ? mWindow->EventTargetFor(TaskCategory::Other) : nullptr;
@@ -4349,18 +4349,19 @@ Storage* nsGlobalWindowInner::GetSession
     nsCOMPtr<nsIDOMStorageManager> storageManager =
         do_QueryInterface(docShell, &rv);
     if (NS_FAILED(rv)) {
       aError.Throw(rv);
       return nullptr;
     }
 
     RefPtr<Storage> storage;
-    aError = storageManager->CreateStorage(this, principal, documentURI,
-                                           IsPrivateBrowsing(),
+    // No StoragePrincipal for sessions.
+    aError = storageManager->CreateStorage(this, principal, principal,
+                                           documentURI, IsPrivateBrowsing(),
                                            getter_AddRefs(storage));
     if (aError.Failed()) {
       return nullptr;
     }
 
     mSessionStorage = storage;
     MOZ_ASSERT(mSessionStorage);
 
@@ -4401,17 +4402,17 @@ Storage* nsGlobalWindowInner::GetLocalSt
 
   nsContentUtils::StorageAccess access =
       nsContentUtils::StorageAllowedForWindow(this);
 
   // We allow partitioned localStorage only to some hosts.
   if (access == nsContentUtils::StorageAccess::ePartitionedOrDeny) {
     if (!mDoc) {
       access = nsContentUtils::StorageAccess::eDeny;
-    } else {
+    } else if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
       nsCOMPtr<nsIURI> uri;
       Unused << mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
       static const char* kPrefName =
           "privacy.restrict3rdpartystorage.partitionedHosts";
       if (!uri || !nsContentUtils::IsURIInPrefList(uri, kPrefName)) {
         access = nsContentUtils::StorageAccess::eDeny;
       }
     }
@@ -4427,17 +4428,18 @@ Storage* nsGlobalWindowInner::GetLocalSt
     }
     return nullptr;
   }
 
   // Note that this behavior is observable: if we grant storage permission to a
   // tracker, we pass from the partitioned LocalStorage to the 'normal'
   // LocalStorage. The previous data is lost and the 2 window.localStorage
   // objects, before and after the permission granted, will be different.
-  if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny &&
+  if ((StaticPrefs::privacy_storagePrincipal_enabledForTrackers() ||
+       access != nsContentUtils::StorageAccess::ePartitionedOrDeny) &&
       (!mLocalStorage ||
        mLocalStorage->Type() == Storage::ePartitionedLocalStorage)) {
     RefPtr<Storage> storage;
 
     if (NextGenLocalStorageEnabled()) {
       aError = LSObject::CreateForWindow(this, getter_AddRefs(storage));
     } else {
       nsresult rv;
@@ -4457,18 +4459,24 @@ Storage* nsGlobalWindowInner::GetLocalSt
       }
 
       nsIPrincipal* principal = GetPrincipal();
       if (!principal) {
         aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
         return nullptr;
       }
 
-      aError = storageManager->CreateStorage(this, principal, documentURI,
-                                             IsPrivateBrowsing(),
+      nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
+      if (!storagePrincipal) {
+        aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
+        return nullptr;
+      }
+
+      aError = storageManager->CreateStorage(this, principal, storagePrincipal,
+                                             documentURI, IsPrivateBrowsing(),
                                              getter_AddRefs(storage));
     }
 
     if (aError.Failed()) {
       return nullptr;
     }
 
     mLocalStorage = storage;
@@ -4478,21 +4486,30 @@ Storage* nsGlobalWindowInner::GetLocalSt
   if (access == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
       !mLocalStorage) {
     nsIPrincipal* principal = GetPrincipal();
     if (!principal) {
       aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
       return nullptr;
     }
 
-    mLocalStorage = new PartitionedLocalStorage(this, principal);
-  }
-
-  MOZ_ASSERT((access == nsContentUtils::StorageAccess::ePartitionedOrDeny) ==
-             (mLocalStorage->Type() == Storage::ePartitionedLocalStorage));
+    nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
+    if (!storagePrincipal) {
+      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
+      return nullptr;
+    }
+
+    mLocalStorage =
+        new PartitionedLocalStorage(this, principal, storagePrincipal);
+  }
+
+  MOZ_ASSERT_IF(
+      !StaticPrefs::privacy_storagePrincipal_enabledForTrackers(),
+      (access == nsContentUtils::StorageAccess::ePartitionedOrDeny) ==
+          (mLocalStorage->Type() == Storage::ePartitionedLocalStorage));
 
   return mLocalStorage;
 }
 
 IDBFactory* nsGlobalWindowInner::GetIndexedDB(ErrorResult& aError) {
   if (!mIndexedDB) {
     // This may keep mIndexedDB null without setting an error.
     aError = IDBFactory::CreateForWindow(this, getter_AddRefs(mIndexedDB));
@@ -4869,16 +4886,21 @@ void nsGlobalWindowInner::ObserveStorage
     return;
   }
 
   nsIPrincipal* principal = GetPrincipal();
   if (!principal) {
     return;
   }
 
+  nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
+  if (!storagePrincipal) {
+    return;
+  }
+
   bool fireMozStorageChanged = false;
   nsAutoString eventType;
   eventType.AssignLiteral("storage");
 
   if (!NS_strcmp(aStorageType, u"sessionStorage")) {
     RefPtr<Storage> changingStorage = aEvent->GetStorageArea();
     MOZ_ASSERT(changingStorage);
 
@@ -4909,18 +4931,18 @@ void nsGlobalWindowInner::ObserveStorage
     if (fireMozStorageChanged) {
       eventType.AssignLiteral("MozSessionStorageChanged");
     }
   }
 
   else {
     MOZ_ASSERT(!NS_strcmp(aStorageType, u"localStorage"));
 
-    MOZ_DIAGNOSTIC_ASSERT(
-        StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(), principal));
+    MOZ_DIAGNOSTIC_ASSERT(StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(),
+                                                        storagePrincipal));
 
     fireMozStorageChanged =
         mLocalStorage && mLocalStorage == aEvent->GetStorageArea();
 
     if (fireMozStorageChanged) {
       eventType.AssignLiteral("MozLocalStorageChanged");
     }
   }
--- a/dom/interfaces/storage/nsIDOMStorageManager.idl
+++ b/dom/interfaces/storage/nsIDOMStorageManager.idl
@@ -34,23 +34,26 @@ interface nsIDOMStorageManager : nsISupp
    * Returns instance of DOM storage object for given principal.
    * A new object is always returned and it is ensured there is
    * a storage for the scope created.
    *
    * @param aWindow
    *    The parent window.
    * @param aPrincipal
    *    Principal to bound storage to.
+   * @param aStoragePrincipal
+   *    StoragePrincipal to bound storage to.
    * @param aDocumentURI
    *    URL of the demanding document, used for DOM storage event only.
    * @param aPrivate
    *    Whether the demanding document is running in Private Browsing mode or not.
    */
   Storage createStorage(in mozIDOMWindow aWindow,
                         in nsIPrincipal aPrincipal,
+                        in nsIPrincipal aStoragePrincipal,
                         in AString aDocumentURI,
                         [optional] in bool aPrivate);
   /**
    * DEPRECATED.  The only good reason to use this was if you were writing a
    * test and wanted to hackily determine if a preload happened.  That's now
    * covered by `nsILocalStorageManager.isPreloaded` and you should use that if
    * that's what you want.  If LSNG is in use, this will throw.
    *
@@ -58,21 +61,24 @@ interface nsIDOMStorageManager : nsISupp
    * If there is no storage managed for the scope, then null is returned and
    * no object is created.  Otherwise, an object (new) for the existing storage
    * scope is returned.
    *
    * @param aWindow
    *    The parent window.
    * @param aPrincipal
    *    Principal to bound storage to.
+   * @param aStoragePrincipal
+   *    StoragePrincipal to bound storage to.
    * @param aPrivate
    *    Whether the demanding document is running in Private Browsing mode or not.
    */
   Storage getStorage(in mozIDOMWindow aWindow,
                      in nsIPrincipal aPrincipal,
+                     in nsIPrincipal aStoragePrincipal,
                      [optional] in bool aPrivate);
 
   /**
    * Clones given storage into this storage manager.
    *
    * @param aStorageToCloneFrom
    *    The storage to copy all items from into this manager.  Manager will then
    *    return a new and independent object that contains snapshot of data from
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -6599,25 +6599,26 @@ nsresult PrepareDatastoreOp::Open() {
   MOZ_ASSERT(mState == State::Opening);
   MOZ_ASSERT(mNestedState == NestedState::BeforeNesting);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceedOnNonOwningThread()) {
     return NS_ERROR_FAILURE;
   }
 
-  const PrincipalInfo& principalInfo = mParams.principalInfo();
-
-  if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+
+  if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin);
   } else {
-    MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
+    MOZ_ASSERT(storagePrincipalInfo.type() ==
+               PrincipalInfo::TContentPrincipalInfo);
 
     QuotaManager::GetInfoFromValidatedPrincipalInfo(
-        principalInfo, &mSuffix, &mGroup, &mMainThreadOrigin);
+        storagePrincipalInfo, &mSuffix, &mGroup, &mMainThreadOrigin);
   }
 
   mState = State::Nesting;
   mNestedState = NestedState::CheckExistingOperations;
 
   MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
 
   return NS_OK;
@@ -6629,27 +6630,29 @@ nsresult PrepareDatastoreOp::CheckExisti
   MOZ_ASSERT(mNestedState == NestedState::CheckExistingOperations);
   MOZ_ASSERT(gPrepareDatastoreOps);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceed()) {
     return NS_ERROR_FAILURE;
   }
 
-  const PrincipalInfo& principalInfo = mParams.principalInfo();
+  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
 
   nsCString originAttrSuffix;
   uint32_t privateBrowsingId;
 
-  if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+  if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     privateBrowsingId = 0;
   } else {
-    MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
-
-    const ContentPrincipalInfo& info = principalInfo.get_ContentPrincipalInfo();
+    MOZ_ASSERT(storagePrincipalInfo.type() ==
+               PrincipalInfo::TContentPrincipalInfo);
+
+    const ContentPrincipalInfo& info =
+        storagePrincipalInfo.get_ContentPrincipalInfo();
     const OriginAttributes& attrs = info.attrs();
     attrs.CreateSuffix(originAttrSuffix);
 
     privateBrowsingId = attrs.mPrivateBrowsingId;
   }
 
   mArchivedOriginScope = ArchivedOriginScope::CreateFromOrigin(
       originAttrSuffix, mParams.originKey());
@@ -7905,25 +7908,26 @@ nsresult PrepareObserverOp::Open() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::Opening);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceedOnNonOwningThread()) {
     return NS_ERROR_FAILURE;
   }
 
-  const PrincipalInfo& principalInfo = mParams.principalInfo();
-
-  if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+
+  if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(nullptr, nullptr, &mOrigin);
   } else {
-    MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
-
-    QuotaManager::GetInfoFromValidatedPrincipalInfo(principalInfo, nullptr,
-                                                    nullptr, &mOrigin);
+    MOZ_ASSERT(storagePrincipalInfo.type() ==
+               PrincipalInfo::TContentPrincipalInfo);
+
+    QuotaManager::GetInfoFromValidatedPrincipalInfo(storagePrincipalInfo,
+                                                    nullptr, nullptr, &mOrigin);
   }
 
   mState = State::SendingReadyMessage;
   MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
 
   return NS_OK;
 }
 
@@ -8046,25 +8050,26 @@ nsresult PreloadedOp::Open() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::Opening);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
       !MayProceedOnNonOwningThread()) {
     return NS_ERROR_FAILURE;
   }
 
-  const PrincipalInfo& principalInfo = mParams.principalInfo();
-
-  if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+  const PrincipalInfo& storagePrincipalInfo = mParams.storagePrincipalInfo();
+
+  if (storagePrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(nullptr, nullptr, &mOrigin);
   } else {
-    MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
-
-    QuotaManager::GetInfoFromValidatedPrincipalInfo(principalInfo, nullptr,
-                                                    nullptr, &mOrigin);
+    MOZ_ASSERT(storagePrincipalInfo.type() ==
+               PrincipalInfo::TContentPrincipalInfo);
+
+    QuotaManager::GetInfoFromValidatedPrincipalInfo(storagePrincipalInfo,
+                                                    nullptr, nullptr, &mOrigin);
   }
 
   mState = State::SendingResults;
   MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
 
   return NS_OK;
 }
 
@@ -8965,21 +8970,21 @@ nsresult QuotaClient::CreateArchivedOrig
                                               &attrs))) {
       return NS_ERROR_FAILURE;
     }
 
     ContentPrincipalInfo contentPrincipalInfo;
     contentPrincipalInfo.attrs() = attrs;
     contentPrincipalInfo.spec() = spec;
 
-    PrincipalInfo principalInfo(contentPrincipalInfo);
+    PrincipalInfo storagePrincipalInfo(contentPrincipalInfo);
 
     nsCString originAttrSuffix;
     nsCString originKey;
-    rv = GenerateOriginKey2(principalInfo, originAttrSuffix, originKey);
+    rv = GenerateOriginKey2(storagePrincipalInfo, originAttrSuffix, originKey);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     archivedOriginScope =
         ArchivedOriginScope::CreateFromOrigin(originAttrSuffix, originKey);
   } else if (aOriginScope.IsPrefix()) {
     nsCString spec;
@@ -8988,21 +8993,21 @@ nsresult QuotaClient::CreateArchivedOrig
                                               spec, &attrs))) {
       return NS_ERROR_FAILURE;
     }
 
     ContentPrincipalInfo contentPrincipalInfo;
     contentPrincipalInfo.attrs() = attrs;
     contentPrincipalInfo.spec() = spec;
 
-    PrincipalInfo principalInfo(contentPrincipalInfo);
+    PrincipalInfo storagePrincipalInfo(contentPrincipalInfo);
 
     nsCString originAttrSuffix;
     nsCString originKey;
-    rv = GenerateOriginKey2(principalInfo, originAttrSuffix, originKey);
+    rv = GenerateOriginKey2(storagePrincipalInfo, originAttrSuffix, originKey);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     archivedOriginScope = ArchivedOriginScope::CreateFromPrefix(originKey);
   } else if (aOriginScope.IsPattern()) {
     archivedOriginScope =
         ArchivedOriginScope::CreateFromPattern(aOriginScope.GetPattern());
--- a/dom/localstorage/LSObject.cpp
+++ b/dom/localstorage/LSObject.cpp
@@ -190,18 +190,19 @@ class RequestHelper final : public Runna
   NS_DECL_NSIRUNNABLE
 
   // LSRequestChildCallback
   void OnResponse(const LSRequestResponse& aResponse) override;
 };
 
 }  // namespace
 
-LSObject::LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
-    : Storage(aWindow, aPrincipal),
+LSObject::LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+                   nsIPrincipal* aStoragePrincipal)
+    : Storage(aWindow, aPrincipal, aStoragePrincipal),
       mPrivateBrowsingId(0),
       mInExplicitSnapshot(false) {
   AssertIsOnOwningThread();
   MOZ_ASSERT(NextGenLocalStorageEnabled());
 }
 
 LSObject::~LSObject() {
   AssertIsOnOwningThread();
@@ -239,64 +240,80 @@ void LSObject::Initialize() {
 
 // static
 nsresult LSObject::CreateForWindow(nsPIDOMWindowInner* aWindow,
                                    Storage** aStorage) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aStorage);
   MOZ_ASSERT(NextGenLocalStorageEnabled());
-  MOZ_ASSERT(nsContentUtils::StorageAllowedForWindow(aWindow) >
+  MOZ_ASSERT(nsContentUtils::StorageAllowedForWindow(aWindow) !=
              nsContentUtils::StorageAccess::eDeny);
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
   MOZ_ASSERT(sop);
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   if (NS_WARN_IF(!principal)) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIPrincipal> storagePrincipal = sop->GetEffectiveStoragePrincipal();
+  if (NS_WARN_IF(!storagePrincipal)) {
+    return NS_ERROR_FAILURE;
+  }
+
   if (nsContentUtils::IsSystemPrincipal(principal)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // localStorage is not available on some pages on purpose, for example
   // about:home. Match the old implementation by using GenerateOriginKey
   // for the check.
   nsCString originAttrSuffix;
   nsCString originKey;
-  nsresult rv = GenerateOriginKey(principal, originAttrSuffix, originKey);
+  nsresult rv =
+      GenerateOriginKey(storagePrincipal, originAttrSuffix, originKey);
   if (NS_FAILED(rv)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
   rv = PrincipalToPrincipalInfo(principal, principalInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo);
 
-  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo))) {
+  nsAutoPtr<PrincipalInfo> storagePrincipalInfo(new PrincipalInfo());
+  rv = PrincipalToPrincipalInfo(storagePrincipal, storagePrincipalInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  MOZ_ASSERT(storagePrincipalInfo->type() ==
+             PrincipalInfo::TContentPrincipalInfo);
+
+  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*storagePrincipalInfo))) {
     return NS_ERROR_FAILURE;
   }
 
   nsCString suffix;
   nsCString origin;
-  rv = QuotaManager::GetInfoFromPrincipal(principal, &suffix, nullptr, &origin);
+  rv = QuotaManager::GetInfoFromPrincipal(storagePrincipal, &suffix, nullptr,
+                                          &origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(originAttrSuffix == suffix);
 
   uint32_t privateBrowsingId;
-  rv = principal->GetPrivateBrowsingId(&privateBrowsingId);
+  rv = storagePrincipal->GetPrivateBrowsingId(&privateBrowsingId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   Maybe<ClientInfo> clientInfo = aWindow->GetClientInfo();
   if (clientInfo.isNothing()) {
     return NS_ERROR_FAILURE;
   }
@@ -306,61 +323,75 @@ nsresult LSObject::CreateForWindow(nsPID
   nsString documentURI;
   if (nsCOMPtr<Document> doc = aWindow->GetExtantDoc()) {
     rv = doc->GetDocumentURI(documentURI);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  RefPtr<LSObject> object = new LSObject(aWindow, principal);
+  RefPtr<LSObject> object = new LSObject(aWindow, principal, storagePrincipal);
   object->mPrincipalInfo = std::move(principalInfo);
+  object->mStoragePrincipalInfo = std::move(storagePrincipalInfo);
   object->mPrivateBrowsingId = privateBrowsingId;
   object->mClientId = clientId;
   object->mOrigin = origin;
   object->mOriginKey = originKey;
   object->mDocumentURI = documentURI;
 
   object.forget(aStorage);
   return NS_OK;
 }
 
 // static
 nsresult LSObject::CreateForPrincipal(nsPIDOMWindowInner* aWindow,
                                       nsIPrincipal* aPrincipal,
+                                      nsIPrincipal* aStoragePrincipal,
                                       const nsAString& aDocumentURI,
                                       bool aPrivate, LSObject** aObject) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(aStoragePrincipal);
   MOZ_ASSERT(aObject);
 
   nsCString originAttrSuffix;
   nsCString originKey;
-  nsresult rv = GenerateOriginKey(aPrincipal, originAttrSuffix, originKey);
+  nsresult rv =
+      GenerateOriginKey(aStoragePrincipal, originAttrSuffix, originKey);
   if (NS_FAILED(rv)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
   rv = PrincipalToPrincipalInfo(aPrincipal, principalInfo);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
              principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
 
-  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo))) {
+  nsAutoPtr<PrincipalInfo> storagePrincipalInfo(new PrincipalInfo());
+  rv = PrincipalToPrincipalInfo(aStoragePrincipal, storagePrincipalInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  MOZ_ASSERT(
+      storagePrincipalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
+      storagePrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
+
+  if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*storagePrincipalInfo))) {
     return NS_ERROR_FAILURE;
   }
 
   nsCString suffix;
   nsCString origin;
 
-  if (principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo) {
+  if (storagePrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo) {
     QuotaManager::GetInfoForChrome(&suffix, nullptr, &origin);
   } else {
     rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &suffix, nullptr,
                                             &origin);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
@@ -372,18 +403,20 @@ nsresult LSObject::CreateForPrincipal(ns
     Maybe<ClientInfo> clientInfo = aWindow->GetClientInfo();
     if (clientInfo.isNothing()) {
       return NS_ERROR_FAILURE;
     }
 
     clientId = Some(clientInfo.ref().Id());
   }
 
-  RefPtr<LSObject> object = new LSObject(aWindow, aPrincipal);
+  RefPtr<LSObject> object =
+      new LSObject(aWindow, aPrincipal, aStoragePrincipal);
   object->mPrincipalInfo = std::move(principalInfo);
+  object->mStoragePrincipalInfo = std::move(storagePrincipalInfo);
   object->mPrivateBrowsingId = aPrivate ? 1 : 0;
   object->mClientId = clientId;
   object->mOrigin = origin;
   object->mOriginKey = originKey;
   object->mDocumentURI = aDocumentURI;
 
   object.forget(aObject);
   return NS_OK;
@@ -806,16 +839,17 @@ nsresult LSObject::EnsureDatabase() {
   PBackgroundChild* backgroundActor =
       BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!backgroundActor)) {
     return NS_ERROR_FAILURE;
   }
 
   LSRequestCommonParams commonParams;
   commonParams.principalInfo() = *mPrincipalInfo;
+  commonParams.storagePrincipalInfo() = *mStoragePrincipalInfo;
   commonParams.originKey() = mOriginKey;
 
   LSRequestPrepareDatastoreParams params;
   params.commonParams() = commonParams;
   params.clientId() = mClientId;
 
   LSRequestResponse response;
 
@@ -839,17 +873,17 @@ nsresult LSObject::EnsureDatabase() {
   // Note that we now can't error out, otherwise parent will keep an extra
   // strong reference to the datastore.
 
   RefPtr<LSDatabase> database = new LSDatabase(mOrigin);
 
   LSDatabaseChild* actor = new LSDatabaseChild(database);
 
   MOZ_ALWAYS_TRUE(backgroundActor->SendPBackgroundLSDatabaseConstructor(
-      actor, *mPrincipalInfo, mPrivateBrowsingId, datastoreId));
+      actor, *mStoragePrincipalInfo, mPrivateBrowsingId, datastoreId));
 
   database->SetActor(actor);
 
   mDatabase = std::move(database);
 
   return NS_OK;
 }
 
@@ -874,16 +908,17 @@ nsresult LSObject::EnsureObserver() {
   mObserver = LSObserver::Get(mOrigin);
 
   if (mObserver) {
     return NS_OK;
   }
 
   LSRequestPrepareObserverParams params;
   params.principalInfo() = *mPrincipalInfo;
+  params.storagePrincipalInfo() = *mStoragePrincipalInfo;
   params.clientId() = mClientId;
 
   LSRequestResponse response;
 
   nsresult rv = DoRequestSynchronously(params, response);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -927,18 +962,18 @@ void LSObject::DropObserver() {
     mObserver = nullptr;
   }
 }
 
 void LSObject::OnChange(const nsAString& aKey, const nsAString& aOldValue,
                         const nsAString& aNewValue) {
   AssertIsOnOwningThread();
 
-  NotifyChange(/* aStorage */ this, Principal(), aKey, aOldValue, aNewValue,
-               /* aStorageType */ kLocalStorageType, mDocumentURI,
+  NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey, aOldValue,
+               aNewValue, /* aStorageType */ kLocalStorageType, mDocumentURI,
                /* aIsPrivate */ !!mPrivateBrowsingId,
                /* aImmediateDispatch */ false);
 }
 
 nsresult LSObject::EndExplicitSnapshotInternal() {
   AssertIsOnOwningThread();
 
   // Can be only called if the mInExplicitSnapshot flag is true.
--- a/dom/localstorage/LSObject.h
+++ b/dom/localstorage/LSObject.h
@@ -56,16 +56,17 @@ class LSRequestResponse;
  * parent Datastore at the moment the Snapshot was created.
  */
 class LSObject final : public Storage {
   typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
 
   friend nsGlobalWindowInner;
 
   nsAutoPtr<PrincipalInfo> mPrincipalInfo;
+  nsAutoPtr<PrincipalInfo> mStoragePrincipalInfo;
 
   RefPtr<LSDatabase> mDatabase;
   RefPtr<LSObserver> mObserver;
 
   uint32_t mPrivateBrowsingId;
   Maybe<nsID> mClientId;
   nsCString mOrigin;
   nsCString mOriginKey;
@@ -87,16 +88,17 @@ class LSObject final : public Storage {
    * system principal where CreateForWindow does not.  This is also why aPrivate
    * exists separate from the principal; because the system principal can never
    * be mutated to have a private browsing id even though it can be used in a
    * window/document marked as private browsing.  That's a legacy issue that is
    * being dealt with, but it's why it exists here.
    */
   static nsresult CreateForPrincipal(nsPIDOMWindowInner* aWindow,
                                      nsIPrincipal* aPrincipal,
+                                     nsIPrincipal* aStoragePrincipal,
                                      const nsAString& aDocumentURI,
                                      bool aPrivate, LSObject** aObject);
 
   /**
    * Used for requests from the parent process to the parent process; in that
    * case we want ActorsParent to know our event-target and this is better than
    * trying to tunnel the pointer through IPC.
    */
@@ -172,17 +174,18 @@ class LSObject final : public Storage {
                            ErrorResult& aError) override;
 
   //////////////////////////////////////////////////////////////////////////////
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LSObject, Storage)
 
  private:
-  LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal);
+  LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+           nsIPrincipal* aStoragePrincipal);
 
   ~LSObject();
 
   nsresult DoRequestSynchronously(const LSRequestParams& aParams,
                                   LSRequestResponse& aResponse);
 
   nsresult EnsureDatabase();
 
--- a/dom/localstorage/LocalStorageManager2.cpp
+++ b/dom/localstorage/LocalStorageManager2.cpp
@@ -186,41 +186,46 @@ LocalStorageManager2::PrecacheStorage(ns
   // process, triggered by the official preloading spot,
   // ContentParent::AboutToLoadHttpFtpDocumentForChild.
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 LocalStorageManager2::CreateStorage(mozIDOMWindow* aWindow,
                                     nsIPrincipal* aPrincipal,
+                                    nsIPrincipal* aStoragePrincipal,
                                     const nsAString& aDocumentURI,
                                     bool aPrivate, Storage** _retval) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(aStoragePrincipal);
   MOZ_ASSERT(_retval);
 
   nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
 
   RefPtr<LSObject> object;
-  nsresult rv = LSObject::CreateForPrincipal(inner, aPrincipal, aDocumentURI,
+  nsresult rv = LSObject::CreateForPrincipal(inner, aPrincipal,
+                                             aStoragePrincipal, aDocumentURI,
                                              aPrivate, getter_AddRefs(object));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   object.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocalStorageManager2::GetStorage(mozIDOMWindow* aWindow,
-                                 nsIPrincipal* aPrincipal, bool aPrivate,
+                                 nsIPrincipal* aPrincipal,
+                                 nsIPrincipal* aStoragePrincipal, bool aPrivate,
                                  Storage** _retval) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(aStoragePrincipal);
   MOZ_ASSERT(_retval);
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 LocalStorageManager2::CloneStorage(Storage* aStorageToCloneFrom) {
   MOZ_ASSERT(NS_IsMainThread());
@@ -278,16 +283,17 @@ LocalStorageManager2::Preload(nsIPrincip
     rv = CreatePromise(aContext, getter_AddRefs(promise));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   LSRequestCommonParams commonParams;
   commonParams.principalInfo() = *principalInfo;
+  commonParams.storagePrincipalInfo() = *principalInfo;
   commonParams.originKey() = originKey;
 
   LSRequestPreloadDatastoreParams params(commonParams);
 
   RefPtr<AsyncRequestHelper> helper =
       new AsyncRequestHelper(this, promise, params);
 
   // This will start and finish the async request on the DOM File thread.
@@ -324,16 +330,18 @@ LocalStorageManager2::IsPreloaded(nsIPri
 
   LSSimpleRequestPreloadedParams params;
 
   rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  params.storagePrincipalInfo() = params.principalInfo();
+
   rv = StartSimpleRequest(promise, params);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   promise.forget(_retval);
   return NS_OK;
 }
--- a/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
+++ b/dom/localstorage/PBackgroundLSSharedTypes.ipdlh
@@ -11,16 +11,17 @@ using mozilla::dom::LSValue
   from "mozilla/dom/LSValue.h";
 
 namespace mozilla {
 namespace dom {
 
 struct LSRequestCommonParams
 {
   PrincipalInfo principalInfo;
+  PrincipalInfo storagePrincipalInfo;
   nsCString originKey;
 };
 
 struct LSRequestPreloadDatastoreParams
 {
   LSRequestCommonParams commonParams;
 };
 
@@ -28,29 +29,31 @@ struct LSRequestPrepareDatastoreParams
 {
   LSRequestCommonParams commonParams;
   nsID? clientId;
 };
 
 struct LSRequestPrepareObserverParams
 {
   PrincipalInfo principalInfo;
+  PrincipalInfo storagePrincipalInfo;
   nsID? clientId;
 };
 
 union LSRequestParams
 {
   LSRequestPreloadDatastoreParams;
   LSRequestPrepareDatastoreParams;
   LSRequestPrepareObserverParams;
 };
 
 struct LSSimpleRequestPreloadedParams
 {
   PrincipalInfo principalInfo;
+  PrincipalInfo storagePrincipalInfo;
 };
 
 union LSSimpleRequestParams
 {
   LSSimpleRequestPreloadedParams;
 };
 
 /**
--- a/dom/localstorage/test/unit/head.js
+++ b/dom/localstorage/test/unit/head.js
@@ -227,17 +227,17 @@ function getCurrentPrincipal() {
   return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
 }
 
 function getLocalStorage(principal) {
   if (!principal) {
     principal = getCurrentPrincipal();
   }
 
-  return Services.domStorageManager.createStorage(null, principal, "");
+  return Services.domStorageManager.createStorage(null, principal, principal, "");
 }
 
 function requestFinished(request) {
   return new Promise(function(resolve, reject) {
     request.callback = function(requestInner) {
       if (requestInner.resultCode == Cr.NS_OK) {
         resolve(requestInner.result);
       } else {
--- a/dom/quota/test/unit/test_localStorageArchive4upgrade.js
+++ b/dom/quota/test/unit/test_localStorageArchive4upgrade.js
@@ -24,17 +24,17 @@ async function testSteps() {
 
   const data = [
     { key: "foo0", value: "bar" },
     { key: "foo1", value: "A" },
     { key: "foo2", value: "A".repeat(100) },
   ];
 
   function getLocalStorage(principal) {
-    return Services.domStorageManager.createStorage(null, principal, "");
+    return Services.domStorageManager.createStorage(null, principal, principal, "");
   }
 
   info("Clearing");
 
   let request = clear();
   await requestFinished(request);
 
   info("Installing package");
--- a/dom/storage/LocalStorage.cpp
+++ b/dom/storage/LocalStorage.cpp
@@ -49,18 +49,19 @@ NS_INTERFACE_MAP_END_INHERITING(Storage)
 
 NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
 NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
 
 LocalStorage::LocalStorage(nsPIDOMWindowInner* aWindow,
                            LocalStorageManager* aManager,
                            LocalStorageCache* aCache,
                            const nsAString& aDocumentURI,
-                           nsIPrincipal* aPrincipal, bool aIsPrivate)
-    : Storage(aWindow, aPrincipal),
+                           nsIPrincipal* aPrincipal,
+                           nsIPrincipal* aStoragePrincipal, bool aIsPrivate)
+    : Storage(aWindow, aPrincipal, aStoragePrincipal),
       mManager(aManager),
       mCache(aCache),
       mDocumentURI(aDocumentURI),
       mIsPrivate(aIsPrivate) {
   mCache->Preload();
 }
 
 LocalStorage::~LocalStorage() {}
@@ -158,19 +159,19 @@ void LocalStorage::Clear(nsIPrincipal& a
 
   if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
     OnChange(VoidString(), VoidString(), VoidString());
   }
 }
 
 void LocalStorage::OnChange(const nsAString& aKey, const nsAString& aOldValue,
                             const nsAString& aNewValue) {
-  NotifyChange(/* aStorage */ this, Principal(), aKey, aOldValue, aNewValue,
-               /* aStorageType */ u"localStorage", mDocumentURI, mIsPrivate,
-               /* aImmediateDispatch */ false);
+  NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey, aOldValue,
+               aNewValue, /* aStorageType */ u"localStorage", mDocumentURI,
+               mIsPrivate, /* aImmediateDispatch */ false);
 }
 
 void LocalStorage::ApplyEvent(StorageEvent* aStorageEvent) {
   MOZ_ASSERT(aStorageEvent);
 
   nsAutoString key;
   nsAutoString old;
   nsAutoString value;
--- a/dom/storage/LocalStorage.h
+++ b/dom/storage/LocalStorage.h
@@ -27,17 +27,18 @@ class LocalStorage final : public Storag
   LocalStorageManager* GetManager() const { return mManager; }
 
   LocalStorageCache const* GetCache() const { return mCache; }
 
   const nsString& DocumentURI() const { return mDocumentURI; }
 
   LocalStorage(nsPIDOMWindowInner* aWindow, LocalStorageManager* aManager,
                LocalStorageCache* aCache, const nsAString& aDocumentURI,
-               nsIPrincipal* aPrincipal, bool aIsPrivate);
+               nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal,
+               bool aIsPrivate);
 
   bool IsForkOf(const Storage* aOther) const override;
 
   // WebIDL
 
   int64_t GetOriginQuotaUsage() const override;
 
   uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
--- a/dom/storage/LocalStorageManager.cpp
+++ b/dom/storage/LocalStorageManager.cpp
@@ -193,17 +193,18 @@ void LocalStorageManager::DropCache(Loca
   }
 
   CacheOriginHashtable* table = mCaches.LookupOrAdd(aCache->OriginSuffix());
   table->RemoveEntry(aCache->OriginNoSuffix());
 }
 
 nsresult LocalStorageManager::GetStorageInternal(
     CreateMode aCreateMode, mozIDOMWindow* aWindow, nsIPrincipal* aPrincipal,
-    const nsAString& aDocumentURI, bool aPrivate, Storage** aRetval) {
+    nsIPrincipal* aStoragePrincipal, const nsAString& aDocumentURI,
+    bool aPrivate, Storage** aRetval) {
   nsAutoCString originAttrSuffix;
   nsAutoCString originKey;
 
   nsresult rv = GenerateOriginKey(aPrincipal, originAttrSuffix, originKey);
   if (NS_FAILED(rv)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -265,46 +266,51 @@ nsresult LocalStorageManager::GetStorage
 
     cache->SetActor(actor);
 #endif
   }
 
   if (aRetval) {
     nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
 
-    RefPtr<Storage> storage = new LocalStorage(inner, this, cache, aDocumentURI,
-                                               aPrincipal, aPrivate);
+    RefPtr<Storage> storage =
+        new LocalStorage(inner, this, cache, aDocumentURI, aPrincipal,
+                         aStoragePrincipal, aPrivate);
     storage.forget(aRetval);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocalStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal,
                                      Storage** aRetval) {
   return GetStorageInternal(CreateMode::CreateIfShouldPreload, nullptr,
-                            aPrincipal, EmptyString(), false, aRetval);
+                            aPrincipal, aPrincipal, EmptyString(), false,
+                            aRetval);
 }
 
 NS_IMETHODIMP
 LocalStorageManager::CreateStorage(mozIDOMWindow* aWindow,
                                    nsIPrincipal* aPrincipal,
+                                   nsIPrincipal* aStoragePrincipal,
                                    const nsAString& aDocumentURI, bool aPrivate,
                                    Storage** aRetval) {
   return GetStorageInternal(CreateMode::CreateAlways, aWindow, aPrincipal,
-                            aDocumentURI, aPrivate, aRetval);
+                            aStoragePrincipal, aDocumentURI, aPrivate, aRetval);
 }
 
 NS_IMETHODIMP
 LocalStorageManager::GetStorage(mozIDOMWindow* aWindow,
-                                nsIPrincipal* aPrincipal, bool aPrivate,
+                                nsIPrincipal* aPrincipal,
+                                nsIPrincipal* aStoragePrincipal, bool aPrivate,
                                 Storage** aRetval) {
   return GetStorageInternal(CreateMode::UseIfExistsNeverCreate, aWindow,
-                            aPrincipal, EmptyString(), aPrivate, aRetval);
+                            aPrincipal, aStoragePrincipal, EmptyString(),
+                            aPrivate, aRetval);
 }
 
 NS_IMETHODIMP
 LocalStorageManager::CloneStorage(Storage* aStorage) {
   // Cloning is supported only for sessionStorage
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/dom/storage/LocalStorageManager.h
+++ b/dom/storage/LocalStorageManager.h
@@ -96,16 +96,17 @@ class LocalStorageManager final : public
     CreateAlways,
     // PrecacheStorage: Create only if the database says we ShouldPreloadOrigin.
     CreateIfShouldPreload
   };
 
   // Helper for creation of DOM storage objects
   nsresult GetStorageInternal(CreateMode aCreate, mozIDOMWindow* aWindow,
                               nsIPrincipal* aPrincipal,
+                              nsIPrincipal* aStoragePrincipal,
                               const nsAString& aDocumentURI, bool aPrivate,
                               Storage** aRetval);
 
   // Suffix->origin->cache map
   typedef nsTHashtable<LocalStorageCacheHashKey> CacheOriginHashtable;
   nsClassHashtable<nsCStringHashKey, CacheOriginHashtable> mCaches;
 
   void ClearCaches(uint32_t aUnloadFlags,
--- a/dom/storage/PartitionedLocalStorage.cpp
+++ b/dom/storage/PartitionedLocalStorage.cpp
@@ -15,19 +15,21 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTION_INHERITED(PartitionedLocalStorage, Storage);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PartitionedLocalStorage)
 NS_INTERFACE_MAP_END_INHERITING(Storage)
 
 NS_IMPL_ADDREF_INHERITED(PartitionedLocalStorage, Storage)
 NS_IMPL_RELEASE_INHERITED(PartitionedLocalStorage, Storage)
 
-PartitionedLocalStorage::PartitionedLocalStorage(nsPIDOMWindowInner* aWindow,
-                                                 nsIPrincipal* aPrincipal)
-    : Storage(aWindow, aPrincipal), mCache(new SessionStorageCache()) {}
+PartitionedLocalStorage::PartitionedLocalStorage(
+    nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+    nsIPrincipal* aStoragePrincipal)
+    : Storage(aWindow, aPrincipal, aStoragePrincipal),
+      mCache(new SessionStorageCache()) {}
 
 PartitionedLocalStorage::~PartitionedLocalStorage() {}
 
 int64_t PartitionedLocalStorage::GetOriginQuotaUsage() const {
   return mCache->GetOriginQuotaUsage(SessionStorageCache::eSessionSetType);
 }
 
 uint32_t PartitionedLocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
--- a/dom/storage/PartitionedLocalStorage.h
+++ b/dom/storage/PartitionedLocalStorage.h
@@ -19,18 +19,18 @@ class SessionStorageCache;
 // PartitionedLocalStorage is a in-memory-only storage exposed to trackers. It
 // doesn't share data with other contexts.
 
 class PartitionedLocalStorage final : public Storage {
  public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PartitionedLocalStorage, Storage)
 
-  PartitionedLocalStorage(nsPIDOMWindowInner* aWindow,
-                          nsIPrincipal* aPrincipal);
+  PartitionedLocalStorage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+                          nsIPrincipal* aStoragePrincipal);
 
   StorageType Type() const override { return ePartitionedLocalStorage; }
 
   int64_t GetOriginQuotaUsage() const override;
 
   bool IsForkOf(const Storage* aStorage) const override;
 
   // WebIDL
--- a/dom/storage/SessionStorage.cpp
+++ b/dom/storage/SessionStorage.cpp
@@ -30,27 +30,28 @@ NS_INTERFACE_MAP_END_INHERITING(Storage)
 NS_IMPL_ADDREF_INHERITED(SessionStorage, Storage)
 NS_IMPL_RELEASE_INHERITED(SessionStorage, Storage)
 
 SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
                                nsIPrincipal* aPrincipal,
                                SessionStorageCache* aCache,
                                SessionStorageManager* aManager,
                                const nsAString& aDocumentURI, bool aIsPrivate)
-    : Storage(aWindow, aPrincipal),
+    : Storage(aWindow, aPrincipal, aPrincipal),
       mCache(aCache),
       mManager(aManager),
       mDocumentURI(aDocumentURI),
       mIsPrivate(aIsPrivate) {
   MOZ_ASSERT(aCache);
 }
 
 SessionStorage::~SessionStorage() {}
 
 already_AddRefed<SessionStorage> SessionStorage::Clone() const {
+  MOZ_ASSERT(Principal() == StoragePrincipal());
   RefPtr<SessionStorage> storage =
       new SessionStorage(GetParentObject(), Principal(), mCache, mManager,
                          mDocumentURI, mIsPrivate);
   return storage.forget();
 }
 
 int64_t SessionStorage::GetOriginQuotaUsage() const {
   return mCache->GetOriginQuotaUsage(DATASET);
--- a/dom/storage/SessionStorageManager.cpp
+++ b/dom/storage/SessionStorageManager.cpp
@@ -66,16 +66,17 @@ SessionStorageManager::PrecacheStorage(n
                                        Storage** aRetval) {
   // Nothing to preload.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SessionStorageManager::CreateStorage(mozIDOMWindow* aWindow,
                                      nsIPrincipal* aPrincipal,
+                                     nsIPrincipal* aStoragePrincipal,
                                      const nsAString& aDocumentURI,
                                      bool aPrivate, Storage** aRetval) {
   nsAutoCString originKey;
   nsAutoCString originAttributes;
   nsresult rv = GenerateOriginKey(aPrincipal, originAttributes, originKey);
   if (NS_FAILED(rv)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
@@ -89,27 +90,29 @@ SessionStorageManager::CreateStorage(moz
   RefPtr<SessionStorageCache> cache;
   if (!table->Get(originKey, getter_AddRefs(cache))) {
     cache = new SessionStorageCache();
     table->Put(originKey, cache);
   }
 
   nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
 
+  // No StoragePrincipal for sessionStorage.
   RefPtr<SessionStorage> storage = new SessionStorage(
       inner, aPrincipal, cache, this, aDocumentURI, aPrivate);
 
   storage.forget(aRetval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SessionStorageManager::GetStorage(mozIDOMWindow* aWindow,
-                                  nsIPrincipal* aPrincipal, bool aPrivate,
-                                  Storage** aRetval) {
+                                  nsIPrincipal* aPrincipal,
+                                  nsIPrincipal* aStoragePrincipal,
+                                  bool aPrivate, Storage** aRetval) {
   *aRetval = nullptr;
 
   nsAutoCString originKey;
   nsAutoCString originAttributes;
   nsresult rv = GenerateOriginKey(aPrincipal, originAttributes, originKey);
   if (NS_FAILED(rv)) {
     return rv;
   }
--- a/dom/storage/Storage.cpp
+++ b/dom/storage/Storage.cpp
@@ -11,28 +11,33 @@
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 static const char kStorageEnabled[] = "dom.storage.enabled";
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal,
+                                      mStoragePrincipal)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Storage, LastRelease())
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Storage)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-Storage::Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
-    : mWindow(aWindow), mPrincipal(aPrincipal), mIsSessionOnly(false) {
+Storage::Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+                 nsIPrincipal* aStoragePrincipal)
+    : mWindow(aWindow),
+      mPrincipal(aPrincipal),
+      mStoragePrincipal(aStoragePrincipal),
+      mIsSessionOnly(false) {
   MOZ_ASSERT(aPrincipal);
 
   if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
     mIsSessionOnly = false;
   } else if (mWindow) {
     uint32_t rejectedReason = 0;
     nsContentUtils::StorageAccess access =
         nsContentUtils::StorageAllowedForWindow(mWindow, &rejectedReason);
@@ -40,17 +45,17 @@ Storage::Storage(nsPIDOMWindowInner* aWi
     MOZ_ASSERT(access != nsContentUtils::StorageAccess::eDeny ||
                rejectedReason ==
                    nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN);
 
     mIsSessionOnly = access <= nsContentUtils::StorageAccess::eSessionScoped;
   }
 }
 
-Storage::~Storage() {}
+Storage::~Storage() = default;
 
 /* static */
 bool Storage::StoragePrefIsEnabled() {
   return mozilla::Preferences::GetBool(kStorageEnabled);
 }
 
 bool Storage::CanUseStorage(nsIPrincipal& aSubjectPrincipal) {
   if (!StoragePrefIsEnabled()) {
--- a/dom/storage/Storage.h
+++ b/dom/storage/Storage.h
@@ -21,17 +21,18 @@ class nsPIDOMWindowInner;
 namespace mozilla {
 namespace dom {
 
 class Storage : public nsISupports, public nsWrapperCache {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Storage)
 
-  Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal);
+  Storage(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
+          nsIPrincipal* aStoragePrincipal);
 
   static bool StoragePrefIsEnabled();
 
   enum StorageType {
     eSessionStorage,
     eLocalStorage,
     ePartitionedLocalStorage,
   };
@@ -39,16 +40,18 @@ class Storage : public nsISupports, publ
   virtual StorageType Type() const = 0;
 
   virtual bool IsForkOf(const Storage* aStorage) const = 0;
 
   virtual int64_t GetOriginQuotaUsage() const = 0;
 
   nsIPrincipal* Principal() const { return mPrincipal; }
 
+  nsIPrincipal* StoragePrincipal() const { return mStoragePrincipal; }
+
   // WebIDL
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
 
   virtual uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
                              ErrorResult& aRv) = 0;
@@ -136,16 +139,17 @@ class Storage : public nsISupports, publ
   // The method checks whether the caller can use a storage.
   bool CanUseStorage(nsIPrincipal& aSubjectPrincipal);
 
   virtual void LastRelease() {}
 
  private:
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<nsIPrincipal> mStoragePrincipal;
 
   // Whether storage is set to persist data only per session, may change
   // dynamically and is set by CanUseStorage function that is called
   // before any operation on the storage.
   bool mIsSessionOnly : 1;
 };
 
 }  // namespace dom
--- a/dom/storage/StorageNotifierService.cpp
+++ b/dom/storage/StorageNotifierService.cpp
@@ -71,17 +71,17 @@ void StorageNotifierService::Broadcast(S
     // principal).
     if (aPrivateBrowsing != observer->IsPrivateBrowsing()) {
       continue;
     }
 
     // No reasons to continue if the principal of the event doesn't match with
     // the window's one.
     if (!StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(),
-                                       observer->GetPrincipal())) {
+                                       observer->GetEffectiveStoragePrincipal())) {
       continue;
     }
 
     RefPtr<Runnable> r = NS_NewRunnableFunction(
         "StorageNotifierService::Broadcast",
         [observer, event, aStorageType, aPrivateBrowsing]() {
           observer->ObserveStorageNotification(event, aStorageType,
                                                aPrivateBrowsing);
--- a/dom/storage/StorageNotifierService.h
+++ b/dom/storage/StorageNotifierService.h
@@ -26,17 +26,17 @@ class StorageNotificationObserver {
   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 
   virtual void ObserveStorageNotification(StorageEvent* aEvent,
                                           const char16_t* aStorageType,
                                           bool aPrivateBrowsing) = 0;
 
   virtual bool IsPrivateBrowsing() const = 0;
 
-  virtual nsIPrincipal* GetPrincipal() const = 0;
+  virtual nsIPrincipal* GetEffectiveStoragePrincipal() const = 0;
 
   virtual nsIEventTarget* GetEventTarget() const = 0;
 };
 
 /**
  * A specialized version of the observer service that uses the custom
  * StorageNotificationObserver so that principal checks can happen in this class
  * rather than in the nsIObserver::observe method where they used to happen.
--- a/dom/tests/browser/browser_localStorage_e10s.js
+++ b/dom/tests/browser/browser_localStorage_e10s.js
@@ -83,17 +83,17 @@ function clearOriginStorageEnsuringNoPre
       };
     });
     return promise;
   }
 
   // We want to use createStorage to force the cache to be created so we can
   // issue the clear.  It's possible for getStorage to return false but for the
   // origin preload hash to still have our origin in it.
-  let storage = Services.domStorageManager.createStorage(null, principal, "");
+  let storage = Services.domStorageManager.createStorage(null, principal, principal, "");
   storage.clear();
 
   // We also need to trigger a flush os that mOriginsHavingData gets updated.
   // The inherent flush race is fine here because
   return triggerAndWaitForLocalStorageFlush();
 }
 
 async function verifyTabPreload(knownTab, expectStorageExists) {
@@ -102,17 +102,17 @@ async function verifyTabPreload(knownTab
     HELPER_PAGE_ORIGIN,
     function(origin) {
       let principal =
         Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
           origin);
       if (Services.lsm.nextGenLocalStorageEnabled) {
         return Services.lsm.isPreloaded(principal);
       }
-      return !!Services.domStorageManager.getStorage(null, principal);
+      return !!Services.domStorageManager.getStorage(null, principal, principal);
     });
   is(storageExists, expectStorageExists, "Storage existence === preload");
 }
 
 /**
  * Instruct the given tab to execute the given series of mutations.  For
  * simplicity, the mutations representation matches the expected events rep.
  */
--- a/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
+++ b/dom/tests/mochitest/localstorage/test_localStorageFromChrome.xhtml
@@ -16,17 +16,17 @@ async function startTest()
     .getService(Components.interfaces.nsIIOService);
   var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
     .getService(Components.interfaces.nsIScriptSecurityManager);
   var dsm = Components.classes["@mozilla.org/dom/localStorage-manager;1"]
     .getService(Components.interfaces.nsIDOMStorageManager);
 
   var uri = ios.newURI(url);
   var principal = ssm.createCodebasePrincipal(uri, {});
-  var storage = dsm.createStorage(window, principal, "");
+  var storage = dsm.createStorage(window, principal, principal, "");
 
   storage.setItem("chromekey", "chromevalue");
 
   var aframe = document.getElementById("aframe");
   aframe.onload = function()
   {
     is(storage.getItem("chromekey"), "chromevalue");
     is(aframe.contentDocument.getElementById("data").innerHTML, "chromevalue");
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -267,17 +267,17 @@ var UninstallObserver = {
       Services.qms.clearStoragesForPrincipal(storagePrincipal);
 
       ExtensionStorageIDB.clearMigratedExtensionPref(addon.id);
 
       // If LSNG is not enabled, we need to clear localStorage explicitly using
       // the old API.
       if (!Services.lsm.nextGenLocalStorageEnabled) {
         // Clear localStorage created by the extension
-        let storage = Services.domStorageManager.getStorage(null, principal);
+        let storage = Services.domStorageManager.getStorage(null, principal, storagePrincipal);
         if (storage) {
           storage.clear();
         }
       }
 
       // Remove any permissions related to the unlimitedStorage permission
       // if we are also removing all the data stored by the extension.
       Services.perms.removeFromPrincipal(principal, "WebExtensions-unlimitedStorage");
--- a/toolkit/components/sessionstore/SessionStoreUtils.cpp
+++ b/toolkit/components/sessionstore/SessionStoreUtils.cpp
@@ -961,36 +961,42 @@ static void ReadAllEntriesFromStorage(
   if (!docShell) {
     return;
   }
 
   Document* doc = aWindow->GetDoc();
   if (!doc) {
     return;
   }
+
   nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
   if (!principal) {
     return;
   }
 
+  nsCOMPtr<nsIPrincipal> storagePrincipal = doc->EffectiveStoragePrincipal();
+  if (!storagePrincipal) {
+    return;
+  }
+
   nsAutoCString origin;
   nsresult rv = principal->GetOrigin(origin);
   if (NS_FAILED(rv) || aVisitedOrigins.Contains(origin)) {
     // Don't read a host twice.
     return;
   }
 
   /* Completed checking for recursion and is about to read storage*/
   nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell);
   if (!storageManager) {
     return;
   }
   RefPtr<Storage> storage;
-  storageManager->GetStorage(aWindow->GetCurrentInnerWindow(), principal, false,
-                             getter_AddRefs(storage));
+  storageManager->GetStorage(aWindow->GetCurrentInnerWindow(), principal,
+                             storagePrincipal, false, getter_AddRefs(storage));
   if (!storage) {
     return;
   }
   mozilla::IgnoredErrorResult result;
   uint32_t len = storage->GetLength(*principal, result);
   if (result.Failed() || len == 0) {
     return;
   }
@@ -1108,18 +1114,18 @@ void SessionStoreUtils::RestoreSessionSt
     }
     RefPtr<Storage> storage;
     // There is no need to pass documentURI, it's only used to fill documentURI
     // property of domstorage event, which in this case has no consumer.
     // Prevention of events in case of missing documentURI will be solved in a
     // followup bug to bug 600307.
     // Null window because the current window doesn't match the principal yet
     // and loads about:blank.
-    storageManager->CreateStorage(nullptr, principal, EmptyString(), false,
-                                  getter_AddRefs(storage));
+    storageManager->CreateStorage(nullptr, principal, principal, EmptyString(),
+                                  false, getter_AddRefs(storage));
     if (!storage) {
       continue;
     }
     for (auto& InnerEntry : entry.mValue.Entries()) {
       IgnoredErrorResult result;
       storage->SetItem(InnerEntry.mKey, InnerEntry.mValue, *principal, result);
       if (result.Failed()) {
         NS_WARNING("storage set item failed!");
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1179,19 +1179,19 @@ nsresult nsWindowWatcher::OpenWindowInte
         do_QueryInterface(parentDocShell);
     nsCOMPtr<nsIDOMStorageManager> newStorageManager =
         do_QueryInterface(newDocShell);
 
     if (parentStorageManager && newStorageManager) {
       RefPtr<Storage> storage;
       nsCOMPtr<nsPIDOMWindowInner> pInnerWin =
           parentWindow->GetCurrentInnerWindow();
-      parentStorageManager->GetStorage(pInnerWin, subjectPrincipal,
-                                       isPrivateBrowsingWindow,
-                                       getter_AddRefs(storage));
+      parentStorageManager->GetStorage(
+          pInnerWin, subjectPrincipal, subjectPrincipal,
+          isPrivateBrowsingWindow, getter_AddRefs(storage));
       if (storage) {
         newStorageManager->CloneStorage(storage);
       }
     }
   }
 
   if (isNewToplevelWindow) {
     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
--- a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
+++ b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
@@ -436,17 +436,17 @@ async function test_cache_cleared() {
   await ForgetAboutSite.removeDataFromDomain("mozilla.org");
   do_test_pending();
 }
 
 async function test_storage_cleared() {
   function getStorageForURI(aURI) {
     let principal = Services.scriptSecurityManager.createCodebasePrincipal(aURI, {});
 
-    return Services.domStorageManager.createStorage(null, principal, "");
+    return Services.domStorageManager.createStorage(null, principal, principal, "");
   }
 
   Services.prefs.setBoolPref("dom.storage.client_validation", false);
 
   let s = [
     getStorageForURI(Services.io.newURI("http://mozilla.org")),
     getStorageForURI(Services.io.newURI("http://my.mozilla.org")),
     getStorageForURI(Services.io.newURI("http://ilovemozilla.org")),