diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 1e55928597dc..cb33a0579f78 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -12,6 +12,7 @@ #endif #include "nsIAddonPolicyService.h" #include "nsIContentSecurityPolicy.h" +#include "nsIEffectiveTLDService.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" @@ -100,7 +101,9 @@ NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aA } void -NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs) +NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs, + const bool aIsTopLevelDocument, + nsIURI* aURI) { mAppId = aAttrs.mAppId; mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; @@ -113,7 +116,24 @@ NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes // mSignedPkg accordingly by mSignedPkgInBrowser mPrivateBrowsingId = aAttrs.mPrivateBrowsingId; - mFirstPartyDomain = aAttrs.mFirstPartyDomain; + + bool isFirstPartyEnabled = IsFirstPartyEnabled(); + + // When the pref is on, we also compute the firstPartyDomain attribute + // if this is for top-level document. + if (isFirstPartyEnabled && aIsTopLevelDocument) { + nsCOMPtr tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); + if (!tldService) { + return; + } + + nsAutoCString baseDomain; + tldService->GetBaseDomain(aURI, 0, baseDomain); + mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain); + } else { + mFirstPartyDomain = aAttrs.mFirstPartyDomain; + } } void @@ -326,6 +346,20 @@ OriginAttributes::SetFromGenericAttributes(const GenericOriginAttributes& aAttrs mFirstPartyDomain = aAttrs.mFirstPartyDomain; } +bool +OriginAttributes::IsFirstPartyEnabled() +{ + // Cache the privacy.firstparty.isolate pref. + static bool sFirstPartyIsolation = false; + static bool sCachedFirstPartyPref = false; + if (!sCachedFirstPartyPref) { + sCachedFirstPartyPref = true; + Preferences::AddBoolVarCache(&sFirstPartyIsolation, "privacy.firstparty.isolate"); + } + + return sFirstPartyIsolation; +} + BasePrincipal::BasePrincipal() {} diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 972b2e8242b4..4eeb8eff3d45 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -66,6 +66,9 @@ protected: OriginAttributes() {} explicit OriginAttributes(const OriginAttributesDictionary& aOther) : OriginAttributesDictionary(aOther) {} + + // check if "privacy.firstparty.isolate" is enabled. + bool IsFirstPartyEnabled(); }; class PrincipalOriginAttributes; @@ -137,7 +140,11 @@ public: // is made. void InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs); - void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs); + // Inheriting OriginAttributes from a docshell when loading a top-level + // document. + void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs, + const bool aIsTopLevelDocument = false, + nsIURI* aURI = nullptr); }; // For operating on OriginAttributes not associated with any data structure. diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 0683eb91d99c..59cae64ca492 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -436,37 +436,16 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel, nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr loadContext; - NS_QueryNotificationCallbacks(aChannel, loadContext); - nsCOMPtr loadInfo; aChannel->GetLoadInfo(getter_AddRefs(loadInfo)); - nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_INVALID; - if (loadInfo) { - contentPolicyType = loadInfo->GetExternalContentPolicyType(); - } + // Inherit the origin attributes from loadInfo. + // If this is a top-level document load, the origin attributes of the + // loadInfo will be set from nsDocShell::DoURILoad. + // For subresource loading, the origin attributes of the loadInfo is from + // its loadingPrincipal. PrincipalOriginAttributes attrs; - if (nsIContentPolicy::TYPE_DOCUMENT == contentPolicyType || - nsIContentPolicy::TYPE_SUBDOCUMENT == contentPolicyType) { - // If it's document or sub-document, inherit originAttributes from - // the document. - if (loadContext) { - DocShellOriginAttributes docShellAttrs; - loadContext->GetOriginAttributes(docShellAttrs); - attrs.InheritFromDocShellToDoc(docShellAttrs, uri); - } - } else { - // Inherit origin attributes from loading principal if any. - nsCOMPtr loadingPrincipal; - if (loadInfo) { - loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal)); - } - if (loadingPrincipal) { - attrs = BasePrincipal::Cast(loadingPrincipal)->OriginAttributesRef(); - } - } - + attrs.InheritFromNecko(loadInfo->GetOriginAttributes()); rv = MaybeSetAddonIdFromURI(attrs, uri); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 001f20825f99..aca523f80b0a 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -10812,7 +10812,10 @@ nsDocShell::DoURILoad(nsIURI* aURI, // OriginAttributes of the parent document. Or in case there isn't a // parent document. NeckoOriginAttributes neckoAttrs; - neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes()); + bool isTopLevelDoc = aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT && + mItemType == typeContent && + !GetIsMozBrowserOrApp(); + neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes(), isTopLevelDoc, aURI); rv = loadInfo->SetOriginAttributes(neckoAttrs); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 0ca64f468ae0..17d24c2f45a3 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -2098,6 +2098,38 @@ nsFrameLoader::MaybeCreateDocShell() attrs = nsDocShell::Cast(docShell)->GetOriginAttributes(); } + // Inherit origin attributes from parent document if + // 1. It's in a content docshell. + // 2. its nodePrincipal is not a SystemPrincipal. + // 3. It's not a mozbrowser nor mozapp frame. + // + // For example, firstPartyDomain is computed from top-level document, it + // doesn't exist in the top-level docshell. + if (parentType == nsIDocShellTreeItem::typeContent && + !nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) && + !OwnerIsMozBrowserOrAppFrame()) { + PrincipalOriginAttributes poa = BasePrincipal::Cast(doc->NodePrincipal())->OriginAttributesRef(); + + // Assert on the firstPartyDomain from top-level docshell should be empty + if (mIsTopLevelContent) { + MOZ_ASSERT(attrs.mFirstPartyDomain.IsEmpty(), + "top-level docshell shouldn't have firstPartyDomain attribute."); + } + + // So far we want to make sure InheritFromDocToChildDocShell doesn't override + // any other origin attribute than firstPartyDomain. + MOZ_ASSERT(attrs.mAppId == poa.mAppId, + "docshell and document should have the same appId attribute."); + MOZ_ASSERT(attrs.mUserContextId == poa.mUserContextId, + "docshell and document should have the same userContextId attribute."); + MOZ_ASSERT(attrs.mInIsolatedMozBrowser == poa.mInIsolatedMozBrowser, + "docshell and document should have the same inIsolatedMozBrowser attribute."); + MOZ_ASSERT(attrs.mPrivateBrowsingId == poa.mPrivateBrowsingId, + "docshell and document should have the same privateBrowsingId attribute."); + + attrs.InheritFromDocToChildDocShell(poa); + } + if (OwnerIsAppFrame()) { // You can't be both an app and a browser frame. MOZ_ASSERT(!OwnerIsMozBrowserFrame()); diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 6b0dd421e090..40cd99334069 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -148,6 +148,7 @@ NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized, aAttrs.mSignedPkg = aSerialized.mOriginAttributes.mSignedPkg; aAttrs.mUserContextId = aSerialized.mOriginAttributes.mUserContextId; aAttrs.mPrivateBrowsingId = aSerialized.mOriginAttributes.mPrivateBrowsingId; + aAttrs.mFirstPartyDomain = aSerialized.mOriginAttributes.mFirstPartyDomain; return nullptr; }