diff --git a/extensions/permissions/nsPermissionManager.cpp b/extensions/permissions/nsPermissionManager.cpp index 9b667d3a4c29..c55722b0bdc9 100644 --- a/extensions/permissions/nsPermissionManager.cpp +++ b/extensions/permissions/nsPermissionManager.cpp @@ -153,16 +153,37 @@ bool IsPreloadPermission(const nsACString& aType) { return false; } -// Strip private browsing and user context (if enabled by pref) -// Flipping these prefs changes the suffix being hashed. -void MaybeStripOAs(OriginAttributes& aOriginAttributes) { +// Array of permission types which should not be isolated by origin attributes, +// for user context and private browsing. +static constexpr std::array kStripOAPermissions = { + {NS_LITERAL_CSTRING("cookie")}}; + +bool IsOAForceStripPermission(const nsACString& aType) { + if (aType.IsEmpty()) { + return false; + } + for (const auto& perm : kStripOAPermissions) { + if (perm.Equals(aType)) { + return true; + } + } + return false; +} + +/** + * Strip origin attributes depending on pref state + * @param aForceStrip If true, strips user context and private browsing id, + * ignoring stripping prefs. + * @param aOriginAttributes object to strip. + */ +void MaybeStripOAs(bool aForceStrip, OriginAttributes& aOriginAttributes) { uint32_t flags = 0; - if (!StaticPrefs::permissions_isolateBy_privateBrowsing()) { + if (aForceStrip || !StaticPrefs::permissions_isolateBy_privateBrowsing()) { flags |= OriginAttributes::STRIP_PRIVATE_BROWSING_ID; } - if (!StaticPrefs::permissions_isolateBy_userContext()) { + if (aForceStrip || !StaticPrefs::permissions_isolateBy_userContext()) { flags |= OriginAttributes::STRIP_USER_CONTEXT_ID; } @@ -172,15 +193,16 @@ void MaybeStripOAs(OriginAttributes& aOriginAttributes) { } void OriginAppendOASuffix(OriginAttributes aOriginAttributes, - nsACString& aOrigin) { - MaybeStripOAs(aOriginAttributes); + bool aForceStripOA, nsACString& aOrigin) { + MaybeStripOAs(aForceStripOA, aOriginAttributes); nsAutoCString oaSuffix; aOriginAttributes.CreateSuffix(oaSuffix); aOrigin.Append(oaSuffix); } -nsresult GetOriginFromPrincipal(nsIPrincipal* aPrincipal, nsACString& aOrigin) { +nsresult GetOriginFromPrincipal(nsIPrincipal* aPrincipal, bool aForceStripOA, + nsACString& aOrigin) { nsresult rv = aPrincipal->GetOriginNoSuffix(aOrigin); // The principal may belong to the about:blank content viewer, so this can be // expected to fail. @@ -197,26 +219,26 @@ nsresult GetOriginFromPrincipal(nsIPrincipal* aPrincipal, nsACString& aOrigin) { return NS_ERROR_FAILURE; } - OriginAppendOASuffix(attrs, aOrigin); + OriginAppendOASuffix(attrs, aForceStripOA, aOrigin); return NS_OK; } nsresult GetOriginFromURIAndOA(nsIURI* aURI, const OriginAttributes* aOriginAttributes, - nsACString& aOrigin) { + bool aForceStripOA, nsACString& aOrigin) { nsAutoCString origin(aOrigin); nsresult rv = ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI, origin); NS_ENSURE_SUCCESS(rv, rv); - OriginAppendOASuffix(*aOriginAttributes, origin); + OriginAppendOASuffix(*aOriginAttributes, aForceStripOA, origin); aOrigin = origin; return NS_OK; } -nsresult GetPrincipalFromOrigin(const nsACString& aOrigin, +nsresult GetPrincipalFromOrigin(const nsACString& aOrigin, bool aForceStripOA, nsIPrincipal** aPrincipal) { nsAutoCString originNoSuffix; mozilla::OriginAttributes attrs; @@ -224,7 +246,7 @@ nsresult GetPrincipalFromOrigin(const nsACString& aOrigin, return NS_ERROR_FAILURE; } - MaybeStripOAs(attrs); + MaybeStripOAs(aForceStripOA, attrs); nsCOMPtr uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); @@ -397,7 +419,8 @@ class MOZ_STACK_CLASS UpgradeHostToOriginHostfileImport final uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime) final { nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin(aOrigin, getter_AddRefs(principal)); + nsresult rv = GetPrincipalFromOrigin( + aOrigin, IsOAForceStripPermission(aType), getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); return mPm->AddInternal(principal, aType, aPermission, mID, aExpireType, @@ -530,7 +553,8 @@ nsresult UpgradeHostToOriginAndInsert( NS_ENSURE_SUCCESS(rv, rv); nsAutoCString origin; - rv = GetOriginFromPrincipal(principal, origin); + rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), + origin); NS_ENSURE_SUCCESS(rv, rv); return aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, @@ -645,7 +669,8 @@ nsresult UpgradeHostToOriginAndInsert( if (NS_WARN_IF(NS_FAILED(rv))) continue; nsAutoCString origin; - rv = GetOriginFromPrincipal(principal, origin); + rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), + origin); if (NS_WARN_IF(NS_FAILED(rv))) continue; // Ensure that we don't insert the same origin repeatedly @@ -692,7 +717,8 @@ nsresult UpgradeHostToOriginAndInsert( getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); - rv = GetOriginFromPrincipal(principal, origin); + rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), + origin); NS_ENSURE_SUCCESS(rv, rv); aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, @@ -707,7 +733,8 @@ nsresult UpgradeHostToOriginAndInsert( getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); - rv = GetOriginFromPrincipal(principal, origin); + rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), + origin); NS_ENSURE_SUCCESS(rv, rv); aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, @@ -741,9 +768,9 @@ static bool IsPersistentExpire(uint32_t aExpire, const nsACString& aType) { nsPermissionManager::PermissionKey* nsPermissionManager::PermissionKey::CreateFromPrincipal( - nsIPrincipal* aPrincipal, nsresult& aResult) { + nsIPrincipal* aPrincipal, bool aForceStripOA, nsresult& aResult) { nsAutoCString origin; - aResult = GetOriginFromPrincipal(aPrincipal, origin); + aResult = GetOriginFromPrincipal(aPrincipal, aForceStripOA, origin); if (NS_WARN_IF(NS_FAILED(aResult))) { return nullptr; } @@ -753,10 +780,11 @@ nsPermissionManager::PermissionKey::CreateFromPrincipal( nsPermissionManager::PermissionKey* nsPermissionManager::PermissionKey::CreateFromURIAndOriginAttributes( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, + nsIURI* aURI, const OriginAttributes* aOriginAttributes, bool aForceStripOA, nsresult& aResult) { nsAutoCString origin; - aResult = GetOriginFromURIAndOA(aURI, aOriginAttributes, origin); + aResult = + GetOriginFromURIAndOA(aURI, aOriginAttributes, aForceStripOA, origin); if (NS_WARN_IF(NS_FAILED(aResult))) { return nullptr; } @@ -1714,7 +1742,8 @@ nsresult nsPermissionManager::AddInternal( int64_t aModificationTime, NotifyOperationType aNotifyOperation, DBOperationType aDBOperation, const bool aIgnoreSessionPermissions) { nsAutoCString origin; - nsresult rv = GetOriginFromPrincipal(aPrincipal, origin); + nsresult rv = GetOriginFromPrincipal(aPrincipal, + IsOAForceStripPermission(aType), origin); NS_ENSURE_SUCCESS(rv, rv); // For private browsing only store permissions for the session @@ -1753,8 +1782,8 @@ nsresult nsPermissionManager::AddInternal( // When an entry already exists, PutEntry will return that, instead // of adding a new one - RefPtr key = - PermissionKey::CreateFromPrincipal(aPrincipal, rv); + RefPtr key = PermissionKey::CreateFromPrincipal( + aPrincipal, IsOAForceStripPermission(aType), rv); if (!key) { MOZ_ASSERT(NS_FAILED(rv)); return rv; @@ -2063,8 +2092,10 @@ nsresult nsPermissionManager::RemovePermissionEntries(T aCondition) { } nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, - getter_AddRefs(principal)); + nsresult rv = GetPrincipalFromOrigin( + entry->GetKey()->mOrigin, + IsOAForceStripPermission(mTypeArray[permEntry.mType]), + getter_AddRefs(principal)); if (NS_FAILED(rv)) { continue; } @@ -2266,6 +2297,7 @@ nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal, nsCOMPtr principal; nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, + IsOAForceStripPermission(aType), getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); @@ -2333,8 +2365,8 @@ nsPermissionManager::GetPermissionHashKey(nsIPrincipal* aPrincipal, MOZ_ASSERT(PermissionAvailable(aPrincipal, mTypeArray[aType])); nsresult rv; - RefPtr key = - PermissionKey::CreateFromPrincipal(aPrincipal, rv); + RefPtr key = PermissionKey::CreateFromPrincipal( + aPrincipal, IsOAForceStripPermission(mTypeArray[aType]), rv); if (!key) { return nullptr; } @@ -2402,7 +2434,8 @@ nsPermissionManager::GetPermissionHashKey( if (aOriginAttributes) { key = PermissionKey::CreateFromURIAndOriginAttributes( - aURI, aOriginAttributes, rv); + aURI, aOriginAttributes, IsOAForceStripPermission(mTypeArray[aType]), + rv); } else { key = PermissionKey::CreateFromURI(aURI, rv); } @@ -2490,8 +2523,10 @@ NS_IMETHODIMP nsPermissionManager::GetAllWithTypePrefix( } nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, - getter_AddRefs(principal)); + nsresult rv = GetPrincipalFromOrigin( + entry->GetKey()->mOrigin, + IsOAForceStripPermission(mTypeArray[permEntry.mType]), + getter_AddRefs(principal)); if (NS_FAILED(rv)) { continue; } @@ -2510,6 +2545,45 @@ NS_IMETHODIMP nsPermissionManager::GetAllWithTypePrefix( return NS_OK; } +nsresult nsPermissionManager::GetStripPermsForPrincipal( + nsIPrincipal* aPrincipal, nsTArray& aResult) { + aResult.Clear(); + aResult.SetCapacity(kStripOAPermissions.size()); + + // No special strip permissions + if (kStripOAPermissions.empty()) { + return NS_OK; + } + + nsresult rv; + // Create a key for the principal, but strip any origin attributes + RefPtr key = + PermissionKey::CreateFromPrincipal(aPrincipal, true, rv); + if (!key) { + MOZ_ASSERT(NS_FAILED(rv)); + return rv; + } + + PermissionHashKey* hashKey = mPermissionTable.GetEntry(key); + if (!hashKey) { + return NS_OK; + } + + for (const auto& permType : kStripOAPermissions) { + int32_t index = GetTypeIndex(permType, false); + if (index == -1) { + continue; + } + PermissionEntry perm = hashKey->GetPermission(index); + if (perm.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + aResult.AppendElement(perm); + } + + return NS_OK; +} + NS_IMETHODIMP nsPermissionManager::GetAllForPrincipal( nsIPrincipal* aPrincipal, nsTArray>& aResult) { @@ -2519,14 +2593,19 @@ nsPermissionManager::GetAllForPrincipal( nsresult rv; RefPtr key = - PermissionKey::CreateFromPrincipal(aPrincipal, rv); + PermissionKey::CreateFromPrincipal(aPrincipal, false, rv); if (!key) { MOZ_ASSERT(NS_FAILED(rv)); return rv; } - PermissionHashKey* entry = mPermissionTable.GetEntry(key); + nsTArray strippedPerms; + rv = GetStripPermsForPrincipal(aPrincipal, strippedPerms); + if (NS_FAILED(rv)) { + return rv; + } + if (entry) { for (const auto& permEntry : entry->GetPermissions()) { // Only return custom permissions @@ -2534,10 +2613,23 @@ nsPermissionManager::GetAllForPrincipal( continue; } + // Stripped principal permissions overwrite regular ones + // For each permission check if there is a stripped permission we should + // use instead + PermissionEntry perm = permEntry; + nsTArray::index_type index = 0; + for (const auto& strippedPerm : strippedPerms) { + if (strippedPerm.mType == permEntry.mType) { + perm = strippedPerm; + strippedPerms.RemoveElementAt(index); + break; + } + index++; + } + RefPtr permission = nsPermission::Create( - aPrincipal, mTypeArray[permEntry.mType], permEntry.mPermission, - permEntry.mExpireType, permEntry.mExpireTime, - permEntry.mModificationTime); + aPrincipal, mTypeArray[perm.mType], perm.mPermission, + perm.mExpireType, perm.mExpireTime, perm.mModificationTime); if (NS_WARN_IF(!permission)) { continue; } @@ -2545,6 +2637,16 @@ nsPermissionManager::GetAllForPrincipal( } } + for (const auto& perm : strippedPerms) { + RefPtr permission = nsPermission::Create( + aPrincipal, mTypeArray[perm.mType], perm.mPermission, perm.mExpireType, + perm.mExpireTime, perm.mModificationTime); + if (NS_WARN_IF(!permission)) { + continue; + } + aResult.AppendElement(permission); + } + return NS_OK; } @@ -2607,7 +2709,7 @@ nsresult nsPermissionManager::RemovePermissionsWithAttributes( PermissionHashKey* entry = iter.Get(); nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, false, getter_AddRefs(principal)); if (NS_FAILED(rv)) { continue; @@ -2743,7 +2845,8 @@ nsresult nsPermissionManager::Read() { modificationTime = stmt->AsInt64(6); nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin(origin, getter_AddRefs(principal)); + nsresult rv = GetPrincipalFromOrigin(origin, IsOAForceStripPermission(type), + getter_AddRefs(principal)); if (NS_FAILED(rv)) { readError = true; continue; @@ -2867,7 +2970,9 @@ nsresult nsPermissionManager::_DoImport(nsIInputStream* inputStream, if (NS_FAILED(error)) continue; nsCOMPtr principal; - error = GetPrincipalFromOrigin(lineArray[3], getter_AddRefs(principal)); + error = GetPrincipalFromOrigin(lineArray[3], + IsOAForceStripPermission(lineArray[1]), + getter_AddRefs(principal)); if (NS_FAILED(error)) { NS_WARNING("Couldn't import an origin permission - malformed origin"); continue; @@ -2975,7 +3080,8 @@ bool nsPermissionManager::GetPermissionsWithKey( PermissionHashKey* entry = iter.Get(); nsAutoCString permissionKey; - GetKeyForOrigin(entry->GetKey()->mOrigin, permissionKey); + GetKeyForOrigin(entry->GetKey()->mOrigin, + IsOAForceStripPermission(aPermissionKey), permissionKey); // If the keys don't match, and we aren't getting the default "" key, then // we can exit early. We have to keep looking if we're getting the default @@ -3032,7 +3138,8 @@ void nsPermissionManager::SetPermissionsWithKey( for (IPC::Permission& perm : aPerms) { nsCOMPtr principal; nsresult rv = - GetPrincipalFromOrigin(perm.origin, getter_AddRefs(principal)); + GetPrincipalFromOrigin(perm.origin, IsOAForceStripPermission(perm.type), + getter_AddRefs(principal)); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } @@ -3056,6 +3163,7 @@ void nsPermissionManager::SetPermissionsWithKey( /* static */ void nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, + bool aForceStripOA, nsACString& aKey) { aKey.Truncate(); @@ -3079,14 +3187,14 @@ void nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, return; } - MaybeStripOAs(attrs); + MaybeStripOAs(aForceStripOA, attrs); #ifdef DEBUG // Parse the origin string into a principal, and extract some useful // information from it for assertions. nsCOMPtr dbgPrincipal; - MOZ_ALWAYS_SUCCEEDS( - GetPrincipalFromOrigin(aOrigin, getter_AddRefs(dbgPrincipal))); + MOZ_ALWAYS_SUCCEEDS(GetPrincipalFromOrigin(aOrigin, aForceStripOA, + getter_AddRefs(dbgPrincipal))); MOZ_ASSERT(dbgPrincipal->SchemeIs("http") || dbgPrincipal->SchemeIs("https") || dbgPrincipal->SchemeIs("ftp")); MOZ_ASSERT(dbgPrincipal->OriginAttributesRef() == attrs); @@ -3100,6 +3208,7 @@ void nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, /* static */ void nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, + bool aForceStripOA, nsACString& aKey) { nsAutoCString origin; nsresult rv = aPrincipal->GetOrigin(origin); @@ -3107,7 +3216,7 @@ void nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, aKey.Truncate(); return; } - GetKeyForOrigin(origin, aKey); + GetKeyForOrigin(origin, aForceStripOA, aKey); } /* static */ @@ -3120,7 +3229,7 @@ void nsPermissionManager::GetKeyForPermission(nsIPrincipal* aPrincipal, return; } - GetKeyForPrincipal(aPrincipal, aKey); + GetKeyForPrincipal(aPrincipal, IsOAForceStripPermission(aType), aKey); } /* static */ @@ -3133,7 +3242,7 @@ nsTArray nsPermissionManager::GetAllKeysForPrincipal( while (prin) { // Add the key to the list nsCString* key = keys.AppendElement(); - GetKeyForPrincipal(prin, *key); + GetKeyForPrincipal(prin, false, *key); // Get the next subdomain principal and loop back around. prin = GetNextSubDomainPrincipal(prin); diff --git a/extensions/permissions/nsPermissionManager.h b/extensions/permissions/nsPermissionManager.h index 5e118a34e9f3..ad6a8ea8066a 100644 --- a/extensions/permissions/nsPermissionManager.h +++ b/extensions/permissions/nsPermissionManager.h @@ -78,11 +78,12 @@ class nsPermissionManager final : public nsIPermissionManager, class PermissionKey { public: static PermissionKey* CreateFromPrincipal(nsIPrincipal* aPrincipal, + bool aForceStripOA, nsresult& aResult); static PermissionKey* CreateFromURI(nsIURI* aURI, nsresult& aResult); static PermissionKey* CreateFromURIAndOriginAttributes( nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, - nsresult& aResult); + bool aForceStripOA, nsresult& aResult); explicit PermissionKey(const nsACString& aOrigin) : mOrigin(aOrigin), mHashCode(mozilla::HashString(aOrigin)) {} @@ -222,11 +223,13 @@ class nsPermissionManager final : public nsIPermissionManager, * https://, or ftp:// schemes are given the default "" Permission Key. * * @param aPrincipal The Principal which the key is to be extracted from. - * @param aPermissionKey A string which will be filled with the permission + * @param aForceStripOA Whether to force stripping the principals origin + * attributes prior to generating the key. + * @param aKey A string which will be filled with the permission * key. */ - static void GetKeyForPrincipal(nsIPrincipal* aPrincipal, - nsACString& aPermissionKey); + static void GetKeyForPrincipal(nsIPrincipal* aPrincipal, bool aForceStripOA, + nsACString& aKey); /** * See `nsIPermissionManager::GetPermissionsWithKey` for more info on @@ -240,11 +243,13 @@ class nsPermissionManager final : public nsIPermissionManager, * nonsensical permission key result. * * @param aOrigin The origin which the key is to be extracted from. - * @param aPermissionKey A string which will be filled with the permission + * @param aForceStripOA Whether to force stripping the origins attributes + * prior to generating the key. + * @param aKey A string which will be filled with the permission * key. */ - static void GetKeyForOrigin(const nsACString& aOrigin, - nsACString& aPermissionKey); + static void GetKeyForOrigin(const nsACString& aOrigin, bool aForceStripOA, + nsACString& aKey); /** * See `nsIPermissionManager::GetPermissionsWithKey` for more info on @@ -361,6 +366,16 @@ class nsPermissionManager final : public nsIPermissionManager, private: virtual ~nsPermissionManager(); + /** + * Get all permissions for a given principal, which should not be isolated + * by user context or private browsing. The principal has its origin + * attributes stripped before perm db lookup. This is currently only affects + * the "cookie" permission. + * @param aPrincipal Used for creating the permission key. + */ + nsresult GetStripPermsForPrincipal(nsIPrincipal* aPrincipal, + nsTArray& aResult); + // NOTE: nullptr can be passed as aType - if it is this function will return // "false" unconditionally. static bool HasDefaultPref(const nsACString& aType) {