From 915fb54734e6e288683edbd9fdf4274dadf392fa Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 3 May 2023 18:36:08 +0000 Subject: [PATCH] Bug 1781201 - Generate unique anonymous origins for private browsing; r=hsingh The generated origins are cached in a hash map. There's also a hash map for getting the original origin from a generated origin which will be needed for metadata loading once generated origins are actually used for creating origin directories and for creating metadata files. The patch is partially based on D176751. Differential Revision: https://phabricator.services.mozilla.com/D176875 --- dom/quota/ActorsParent.cpp | 105 +++++++++++++++++++++++++++++--- dom/quota/CommonMetadata.h | 9 ++- dom/quota/Constants.h | 18 ++++++ dom/quota/DirectoryLockImpl.cpp | 5 +- dom/quota/OriginInfo.cpp | 3 +- dom/quota/QuotaManager.h | 10 +++ dom/quota/moz.build | 1 + 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 dom/quota/Constants.h diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 0257f750dead..8430ab064f8a 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -85,6 +85,7 @@ #include "mozilla/dom/quota/AssertionsImpl.h" #include "mozilla/dom/quota/CheckedUnsafePtr.h" #include "mozilla/dom/quota/Client.h" +#include "mozilla/dom/quota/Constants.h" #include "mozilla/dom/quota/DirectoryLock.h" #include "mozilla/dom/quota/PersistenceType.h" #include "mozilla/dom/quota/PQuota.h" @@ -122,6 +123,7 @@ #include "nsIBinaryOutputStream.h" #include "nsIConsoleService.h" #include "nsIDirectoryEnumerator.h" +#include "nsIDUtils.h" #include "nsIEventTarget.h" #include "nsIFile.h" #include "nsIFileStreams.h" @@ -146,6 +148,7 @@ #include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "nsPrintfCString.h" +#include "nsStandardURL.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsStringFlags.h" @@ -6451,16 +6454,40 @@ QuotaManager::GetInfoFromValidatedPrincipalInfo( const ContentPrincipalInfo& info = aPrincipalInfo.get_ContentPrincipalInfo(); + nsCString suffix; + info.attrs().CreateSuffix(suffix); + + nsCString origin = info.originNoSuffix() + suffix; + + if (StringBeginsWith(origin, kUUIDOriginScheme)) { + QM_TRY_INSPECT(const auto& originalOrigin, + GetOriginFromStorageOrigin(origin)); + + nsCOMPtr principal = + BasePrincipal::CreateContentPrincipal(originalOrigin); + QM_TRY(MOZ_TO_RESULT(principal)); + + PrincipalInfo principalInfo; + QM_TRY( + MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo))); + + return GetInfoFromValidatedPrincipalInfo(principalInfo); + } + PrincipalMetadata principalMetadata; - info.attrs().CreateSuffix(principalMetadata.mSuffix); + principalMetadata.mSuffix = suffix; - principalMetadata.mGroup = info.baseDomain() + principalMetadata.mSuffix; + principalMetadata.mGroup = info.baseDomain() + suffix; - principalMetadata.mOrigin = - info.originNoSuffix() + principalMetadata.mSuffix; + principalMetadata.mOrigin = origin; - principalMetadata.mStorageOrigin = principalMetadata.mOrigin; + if (info.attrs().mPrivateBrowsingId != 0) { + QM_TRY_UNWRAP(principalMetadata.mStorageOrigin, + EnsureStorageOriginFromOrigin(origin)); + } else { + principalMetadata.mStorageOrigin = origin; + } principalMetadata.mIsPrivate = info.attrs().mPrivateBrowsingId != 0; @@ -7095,6 +7122,59 @@ bool QuotaManager::IsSanitizedOriginValid(const nsACString& aSanitizedOrigin) { }); } +Result QuotaManager::EnsureStorageOriginFromOrigin( + const nsACString& aOrigin) { + MutexAutoLock lock(mQuotaMutex); + + QM_TRY_UNWRAP( + auto storageOrigin, + mOriginToStorageOriginMap.TryLookupOrInsertWith( + aOrigin, [this, &aOrigin]() -> Result { + OriginAttributes originAttributes; + + nsCString originNoSuffix; + QM_TRY(MOZ_TO_RESULT( + originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix))); + + nsCOMPtr uri; + QM_TRY(MOZ_TO_RESULT( + NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID) + .SetSpec(originNoSuffix) + .SetScheme("uuid"_ns) + .SetHost(NSID_TrimBracketsASCII(nsID::GenerateUUID())) + .SetPort(-1) + .Finalize(uri))); + + nsCOMPtr principal = + BasePrincipal::CreateContentPrincipal(uri, OriginAttributes{}); + QM_TRY(MOZ_TO_RESULT(principal)); + + QM_TRY_UNWRAP(auto origin, + MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( + nsAutoCString, principal, GetOrigin)); + + mStorageOriginToOriginMap.WithEntryHandle( + origin, + [&aOrigin](auto entryHandle) { entryHandle.Insert(aOrigin); }); + + return nsCString(std::move(origin)); + })); + + return nsCString(std::move(storageOrigin)); +} + +Result QuotaManager::GetOriginFromStorageOrigin( + const nsACString& aStorageOrigin) { + MutexAutoLock lock(mQuotaMutex); + + auto maybeOrigin = mStorageOriginToOriginMap.MaybeGet(aStorageOrigin); + if (maybeOrigin.isNothing()) { + return Err(NS_ERROR_FAILURE); + } + + return maybeOrigin.ref(); +} + int64_t QuotaManager::GenerateDirectoryLockId() { const int64_t directorylockId = mNextDirectoryLockId; @@ -8392,7 +8472,8 @@ nsresult GetOriginUsageOp::DoInit(QuotaManager& aQuotaManager) { QM_TRY_UNWRAP( PrincipalMetadata principalMetadata, aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo())); - MOZ_ASSERT(principalMetadata.mOrigin == principalMetadata.mStorageOrigin); + + principalMetadata.AssertInvariants(); mSuffix = std::move(principalMetadata.mSuffix); mGroup = std::move(principalMetadata.mGroup); @@ -8671,7 +8752,8 @@ nsresult InitializeOriginRequestBase::DoInit(QuotaManager& aQuotaManager) { QM_TRY_UNWRAP( auto principalMetadata, aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo)); - MOZ_ASSERT(principalMetadata.mOrigin == principalMetadata.mStorageOrigin); + + principalMetadata.AssertInvariants(); mSuffix = std::move(principalMetadata.mSuffix); mGroup = std::move(principalMetadata.mGroup); @@ -8773,7 +8855,8 @@ nsresult GetFullOriginMetadataOp::DoInit(QuotaManager& aQuotaManager) { QM_TRY_UNWRAP( PrincipalMetadata principalMetadata, aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo())); - MOZ_ASSERT(principalMetadata.mOrigin == principalMetadata.mStorageOrigin); + + principalMetadata.AssertInvariants(); mOriginMetadata = {std::move(principalMetadata), mParams.persistenceType()}; @@ -9284,7 +9367,8 @@ nsresult PersistRequestBase::DoInit(QuotaManager& aQuotaManager) { QM_TRY_UNWRAP( PrincipalMetadata principalMetadata, aQuotaManager.GetInfoFromValidatedPrincipalInfo(mPrincipalInfo)); - MOZ_ASSERT(principalMetadata.mOrigin == principalMetadata.mStorageOrigin); + + principalMetadata.AssertInvariants(); mSuffix = std::move(principalMetadata.mSuffix); mGroup = std::move(principalMetadata.mGroup); @@ -9448,7 +9532,8 @@ nsresult EstimateOp::DoInit(QuotaManager& aQuotaManager) { QM_TRY_UNWRAP( PrincipalMetadata principalMetadata, aQuotaManager.GetInfoFromValidatedPrincipalInfo(mParams.principalInfo())); - MOZ_ASSERT(principalMetadata.mOrigin == principalMetadata.mStorageOrigin); + + principalMetadata.AssertInvariants(); mOriginMetadata = {std::move(principalMetadata), PERSISTENCE_TYPE_DEFAULT}; diff --git a/dom/quota/CommonMetadata.h b/dom/quota/CommonMetadata.h index cf76b3f9817d..b09fafc6e62b 100644 --- a/dom/quota/CommonMetadata.h +++ b/dom/quota/CommonMetadata.h @@ -10,6 +10,7 @@ #include #include "mozilla/dom/quota/Client.h" +#include "mozilla/dom/quota/Constants.h" #include "mozilla/dom/quota/PersistenceType.h" #include "nsString.h" @@ -34,7 +35,13 @@ struct PrincipalMetadata { mOrigin{std::move(aOrigin)}, mStorageOrigin{std::move(aStorageOrigin)}, mIsPrivate{aIsPrivate} { - MOZ_ASSERT(mOrigin == mStorageOrigin); + AssertInvariants(); + } + + void AssertInvariants() const { + MOZ_ASSERT(!StringBeginsWith(mOrigin, kUUIDOriginScheme)); + MOZ_ASSERT_IF(!mIsPrivate, mOrigin == mStorageOrigin); + MOZ_ASSERT_IF(mIsPrivate, mOrigin != mStorageOrigin); } }; diff --git a/dom/quota/Constants.h b/dom/quota/Constants.h new file mode 100644 index 000000000000..62f6c3267adb --- /dev/null +++ b/dom/quota/Constants.h @@ -0,0 +1,18 @@ +/* -*- 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 DOM_QUOTA_CONSTANTS_H_ +#define DOM_QUOTA_CONSTANTS_H_ + +#include "nsLiteralString.h" + +namespace mozilla::dom::quota { + +constexpr nsLiteralCString kUUIDOriginScheme = "uuid"_ns; + +} // namespace mozilla::dom::quota + +#endif // DOM_QUOTA_CONSTANTS_H_ diff --git a/dom/quota/DirectoryLockImpl.cpp b/dom/quota/DirectoryLockImpl.cpp index c1ff93b3af85..2993971c7ae3 100644 --- a/dom/quota/DirectoryLockImpl.cpp +++ b/dom/quota/DirectoryLockImpl.cpp @@ -42,7 +42,10 @@ DirectoryLockImpl::DirectoryLockImpl( MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty()); MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin()); MOZ_ASSERT_IF(!aInternal, !aStorageOrigin.IsEmpty()); - MOZ_ASSERT_IF(!aInternal, aOriginScope.GetOrigin() == aStorageOrigin); + MOZ_ASSERT_IF(!aInternal && !aIsPrivate, + aOriginScope.GetOrigin() == aStorageOrigin); + MOZ_ASSERT_IF(!aInternal && aIsPrivate, + aOriginScope.GetOrigin() != aStorageOrigin); MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull()); MOZ_ASSERT_IF(!aInternal, aClientType.Value() < Client::TypeMax()); } diff --git a/dom/quota/OriginInfo.cpp b/dom/quota/OriginInfo.cpp index 3ec4df2830b7..4117138ef2fc 100644 --- a/dom/quota/OriginInfo.cpp +++ b/dom/quota/OriginInfo.cpp @@ -30,7 +30,8 @@ OriginInfo::OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, mPersisted(aPersisted), mDirectoryExists(aDirectoryExists) { MOZ_ASSERT(aGroupInfo); - MOZ_ASSERT(aOrigin == aStorageOrigin); + MOZ_ASSERT_IF(!aIsPrivate, aOrigin == aStorageOrigin); + MOZ_ASSERT_IF(aIsPrivate, aOrigin != aStorageOrigin); MOZ_ASSERT(aClientUsages.Length() == Client::TypeMax()); MOZ_ASSERT_IF(aPersisted, aGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT); diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h index a640d31db36d..31bbc15a844e 100644 --- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -577,6 +577,12 @@ class QuotaManager final : public BackgroundThreadObject { bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin); + Result EnsureStorageOriginFromOrigin( + const nsACString& aOrigin); + + Result GetOriginFromStorageOrigin( + const nsACString& aStorageOrigin); + int64_t GenerateDirectoryLockId(); bool ShutdownStarted() const; @@ -655,6 +661,10 @@ class QuotaManager final : public BackgroundThreadObject { // it is only ever touched on the IO thread. nsTHashMap mValidOrigins; + // These maps are protected by mQuotaMutex. + nsTHashMap mOriginToStorageOriginMap; + nsTHashMap mStorageOriginToOriginMap; + // This array is populated at initialization time and then never modified, so // it can be iterated on any thread. LazyInitializedOnce, Client::TYPE_MAX>> diff --git a/dom/quota/moz.build b/dom/quota/moz.build index 67f562d6d94a..56a1fc73ecb6 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -34,6 +34,7 @@ EXPORTS.mozilla.dom.quota += [ "ClientImpl.h", "CommonMetadata.h", "Config.h", + "Constants.h", "DebugOnlyMacro.h", "DecryptingInputStream.h", "DecryptingInputStream_impl.h",