Issue #2736 - Part 13: Override page CSP for loads by expanded principals.

Per the CSP specification, content injected by extensions is meant to
be exempt from page CSP. This patch takes care of the most common case
of content injected by extension content scripts, which always have
expanded principals which inherit from the page principal.

To make this easier, de-virtualize BasePrincipal::Kind(), using CTOR
initializers instead.
This commit is contained in:
Moonchild 2025-05-09 22:25:06 +02:00 committed by roytam1
commit 9847e9f759
7 changed files with 42 additions and 27 deletions

View file

@ -343,7 +343,8 @@ OriginAttributes::IsFirstPartyEnabled()
return sFirstPartyIsolation;
}
BasePrincipal::BasePrincipal()
BasePrincipal::BasePrincipal(PrincipalKind aKind)
: mKind(aKind)
{}
BasePrincipal::~BasePrincipal()

View file

@ -251,7 +251,14 @@ public:
class BasePrincipal : public nsJSPrincipals
{
public:
BasePrincipal();
enum PrincipalKind {
eNullPrincipal,
eCodebasePrincipal,
eExpandedPrincipal,
eSystemPrincipal
};
explicit BasePrincipal(PrincipalKind aKind);
enum DocumentDomainConsideration { DontConsiderDocumentDomain, ConsiderDocumentDomain};
bool Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
@ -301,17 +308,19 @@ public:
uint32_t PrivateBrowsingId() const { return mOriginAttributes.mPrivateBrowsingId; }
bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
enum PrincipalKind {
eNullPrincipal,
eCodebasePrincipal,
eExpandedPrincipal,
eSystemPrincipal
};
virtual PrincipalKind Kind() = 0;
PrincipalKind Kind() const { return mKind; }
already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
/**
* Returns true if this principal's CSP should override a document's CSP for
* loads that it triggers. Currently true only for expanded principals which
* subsume the document principal.
*/
bool OverridesCSP(nsIPrincipal* aDocumentPrincipal) {
return mKind == eExpandedPrincipal && Subsumes(aDocumentPrincipal, DontConsiderDocumentDomain);
}
protected:
virtual ~BasePrincipal();
@ -333,6 +342,7 @@ protected:
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
PrincipalOriginAttributes mOriginAttributes;
PrincipalKind mKind;
};
} // namespace mozilla

View file

@ -36,7 +36,9 @@ public:
// This should only be used by deserialization, and the factory constructor.
// Other consumers should use the Create and CreateWithInheritedAttributes
// methods.
nsNullPrincipal() {}
nsNullPrincipal()
: BasePrincipal(eNullPrincipal)
{}
NS_DECL_NSISERIALIZABLE
@ -60,8 +62,6 @@ public:
virtual nsresult GetScriptLocation(nsACString &aStr) override;
PrincipalKind Kind() override { return eNullPrincipal; }
protected:
virtual ~nsNullPrincipal() {}

View file

@ -64,10 +64,11 @@ nsPrincipal::InitializeStatics()
}
nsPrincipal::nsPrincipal()
: mCodebaseImmutable(false)
: BasePrincipal(eCodebasePrincipal)
, mCodebaseImmutable(false)
, mDomainImmutable(false)
, mInitialized(false)
{ }
{}
nsPrincipal::~nsPrincipal()
{
@ -514,6 +515,7 @@ struct OriginComparator
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
const PrincipalOriginAttributes& aAttrs)
: BasePrincipal(eExpandedPrincipal)
{
// We force the principals to be sorted by origin so that nsExpandedPrincipal
// origins can have a canonical form.

View file

@ -46,8 +46,6 @@ public:
*/
static void InitializeStatics();
PrincipalKind Kind() override { return eCodebasePrincipal; }
nsCOMPtr<nsIURI> mDomain;
nsCOMPtr<nsIURI> mCodebase;
// If mCodebaseImmutable is true, mCodebase is non-null and immutable
@ -82,8 +80,6 @@ public:
virtual nsresult GetScriptLocation(nsACString &aStr) override;
nsresult GetOriginInternal(nsACString& aOrigin) override;
PrincipalKind Kind() override { return eExpandedPrincipal; }
protected:
virtual ~nsExpandedPrincipal();

View file

@ -36,7 +36,9 @@ public:
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
nsresult GetOriginInternal(nsACString& aOrigin) override;
nsSystemPrincipal() {}
nsSystemPrincipal()
: BasePrincipal(eSystemPrincipal)
{}
virtual nsresult GetScriptLocation(nsACString &aStr) override;
@ -52,8 +54,6 @@ protected:
{
return true;
}
PrincipalKind Kind() override { return eSystemPrincipal; }
};
#endif // nsSystemPrincipal_h__

View file

@ -140,12 +140,18 @@ CSPService::ShouldLoad(uint32_t aContentType,
return NS_OK;
}
// query the principal of the document; if no document is passed, then
// fall back to using the requestPrincipal (e.g. service workers do not
// pass a document).
// Find a principal to retrieve the CSP from. If we don't have a context node
// (because, for instance, the load originates in a service worker), or the
// requesting principal's CSP overrides our document CSP, use the request
// principal. Otherwise, use the document principal.
nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
nsCOMPtr<nsIPrincipal> principal = node ? node->NodePrincipal()
: aRequestPrincipal;
nsCOMPtr<nsIPrincipal> principal;
if (!node || (aRequestPrincipal &&
BasePrincipal::Cast(aRequestPrincipal)->OverridesCSP(node->NodePrincipal()))) {
principal = aRequestPrincipal;
} else {
principal = node->NodePrincipal();
}
if (!principal) {
// if we can't query a principal, then there is nothing to do.
return NS_OK;