Bug 1536411 - StoragePrincipal - part 1 - Implementation, r=Ehsan

Differential Revision: https://phabricator.services.mozilla.com/D24025

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2019-04-11 16:27:12 +00:00
Родитель 4b6aa5b40f
Коммит 5cfeeda19e
32 изменённых файлов: 369 добавлений и 53 удалений

Просмотреть файл

@ -455,6 +455,28 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain() {
return BasePrincipal::CreateCodebasePrincipal(uri, attrs);
}
already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingFirstPartyDomain(
nsIURI* aURI) {
if (NS_WARN_IF(!IsCodebasePrincipal())) {
return nullptr;
}
OriginAttributes attrs = OriginAttributesRef();
// XXX this is slow. Maybe we should consider to make it faster.
attrs.SetFirstPartyDomain(false, aURI, true /* aForced */);
nsAutoCString originNoSuffix;
nsresult rv = GetOriginNoSuffix(originNoSuffix);
NS_ENSURE_SUCCESS(rv, nullptr);
nsIURI* uri = static_cast<ContentPrincipal*>(this)->mCodebase;
RefPtr<ContentPrincipal> copy = new ContentPrincipal();
rv = copy->Init(uri, attrs, originNoSuffix);
NS_ENSURE_SUCCESS(rv, nullptr);
return copy.forget();
}
extensions::WebExtensionPolicy* BasePrincipal::ContentScriptAddonPolicy() {
if (!Is<ExpandedPrincipal>()) {
return nullptr;

Просмотреть файл

@ -169,6 +169,8 @@ class BasePrincipal : public nsJSPrincipals {
already_AddRefed<BasePrincipal>
CloneStrippingUserContextIdAndFirstPartyDomain();
already_AddRefed<BasePrincipal> CloneForcingFirstPartyDomain(nsIURI* aURI);
// If this is an add-on content script principal, returns its AddonPolicy.
// Otherwise returns null.
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();

Просмотреть файл

@ -38,11 +38,11 @@ void OriginAttributes::InitPrefs() {
}
void OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
nsIURI* aURI) {
nsIURI* aURI, bool aForced) {
bool isFirstPartyEnabled = IsFirstPartyEnabled();
// If the pref is off or this is not a top level load, bail out.
if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
// If the prefs are off or this is not a top level load, bail out.
if ((!isFirstPartyEnabled || !aIsTopLevelDocument) && !aForced) {
return;
}

Просмотреть файл

@ -25,7 +25,8 @@ class OriginAttributes : public dom::OriginAttributesDictionary {
explicit OriginAttributes(const OriginAttributesDictionary& aOther)
: OriginAttributesDictionary(aOther) {}
void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI);
void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI,
bool aForced = false);
void SetFirstPartyDomain(const bool aIsTopLevelDocument,
const nsACString& aDomain);

Просмотреть файл

@ -197,6 +197,7 @@ interface nsIScriptSecurityManager : nsISupports
in nsIURI aTargetURI,
in boolean reportError,
in boolean fromPrivateWindow);
/**
* Get the principal for the given channel. This will typically be the
* channel owner if there is one, and the codebase principal for the
@ -204,6 +205,23 @@ interface nsIScriptSecurityManager : nsISupports
*/
nsIPrincipal getChannelResultPrincipal(in nsIChannel aChannel);
/**
* Get the storage principal for the given channel. This is basically the
* same of getChannelResultPrincipal() execept for trackers, where we
* return a principal with a different OriginAttributes.
*/
nsIPrincipal getChannelResultStoragePrincipal(in nsIChannel aChannel);
/**
* This method does getChannelResultPrincipal() +
* getChannelResultStoragePrincipal().
* This method is mainly done for Document::Reset(). There are no other
* reasons to use this method.
*/
void getChannelResultPrincipals(in nsIChannel aChannel,
out nsIPrincipal aPrincipal,
out nsIPrincipal aStoragePrincipal);
/**
* Temporary API until bug 1220687 is fixed.
*

Просмотреть файл

@ -7,6 +7,7 @@
#include "nsScriptSecurityManager.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "xpcpublic.h"
#include "XPCWrapper.h"
@ -245,6 +246,33 @@ nsresult nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(
/*aIgnoreSandboxing*/ true);
}
NS_IMETHODIMP
nsScriptSecurityManager::GetChannelResultStoragePrincipal(
nsIChannel* aChannel, nsIPrincipal** aPrincipal) {
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = GetChannelResultPrincipal(aChannel, getter_AddRefs(principal),
/*aIgnoreSandboxing*/ false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return StoragePrincipalHelper::Create(aChannel, principal, aPrincipal);
}
NS_IMETHODIMP
nsScriptSecurityManager::GetChannelResultPrincipals(
nsIChannel* aChannel, nsIPrincipal** aPrincipal,
nsIPrincipal** aStoragePrincipal) {
nsresult rv = GetChannelResultPrincipal(aChannel, aPrincipal,
/*aIgnoreSandboxing*/ false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return StoragePrincipalHelper::Create(aChannel, *aPrincipal,
aStoragePrincipal);
}
static void InheritAndSetCSPOnPrincipalIfNeeded(nsIChannel* aChannel,
nsIPrincipal* aPrincipal) {
// loading a data: URI into an iframe, or loading frame[srcdoc] need

Просмотреть файл

@ -1923,23 +1923,32 @@ bool Document::IsVisibleConsideringAncestors() const {
void Document::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIPrincipal> storagePrincipal;
if (aChannel) {
// Note: this code is duplicated in XULDocument::StartDocumentLoad and
// nsScriptSecurityManager::GetChannelResultPrincipal.
// nsScriptSecurityManager::GetChannelResultPrincipals.
// Note: this should match nsDocShell::OnLoadingSite
NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
nsIScriptSecurityManager* securityManager =
nsContentUtils::GetSecurityManager();
if (securityManager) {
securityManager->GetChannelResultPrincipal(aChannel,
getter_AddRefs(principal));
securityManager->GetChannelResultPrincipals(
aChannel, getter_AddRefs(principal),
getter_AddRefs(storagePrincipal));
}
}
principal = MaybeDowngradePrincipal(principal);
bool equal = principal->Equals(storagePrincipal);
ResetToURI(uri, aLoadGroup, principal);
principal = MaybeDowngradePrincipal(principal);
if (equal) {
storagePrincipal = principal;
} else {
storagePrincipal = MaybeDowngradePrincipal(storagePrincipal);
}
ResetToURI(uri, aLoadGroup, principal, storagePrincipal);
// Note that, since mTiming does not change during a reset, the
// navigationStart time remains unchanged and therefore any future new
@ -2031,8 +2040,10 @@ void Document::DisconnectNodeTree() {
}
void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) {
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) {
MOZ_ASSERT(aURI, "Null URI passed to ResetToURI");
MOZ_ASSERT(!!aPrincipal == !!aStoragePrincipal);
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
@ -2062,7 +2073,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
// This ensures that, during teardown, the document and the dying window
// (which already nulled out its document pointer and cached the principal)
// have matching principals.
SetPrincipal(nullptr);
SetPrincipals(nullptr, nullptr);
// Clear the original URI so SetDocumentURI sets it.
mOriginalURI = nullptr;
@ -2110,7 +2121,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
// Now get our new principal
if (aPrincipal) {
SetPrincipal(aPrincipal);
SetPrincipals(aPrincipal, aStoragePrincipal);
} else {
nsIScriptSecurityManager* securityManager =
nsContentUtils::GetSecurityManager();
@ -2130,7 +2141,7 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsresult rv = securityManager->GetLoadContextCodebasePrincipal(
mDocumentURI, loadContext, getter_AddRefs(principal));
if (NS_SUCCEEDED(rv)) {
SetPrincipal(principal);
SetPrincipals(principal, principal);
}
}
}
@ -2793,7 +2804,7 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
if (needNewNullPrincipal) {
principal = NullPrincipal::CreateWithInheritedAttributes(principal);
principal->SetCsp(csp);
SetPrincipal(principal);
SetPrincipals(principal, principal);
}
// ----- Enforce frame-ancestor policy on any applied policies
@ -3017,7 +3028,9 @@ void Document::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
}
}
void Document::SetPrincipal(nsIPrincipal* aNewPrincipal) {
void Document::SetPrincipals(nsIPrincipal* aNewPrincipal,
nsIPrincipal* aNewStoragePrincipal) {
MOZ_ASSERT(!!aNewPrincipal == !!aNewStoragePrincipal);
if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
nsCOMPtr<nsIURI> uri;
aNewPrincipal->GetURI(getter_AddRefs(uri));
@ -3027,6 +3040,7 @@ void Document::SetPrincipal(nsIPrincipal* aNewPrincipal) {
}
}
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
mIntrinsicStoragePrincipal = aNewStoragePrincipal;
#ifdef DEBUG
// Validate that the docgroup is set correctly by calling its getter and
@ -8193,7 +8207,8 @@ nsresult Document::CloneDocHelper(Document* clone) const {
}
clone->mChannel = channel;
if (uri) {
clone->ResetToURI(uri, loadGroup, NodePrincipal());
clone->ResetToURI(uri, loadGroup, NodePrincipal(),
EffectiveStoragePrincipal());
}
clone->SetContainer(mDocumentContainer);
@ -8207,7 +8222,7 @@ nsresult Document::CloneDocHelper(Document* clone) const {
// them.
clone->SetDocumentURI(Document::GetDocumentURI());
clone->SetChromeXHRDocURI(mChromeXHRDocURI);
clone->SetPrincipal(NodePrincipal());
clone->SetPrincipals(NodePrincipal(), EffectiveStoragePrincipal());
clone->mDocumentBaseURI = mDocumentBaseURI;
clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
@ -12829,5 +12844,23 @@ nsICookieSettings* Document::CookieSettings() {
return mCookieSettings;
}
nsIPrincipal* Document::EffectiveStoragePrincipal() const {
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
return NodePrincipal();
}
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForDocument(this);
// Let's use the storage principal only if we need to partition the cookie
// jar. When the permission is granted, access will be different and the
// normal principal will be used.
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
return NodePrincipal();
}
return mIntrinsicStoragePrincipal;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -523,9 +523,15 @@ class Document : public nsINode,
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
}
nsIPrincipal* EffectiveStoragePrincipal() const;
// nsIScriptObjectPrincipal
nsIPrincipal* GetPrincipal() final { return NodePrincipal(); }
nsIPrincipal* GetEffectiveStoragePrincipal() final {
return EffectiveStoragePrincipal();
}
// EventTarget
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
EventListenerManager* GetOrCreateListenerManager() override;
@ -725,10 +731,10 @@ class Document : public nsINode,
void SetReferrer(const nsACString& aReferrer) { mReferrer = aReferrer; }
/**
* Set the principal responsible for this document. Chances are,
* you do not want to be using this.
* Set the principals responsible for this document. Chances are, you do not
* want to be using this.
*/
void SetPrincipal(nsIPrincipal* aPrincipal);
void SetPrincipals(nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal);
/**
* Get the list of ancestor principals for a document. This is the same as
@ -2086,12 +2092,13 @@ class Document : public nsINode,
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
/**
* Reset this document to aURI, aLoadGroup, and aPrincipal. aURI must not be
* null. If aPrincipal is null, a codebase principal based on aURI will be
* used.
* Reset this document to aURI, aLoadGroup, aPrincipal and aStoragePrincipal.
* aURI must not be null. If aPrincipal is null, a codebase principal based
* on aURI will be used.
*/
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal);
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal);
/**
* Set the container (docshell) for this document. Virtual so that
@ -4734,6 +4741,9 @@ class Document : public nsINode,
bool mInRDMPane;
// The principal to use for the storage area of this document.
nsCOMPtr<nsIPrincipal> mIntrinsicStoragePrincipal;
public:
// Needs to be public because the bindings code pokes at it.
js::ExpandoAndGeneration mExpandoAndGeneration;

Просмотреть файл

@ -8226,7 +8226,7 @@ nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForWindow(
// static, public
nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForDocument(
Document* aDoc) {
const Document* aDoc) {
MOZ_ASSERT(aDoc);
if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) {

Просмотреть файл

@ -2995,7 +2995,7 @@ class nsContentUtils {
* the window's extant document has not been set yet. The code in
* StorageAllowedForWindow(), however, will not work in these cases.
*/
static StorageAccess StorageAllowedForDocument(Document* aDoc);
static StorageAccess StorageAllowedForDocument(const Document* aDoc);
/*
* Checks if storage should be allowed for a new window with the given

Просмотреть файл

@ -1128,6 +1128,7 @@ void nsGlobalWindowInner::FreeInnerObjects() {
if (mDoc) {
// Remember the document's principal and URI.
mDocumentPrincipal = mDoc->NodePrincipal();
mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
mDocumentURI = mDoc->GetDocumentURI();
mDocBaseURI = mDoc->GetDocBaseURI();
@ -1357,6 +1358,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
@ -1460,6 +1462,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
@ -2048,6 +2051,29 @@ nsIPrincipal* nsGlobalWindowInner::GetPrincipal() {
return nullptr;
}
nsIPrincipal* nsGlobalWindowInner::GetEffectiveStoragePrincipal() {
if (mDoc) {
// If we have a document, get the principal from the document
return mDoc->EffectiveStoragePrincipal();
}
if (mDocumentStoragePrincipal) {
return mDocumentStoragePrincipal;
}
// If we don't have a storage principal and we don't have a document we ask
// the parent window for the storage principal.
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
do_QueryInterface(GetParentInternal());
if (objPrincipal) {
return objPrincipal->GetEffectiveStoragePrincipal();
}
return nullptr;
}
//*****************************************************************************
// nsGlobalWindowInner::nsIDOMWindow
//*****************************************************************************
@ -2795,10 +2821,9 @@ bool nsGlobalWindowInner::MayResolve(jsid aId) {
return WebIDLGlobalNameHash::MayResolve(aId);
}
void nsGlobalWindowInner::GetOwnPropertyNames(JSContext* aCx,
JS::MutableHandleVector<jsid> aNames,
bool aEnumerableOnly,
ErrorResult& aRv) {
void nsGlobalWindowInner::GetOwnPropertyNames(
JSContext* aCx, JS::MutableHandleVector<jsid> aNames, bool aEnumerableOnly,
ErrorResult& aRv) {
if (aEnumerableOnly) {
// The names we would return from here get defined on the window via one of
// two codepaths. The ones coming from the WebIDLGlobalNameHash will end up

Просмотреть файл

@ -260,6 +260,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal() override;
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override;
// nsIDOMWindow
NS_DECL_NSIDOMWINDOW
@ -1294,6 +1296,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
RefPtr<mozilla::dom::VisualViewport> mVisualViewport;
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
// mTabChild is only ever populated in the content process.
nsCOMPtr<nsITabChild> mTabChild;

Просмотреть файл

@ -476,8 +476,9 @@ class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
* "proxy" is the WindowProxy object involved. It may not be same-compartment
* with cx.
*/
bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::MutableHandleVector<jsid> props) const override;
bool getOwnEnumerablePropertyKeys(
JSContext* cx, JS::Handle<JSObject*> proxy,
JS::MutableHandleVector<jsid> props) const override;
/**
* Hook used by SpiderMonkey to implement Object.prototype.toString.
@ -733,9 +734,9 @@ bool nsOuterWindowProxy::definePropertySameOrigin(
return true;
}
bool nsOuterWindowProxy::ownPropertyKeys(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::MutableHandleVector<jsid> props) const {
bool nsOuterWindowProxy::ownPropertyKeys(
JSContext* cx, JS::Handle<JSObject*> proxy,
JS::MutableHandleVector<jsid> props) const {
// Just our indexed stuff followed by our "normal" own property names.
if (!AppendIndexedPropertyNames(proxy, props)) {
return false;
@ -938,7 +939,8 @@ bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
}
bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::MutableHandleVector<jsid> props) const {
JSContext* cx, JS::Handle<JSObject*> proxy,
JS::MutableHandleVector<jsid> props) const {
// We could just stop overring getOwnEnumerablePropertyKeys and let our
// superclasses deal (by falling back on the BaseProxyHandler implementation
// that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
@ -1401,6 +1403,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
// Traverse stuff from nsPIDOMWindow
@ -1427,6 +1430,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
// Unlink stuff from nsPIDOMWindow
@ -1894,6 +1898,8 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
bool aForceReuseInnerWindow) {
MOZ_ASSERT(mDocumentPrincipal == nullptr,
"mDocumentPrincipal prematurely set!");
MOZ_ASSERT(mDocumentStoragePrincipal == nullptr,
"mDocumentStoragePrincipal prematurely set!");
MOZ_ASSERT(aDocument);
// Bail out early if we're in process of closing down the window.
@ -2446,6 +2452,7 @@ void nsGlobalWindowOuter::DetachFromDocShell() {
// Remember the document's principal and URI.
mDocumentPrincipal = mDoc->NodePrincipal();
mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
mDocumentURI = mDoc->GetDocumentURI();
// Release our document reference
@ -2761,6 +2768,29 @@ nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
return nullptr;
}
nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
if (mDoc) {
// If we have a document, get the principal from the document
return mDoc->EffectiveStoragePrincipal();
}
if (mDocumentStoragePrincipal) {
return mDocumentStoragePrincipal;
}
// If we don't have a storage principal and we don't have a document we ask
// the parent window for the storage principal.
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
do_QueryInterface(GetParentInternal());
if (objPrincipal) {
return objPrincipal->GetEffectiveStoragePrincipal();
}
return nullptr;
}
//*****************************************************************************
// nsGlobalWindowOuter::nsIDOMWindow
//*****************************************************************************

Просмотреть файл

@ -247,6 +247,8 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal() override;
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override;
// nsIDOMWindow
NS_DECL_NSIDOMWINDOW
@ -1098,6 +1100,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
RefPtr<mozilla::dom::Storage> mLocalStorage;
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
#ifdef DEBUG
uint32_t mSerial;

Просмотреть файл

@ -26,6 +26,8 @@ class nsIScriptObjectPrincipal : public nsISupports {
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTOBJECTPRINCIPAL_IID)
virtual nsIPrincipal* GetPrincipal() = 0;
virtual nsIPrincipal* GetEffectiveStoragePrincipal() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptObjectPrincipal,

Просмотреть файл

@ -222,10 +222,11 @@ void nsHTMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
}
void nsHTMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) {
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) {
mLoadFlags = nsIRequest::LOAD_NORMAL;
Document::ResetToURI(aURI, aLoadGroup, aPrincipal);
Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aStoragePrincipal);
mImages = nullptr;
mApplets = nullptr;

Просмотреть файл

@ -56,7 +56,8 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
// Document
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) override;
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) override;
virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,

Просмотреть файл

@ -15,6 +15,7 @@
* https://wicg.github.io/feature-policy/#policy
*/
interface Principal;
interface WindowProxy;
interface nsISupports;
interface URI;
@ -358,6 +359,10 @@ partial interface Document {
[CEReactions, NewObject, Throws, Func="IsChromeOrXBL"]
Element createXULElement(DOMString localName, optional (ElementCreationOptions or DOMString) options);
// The principal to use for the storage area of this document
[ChromeOnly]
readonly attribute Principal effectiveStoragePrincipal;
// Touch bits
// XXXbz I can't find the sane spec for this stuff, so just cribbing
// from our xpidl for now.

Просмотреть файл

@ -129,7 +129,7 @@ nsresult NS_NewDOMDocument(Document** aInstancePtrResult,
d->SetLoadedAsData(aLoadedAsData);
d->SetDocumentURI(aDocumentURI);
// Must set the principal first, since SetBaseURI checks it.
d->SetPrincipal(aPrincipal);
d->SetPrincipals(aPrincipal, aPrincipal);
d->SetBaseURI(aBaseURI);
// We need to set the script handling object after we set the principal such
@ -252,14 +252,15 @@ void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
}
void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) {
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) {
if (mChannelIsPending) {
StopDocumentLoad();
mChannel->Cancel(NS_BINDING_ABORTED);
mChannelIsPending = false;
}
Document::ResetToURI(aURI, aLoadGroup, aPrincipal);
Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aStoragePrincipal);
}
bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
@ -274,6 +275,7 @@ bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
nsCOMPtr<Document> callingDoc = GetEntryDocument();
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
nsCOMPtr<nsIPrincipal> storagePrincipal = EffectiveStoragePrincipal();
// The callingDoc's Principal and doc's Principal should be the same
if (callingDoc && (callingDoc->NodePrincipal() != principal)) {
@ -370,7 +372,7 @@ bool XMLDocument::Load(const nsAString& aUrl, CallerType aCallerType,
loadGroup = callingDoc->GetDocumentLoadGroup();
}
ResetToURI(uri, loadGroup, principal);
ResetToURI(uri, loadGroup, principal, storagePrincipal);
mListenerManager = elm;

Просмотреть файл

@ -26,7 +26,8 @@ class XMLDocument : public Document {
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) override;
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) override;
virtual void SetSuppressParserErrorElement(bool aSuppress) override;
virtual bool SuppressParserErrorElement() override;

Просмотреть файл

@ -46,6 +46,7 @@ void URIUtils::resolveHref(const nsAString& href, const nsAString& base,
void URIUtils::ResetWithSource(Document* aNewDoc, nsINode* aSourceNode) {
nsCOMPtr<Document> sourceDoc = aSourceNode->OwnerDoc();
nsIPrincipal* sourcePrincipal = sourceDoc->NodePrincipal();
nsIPrincipal* sourceStoragePrincipal = sourceDoc->EffectiveStoragePrincipal();
// Copy the channel and loadgroup from the source document.
nsCOMPtr<nsILoadGroup> loadGroup = sourceDoc->GetDocumentLoadGroup();
@ -66,7 +67,7 @@ void URIUtils::ResetWithSource(Document* aNewDoc, nsINode* aSourceNode) {
}
aNewDoc->Reset(channel, loadGroup);
aNewDoc->SetPrincipal(sourcePrincipal);
aNewDoc->SetPrincipals(sourcePrincipal, sourceStoragePrincipal);
aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI());
// Copy charset

Просмотреть файл

@ -193,7 +193,8 @@ void XULDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
}
void XULDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) {
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) {
MOZ_ASSERT_UNREACHABLE("ResetToURI");
}
@ -242,10 +243,21 @@ nsresult XULDocument::StartDocumentLoad(const char* aCommand,
// Get the document's principal
nsCOMPtr<nsIPrincipal> principal;
nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
mChannel, getter_AddRefs(principal));
nsCOMPtr<nsIPrincipal> storagePrincipal;
rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipals(
mChannel, getter_AddRefs(principal), getter_AddRefs(storagePrincipal));
NS_ENSURE_SUCCESS(rv, rv);
bool equal = principal->Equals(storagePrincipal);
principal = MaybeDowngradePrincipal(principal);
SetPrincipal(principal);
if (equal) {
storagePrincipal = principal;
} else {
storagePrincipal = MaybeDowngradePrincipal(storagePrincipal);
}
SetPrincipals(principal, storagePrincipal);
ResetStylesheetsToURI(mDocumentURI);

Просмотреть файл

@ -59,7 +59,8 @@ class XULDocument final : public XMLDocument {
// Document interface
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override;
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
nsIPrincipal* aPrincipal) override;
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal) override;
virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* channel,
nsILoadGroup* aLoadGroup,

Просмотреть файл

@ -29,6 +29,10 @@ class BackstagePass : public nsIGlobalObject,
virtual nsIPrincipal* GetPrincipal() override { return mPrincipal; }
virtual nsIPrincipal* GetEffectiveStoragePrincipal() override {
return nullptr;
}
virtual JSObject* GetGlobalJSObject() override;
void ForgetGlobalObject() { mWrapper = nullptr; }

Просмотреть файл

@ -45,6 +45,8 @@ class SandboxPrivate : public nsIGlobalObject,
nsIPrincipal* GetPrincipal() override { return mPrincipal; }
nsIPrincipal* GetEffectiveStoragePrincipal() override { return nullptr; }
JSObject* GetGlobalJSObject() override { return GetWrapper(); }
void ForgetGlobalObject(JSObject* obj) { ClearWrapper(obj); }

Просмотреть файл

@ -277,7 +277,7 @@ already_AddRefed<Document> nsContentDLF::CreateBlankDocument(
if (!uri) {
return nullptr;
}
blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal);
blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal, aPrincipal);
blankDoc->SetContainer(aContainer);
// add some simple content structure

Просмотреть файл

@ -2233,6 +2233,12 @@ VARCACHE_PREF(
RelaxedAtomicBool, false
)
VARCACHE_PREF(
"privacy.storagePrincipal.enabledForTrackers",
privacy_storagePrincipal_enabledForTrackers,
RelaxedAtomicBool, false
)
// Password protection
VARCACHE_PREF(
"browser.safebrowsing.passwords.enabled",

Просмотреть файл

@ -189,6 +189,12 @@ LoadInfo::LoadInfo(
!nsContentUtils::IsInPrivateBrowsing(doc))) {
mTopLevelStorageAreaPrincipal = innerWindow->GetPrincipal();
}
// If this is the first level iframe, innerWindow is our top-level
// principal.
if (!mTopLevelPrincipal) {
mTopLevelPrincipal = innerWindow->GetPrincipal();
}
}
mDocumentHasLoaded = innerWindow->IsDocumentLoaded();

Просмотреть файл

@ -84,7 +84,8 @@ PrototypeDocumentParser::Parse(nsIURI* aURL, nsIRequestObserver* aListener,
mCurrentPrototype = proto;
// Set up the right principal on the document.
mDocument->SetPrincipal(proto->DocumentPrincipal());
mDocument->SetPrincipals(proto->DocumentPrincipal(),
proto->DocumentPrincipal());
} else {
// It's just a vanilla document load. Create a parser to deal
// with the stream n' stuff.
@ -185,7 +186,7 @@ nsresult PrototypeDocumentParser::PrepareToLoadPrototype(
nsXULPrototypeCache::GetInstance()->PutPrototype(mCurrentPrototype);
}
mDocument->SetPrincipal(aDocumentPrincipal);
mDocument->SetPrincipals(aDocumentPrincipal, aDocumentPrincipal);
// Create a XUL content sink, a parser, and kick off a load for
// the document.

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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/. */
#include "StoragePrincipalHelper.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs.h"
#include "nsContentUtils.h"
#include "nsIHttpChannel.h"
namespace mozilla {
// static
nsresult StoragePrincipalHelper::Create(nsIChannel* aChannel,
nsIPrincipal* aPrincipal,
nsIPrincipal** aStoragePrincipal) {
MOZ_ASSERT(aChannel);
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aStoragePrincipal);
auto scopeExit = MakeScopeExit([&] {
nsCOMPtr<nsIPrincipal> storagePrincipal = aPrincipal;
storagePrincipal.forget(aStoragePrincipal);
});
if (!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
return NS_OK;
}
// Let's use the storage principal only if we need to partition the cookie
// jar.
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForChannel(aChannel);
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny) {
return NS_OK;
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (!httpChannel) {
return NS_OK;
}
MOZ_ASSERT(httpChannel->IsThirdPartyTrackingResource());
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsIPrincipal> toplevelPrincipal = loadInfo->GetTopLevelPrincipal();
if (!toplevelPrincipal) {
return NS_OK;
}
nsCOMPtr<nsIURI> principalURI;
nsresult rv = toplevelPrincipal->GetURI(getter_AddRefs(principalURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
scopeExit.release();
nsCOMPtr<nsIPrincipal> storagePrincipal =
BasePrincipal::Cast(aPrincipal)
->CloneForcingFirstPartyDomain(principalURI);
storagePrincipal.forget(aStoragePrincipal);
return NS_OK;
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- 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 mozilla_StoragePrincipalHelper_h
#define mozilla_StoragePrincipalHelper_h
class nsIChannel;
class nsIPrincipal;
namespace mozilla {
class StoragePrincipalHelper final {
public:
static nsresult Create(nsIChannel* aChannel, nsIPrincipal* aPrincipal,
nsIPrincipal** aStoragePrincipal);
};
} // namespace mozilla
#endif // mozilla_StoragePrincipalHelper_h

Просмотреть файл

@ -9,10 +9,12 @@ with Files('**'):
EXPORTS.mozilla = [
'AntiTrackingCommon.h',
'StoragePrincipalHelper.h',
]
UNIFIED_SOURCES += [
'AntiTrackingCommon.cpp',
'StoragePrincipalHelper.cpp',
]
LOCAL_INCLUDES += [