Commit 88ab085e authored by Csoregi Natalia's avatar Csoregi Natalia
Browse files

Backed out 5 changesets (bug 1624269) for browser-chrome failures on...

Backed out 5 changesets (bug 1624269) for browser-chrome failures on browser_storageAccessWithHeuristics.js. CLOSED TREE

Backed out changeset 59cdba115447 (bug 1624269)
Backed out changeset 23b5c53f4be8 (bug 1624269)
Backed out changeset be697a5bc0fd (bug 1624269)
Backed out changeset 81420bca683c (bug 1624269)
Backed out changeset 599db5acefe1 (bug 1624269)
parent 2cafee96
......@@ -16204,7 +16204,7 @@ bool Document::HasStoragePermission() {
// it is set in the parent process, so we need to check the cache
// to see if the permission is granted afterwards.
nsPIDOMWindowInner* inner = GetInnerWindow();
if (inner && inner->HasStorageAccessGranted()) {
if (ContentBlocking::HasStorageAccessGranted(inner)) {
return true;
}
 
......
......@@ -7305,14 +7305,27 @@ const nsIGlobalObject* nsPIDOMWindowInner::AsGlobal() const {
return nsGlobalWindowInner::Cast(this);
}
void nsPIDOMWindowInner::SaveStorageAccessGranted() {
mStorageAccessGranted = true;
void nsPIDOMWindowInner::SaveStorageAccessGranted(
const nsACString& aPermissionKey) {
if (!HasStorageAccessGranted(aPermissionKey)) {
mStorageAccessGranted.AppendElement(aPermissionKey);
}
nsGlobalWindowInner::Cast(this)->ClearActiveStoragePrincipal();
}
void nsGlobalWindowInner::ClearActiveStoragePrincipal() {
Document* doc = GetExtantDoc();
if (doc) {
doc->ClearActiveStoragePrincipal();
}
nsGlobalWindowInner::Cast(this)->StorageAccessGranted();
CallOnInProcessChildren(&nsGlobalWindowInner::ClearActiveStoragePrincipal);
}
bool nsPIDOMWindowInner::HasStorageAccessGranted() {
return mStorageAccessGranted;
bool nsPIDOMWindowInner::HasStorageAccessGranted(
const nsACString& aPermissionKey) {
return mStorageAccessGranted.Contains(aPermissionKey);
}
nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter* aOuterWindow,
......@@ -7335,7 +7348,6 @@ nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter* aOuterWindow,
mNumOfIndexedDBDatabases(0),
mNumOfOpenWebSockets(0),
mEvent(nullptr),
mStorageAccessGranted(false),
mWindowGlobalChild(aActor) {
MOZ_ASSERT(aOuterWindow);
mBrowsingContext = aOuterWindow->GetBrowsingContext();
......
......@@ -307,6 +307,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
nsresult PostHandleEvent(mozilla::EventChainPostVisitor& aVisitor) override;
void ClearActiveStoragePrincipal();
void Suspend();
void Resume();
virtual bool IsSuspended() const override;
......
......@@ -17,6 +17,8 @@
#include "nsHistory.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorageManager.h"
#include "nsIPermission.h"
#include "nsIPermissionManager.h"
#include "nsISecureBrowserUI.h"
#include "nsIWebProgressListener.h"
#include "mozilla/AntiTrackingUtils.h"
......@@ -1465,6 +1467,11 @@ nsGlobalWindowOuter::~nsGlobalWindowOuter() {
nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
if (ac) ac->RemoveWindowAsListener(this);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, PERM_CHANGE_NOTIFICATION);
}
nsLayoutStatics::Release();
}
......@@ -1536,6 +1543,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMChromeWindow, IsChromeWindow())
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowOuter)
......@@ -6845,6 +6853,49 @@ nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
return rv;
}
//*****************************************************************************
// nsGlobalWindowOuter::nsIObserver
//*****************************************************************************
NS_IMETHODIMP
nsGlobalWindowOuter::Observe(nsISupports* aSupports, const char* aTopic,
const char16_t* aData) {
if (!nsCRT::strcmp(aTopic, PERM_CHANGE_NOTIFICATION)) {
nsCOMPtr<nsIPermission> permission = do_QueryInterface(aSupports);
if (!permission) {
return NS_OK;
}
nsIPrincipal* principal = GetPrincipal();
if (!principal) {
return NS_OK;
}
if (!AntiTrackingUtils::IsStorageAccessPermission(permission, principal)) {
return NS_OK;
}
if (!nsCRT::strcmp(aData, u"deleted")) {
// The storage access permission was deleted.
mHasStorageAccess = false;
return NS_OK;
}
if (!nsCRT::strcmp(aData, u"added") || !nsCRT::strcmp(aData, u"changed")) {
// The storage access permission was granted or modified.
uint32_t expireType = 0;
int64_t expireTime = 0;
MOZ_ALWAYS_SUCCEEDS(permission->GetExpireType(&expireType));
MOZ_ALWAYS_SUCCEEDS(permission->GetExpireTime(&expireTime));
if ((expireType == nsIPermissionManager::EXPIRE_TIME &&
expireTime >= PR_Now() / 1000) ||
(expireType == nsIPermissionManager::EXPIRE_SESSION &&
expireTime != 0)) {
// Permission hasn't expired yet.
mHasStorageAccess = true;
return NS_OK;
}
}
}
return NS_OK;
}
bool nsGlobalWindowOuter::IsSuspended() const {
MOZ_ASSERT(NS_IsMainThread());
// No inner means we are effectively suspended
......@@ -7569,6 +7620,15 @@ already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
window->SetDocShell(aDocShell);
window->InitWasOffline();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
// Delay calling AddObserver until we hit the event loop, in case we may be
// in the middle of modifying the observer list somehow.
NS_DispatchToMainThread(
NS_NewRunnableFunction("PermChangeDelayRunnable", [obs, window] {
obs->AddObserver(window, PERM_CHANGE_NOTIFICATION, true);
}));
}
return window.forget();
}
......
......@@ -26,6 +26,7 @@
#include "nsIBrowserDOMWindow.h"
#include "nsIInterfaceRequestor.h"
#include "nsIDOMChromeWindow.h"
#include "nsIObserver.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "mozilla/EventListenerManager.h"
......@@ -162,7 +163,8 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
public nsIScriptObjectPrincipal,
public nsSupportsWeakReference,
public nsIInterfaceRequestor,
public PRCListStr {
public PRCListStr,
public nsIObserver {
public:
typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindowOuter*>
OuterWindowByIdTable;
......@@ -350,6 +352,9 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
// nsIObserver
NS_DECL_NSIOBSERVER
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> IndexedGetterOuter(
uint32_t aIndex);
......
......@@ -555,9 +555,9 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
virtual nsISerialEventTarget* EventTargetFor(
mozilla::TaskCategory aCategory) const = 0;
void SaveStorageAccessGranted();
void SaveStorageAccessGranted(const nsACString& aPermissionKey);
bool HasStorageAccessGranted();
bool HasStorageAccessGranted(const nsACString& aPermissionKey);
nsIPrincipal* GetDocumentContentBlockingAllowListPrincipal() const;
......@@ -651,11 +651,10 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
// the event object alive.
mozilla::dom::Event* mEvent;
// A boolean flag indicating whether storage access is granted for the
// current window. These are also set as permissions, but it could happen
// that we need to access them synchronously in this context, and for
// this, we need a copy here.
bool mStorageAccessGranted;
// This is a list of storage access granted for the current window. These are
// also set as permissions, but it could happen that we need to access them
// synchronously in this context, and for this, we need a copy here.
nsTArray<nsCString> mStorageAccessGranted;
// The WindowGlobalChild actor for this window.
//
......
......@@ -67,7 +67,7 @@ child:
async DispatchSecurityPolicyViolation(nsString aViolationEventJSON);
async SaveStorageAccessGranted();
async SaveStorageAccessGranted(nsCString aPermissionKey);
both:
async RawMessage(JSActorMessageMeta aMetadata, ClonedMessageData aData,
......
......@@ -453,18 +453,25 @@ mozilla::ipc::IPCResult WindowGlobalChild::RecvGetSecurityInfo(
return IPC_OK();
}
mozilla::ipc::IPCResult WindowGlobalChild::RecvSaveStorageAccessGranted() {
nsCOMPtr<nsPIDOMWindowInner> inner = GetWindowGlobal();
if (inner) {
inner->SaveStorageAccessGranted();
mozilla::ipc::IPCResult WindowGlobalChild::RecvSaveStorageAccessGranted(
const nsCString& aPermissionKey) {
nsCOMPtr<nsPIDOMWindowInner> window = GetWindowGlobal();
if (!window) {
return IPC_OK();
}
nsCOMPtr<nsPIDOMWindowOuter> outer =
nsPIDOMWindowOuter::GetFromCurrentInner(inner);
if (outer) {
nsGlobalWindowOuter::Cast(outer)->SetHasStorageAccess(true);
#ifdef DEBUG
nsAutoCString trackingOrigin;
nsCOMPtr<nsIPrincipal> principal = DocumentPrincipal();
if (principal && NS_SUCCEEDED(principal->GetOriginNoSuffix(trackingOrigin))) {
nsAutoCString permissionKey;
AntiTrackingUtils::CreateStoragePermissionKey(trackingOrigin,
permissionKey);
MOZ_ASSERT(permissionKey == aPermissionKey);
}
#endif
window->SaveStorageAccessGranted(aPermissionKey);
return IPC_OK();
}
......
......@@ -144,7 +144,8 @@ class WindowGlobalChild final : public WindowGlobalActor,
mozilla::ipc::IPCResult RecvGetSecurityInfo(
GetSecurityInfoResolver&& aResolve);
mozilla::ipc::IPCResult RecvSaveStorageAccessGranted();
mozilla::ipc::IPCResult RecvSaveStorageAccessGranted(
const nsCString& aPermissionKey);
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
......
......@@ -59,6 +59,18 @@ bool GetTopLevelWindowId(BrowsingContext* aParentContext, uint32_t aBehavior,
return aTopLevelInnerWindowId != 0;
}
bool GetTrackingOrigin(nsGlobalWindowInner* a3rdPartyTrackingWindow,
nsACString& aTrackingOrigin) {
nsCOMPtr<nsIPrincipal> trackingPrincipal =
a3rdPartyTrackingWindow->GetPrincipal();
if (NS_WARN_IF(!trackingPrincipal)) {
return false;
}
return !NS_WARN_IF(
NS_FAILED(trackingPrincipal->GetOriginNoSuffix(aTrackingOrigin)));
}
// This internal method returns ACCESS_DENY if the access is denied,
// ACCESS_DEFAULT if unknown, some other access code if granted.
uint32_t CheckCookiePermissionForPrincipal(
......@@ -546,8 +558,8 @@ ContentBlocking::CompleteAllowAccessFor(
ContentBlockingNotifier::StorageAccessGrantedReason aReason) {
MOZ_ASSERT(aParentContext->IsInProcess());
// Let's inform the other windows having the same tracking origin about
// the stroage permission is granted.
// Let's store the permission in the current parent window and other
// windows having the same tracking origin.
ContentBlocking::UpdateAllowAccessOnCurrentProcess(aParentContext,
aTrackingOrigin);
......@@ -556,7 +568,7 @@ ContentBlocking::CompleteAllowAccessFor(
AntiTrackingUtils::GetInnerWindow(aParentContext);
MOZ_ASSERT(parentInner);
nsGlobalWindowInner::Cast(parentInner)->SaveStorageAccessGranted();
nsGlobalWindowInner::Cast(parentInner)->StorageAccessGranted();
// Theoratically this can be done in the parent process. But right now,
// we need the channel while notifying content blocking events, and
......@@ -667,11 +679,57 @@ ContentBlocking::SaveAccessForOriginOnParentProcess(
return ParentAccessGrantPromise::CreateAndResolve(rv, __func__);
}
/* static */
bool ContentBlocking::HasStorageAccessGranted(nsPIDOMWindowInner* aWindow) {
if (!aWindow) {
return false;
}
nsAutoCString trackingOrigin;
if (!GetTrackingOrigin(nsGlobalWindowInner::Cast(aWindow), trackingOrigin)) {
LOG(("Failed to obtain the the tracking origin"));
return false;
}
nsAutoCString permissionKey;
AntiTrackingUtils::CreateStoragePermissionKey(trackingOrigin, permissionKey);
return ContentBlocking::HasStorageAccessGranted(aWindow->GetBrowsingContext(),
permissionKey);
}
/* static */
bool ContentBlocking::HasStorageAccessGranted(
BrowsingContext* aBrowsingContext, const nsACString& aPermissionKey) {
MOZ_ASSERT(aBrowsingContext);
bool useRemoteSubframes;
aBrowsingContext->GetUseRemoteSubframes(&useRemoteSubframes);
// For non-fission, the permission is stored in the top-level window.
// For fission, the permission is stored in the tracking window.
nsCOMPtr<nsPIDOMWindowInner> inner;
if (useRemoteSubframes) {
inner = AntiTrackingUtils::GetInnerWindow(aBrowsingContext);
} else {
inner = AntiTrackingUtils::GetInnerWindow(aBrowsingContext->Top());
}
if (!inner) {
return false;
}
return inner->HasStorageAccessGranted(aPermissionKey);
}
// There are two methods to handle permisson update:
// 1. UpdateAllowAccessOnCurrentProcess
// 2. UpdateAllowAccessOnParentProcess
//
// For non-fission mode, only UpdateAllowAccessOnCurrentProcess is used.
// A permission key (constructed by tracking origin) is stored in the top-level
// window, so every subframe can check if they have the permission by looking
// up their key.
//
// For fission, both methods will be used. Which method to use depends on if the
// storage access heuristic is triggered by a first-party window or a
......@@ -692,46 +750,54 @@ void ContentBlocking::UpdateAllowAccessOnCurrentProcess(
BrowsingContext* aParentContext, const nsACString& aTrackingOrigin) {
MOZ_ASSERT(aParentContext && aParentContext->IsInProcess());
nsAutoCString permissionKey;
AntiTrackingUtils::CreateStoragePermissionKey(aTrackingOrigin, permissionKey);
bool useRemoteSubframes;
aParentContext->GetUseRemoteSubframes(&useRemoteSubframes);
if (useRemoteSubframes && aParentContext->IsTopContent()) {
// If we are a first-party and we are in fission mode, bail out early
// because we can't do anything here.
return;
}
BrowsingContext* top = aParentContext->Top();
uint32_t behavior = AntiTrackingUtils::GetCookieBehavior(top);
top->PreOrderWalk([&](BrowsingContext* aContext) {
// Only check browsing contexts that are in-process.
if (aContext->IsInProcess()) {
nsAutoCString origin;
Unused << AntiTrackingUtils::GetPrincipalAndTrackingOrigin(
aContext, nullptr, origin);
// Permission is only synced to first-level iframes.
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
!AntiTrackingUtils::IsFirstLevelSubContext(aContext)) {
return;
}
// For non-fission mode, save access granted decision in the top-level window.
// However, in fission, top-level window is not accessible from a 3rd-party
// subframe. So we traverse browsing context tree to find all subframes having
// the same tracking origin, and save the decision in the subframe.
if (useRemoteSubframes) {
if (aParentContext->IsTopContent()) {
// If we are a first-party, we can't access tracker's frames.
// For this case, we should update the result in the parent process.
// See UpdateAllowAccessOnParentProcess.
return;
}
if (aTrackingOrigin == origin) {
nsCOMPtr<nsPIDOMWindowInner> inner =
AntiTrackingUtils::GetInnerWindow(aContext);
if (inner) {
inner->SaveStorageAccessGranted();
BrowsingContext* top = aParentContext->Top();
top->PreOrderWalk([&](BrowsingContext* aContext) {
// Only check browsing contexts that are in-process.
if (aContext->IsInProcess()) {
nsAutoCString origin;
Unused << AntiTrackingUtils::GetPrincipalAndTrackingOrigin(
aContext, nullptr, origin);
uint32_t behavior = AntiTrackingUtils::GetCookieBehavior(aContext);
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
!AntiTrackingUtils::IsFirstLevelSubContext(aContext)) {
return;
}
nsCOMPtr<nsPIDOMWindowOuter> outer =
nsPIDOMWindowOuter::GetFromCurrentInner(inner);
if (outer) {
nsGlobalWindowOuter::Cast(outer)->SetHasStorageAccess(true);
if (aTrackingOrigin == origin) {
nsCOMPtr<nsPIDOMWindowInner> inner =
AntiTrackingUtils::GetInnerWindow(aContext);
if (inner) {
inner->SaveStorageAccessGranted(permissionKey);
}
}
}
});
} else {
nsCOMPtr<nsPIDOMWindowInner> topInner =
AntiTrackingUtils::GetInnerWindow(aParentContext->Top());
if (topInner) {
topInner->SaveStorageAccessGranted(permissionKey);
}
});
}
}
/* static */
......@@ -748,7 +814,8 @@ void ContentBlocking::UpdateAllowAccessOnParentProcess(
return;
}
uint32_t behavior = AntiTrackingUtils::GetCookieBehavior(aParentContext);
nsAutoCString permissionKey;
AntiTrackingUtils::CreateStoragePermissionKey(aTrackingOrigin, permissionKey);
aParentContext->PreOrderWalk([&](BrowsingContext* aContext) {
WindowGlobalParent* wgp = aContext->Canonical()->GetCurrentWindowGlobal();
......@@ -756,6 +823,7 @@ void ContentBlocking::UpdateAllowAccessOnParentProcess(
return;
}
uint32_t behavior = AntiTrackingUtils::GetCookieBehavior(aContext);
if (behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
!AntiTrackingUtils::IsFirstLevelSubContext(aContext)) {
return;
......@@ -764,7 +832,7 @@ void ContentBlocking::UpdateAllowAccessOnParentProcess(
nsAutoCString origin;
AntiTrackingUtils::GetPrincipalAndTrackingOrigin(aContext, nullptr, origin);
if (aTrackingOrigin == origin) {
Unused << wgp->SendSaveStorageAccessGranted();
Unused << wgp->SendSaveStorageAccessGranted(permissionKey);
}
});
}
......@@ -930,16 +998,16 @@ bool ContentBlocking::ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow,
return false;
}
// Document::HasStoragePermission first checks if storage access granted is
// cached in the inner window, if no, it then checks the storage permission
// flag in the channel's loadinfo
bool allowed = document->HasStoragePermission();
if (!allowed) {
*aRejectedReason = blockedReason;
} else {
// Document::HasStoragePermission already checks HasStorageAccessGranted,
// we just show log here to know whether the permission is granted because
// of permission update.
if (MOZ_LOG_TEST(gAntiTrackingLog, mozilla::LogLevel::Debug) &&
aWindow->HasStorageAccessGranted()) {
ContentBlocking::HasStorageAccessGranted(aWindow)) {
LOG(("Permission stored in the window. All good."));
}
}
......@@ -1130,14 +1198,15 @@ bool ContentBlocking::ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI,
aChannel->GetIsDocument(&isDocument);
if (isDocument) {
RefPtr<BrowsingContext> bc;
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(bc));
if (!bc || NS_WARN_IF(NS_FAILED(rv))) {
RefPtr<BrowsingContext> browsingContext;
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG(("Failed to get the channel's target browsing context"));
} else {
nsCOMPtr<nsPIDOMWindowInner> inner =
AntiTrackingUtils::GetInnerWindow(bc);
if (inner && inner->HasStorageAccessGranted()) {
nsAutoCString type;
AntiTrackingUtils::CreateStoragePermissionKey(trackingOrigin, type);
if (ContentBlocking::HasStorageAccessGranted(browsingContext, type)) {
LOG(("Permission stored in the window. All good."));
return true;
}
......
......@@ -128,6 +128,12 @@ class ContentBlocking final {
ContentBlockingNotifier::StorageAccessGrantedReason aReason,
const PerformFinalChecks& aPerformFinalChecks = nullptr);
friend class dom::Document;
static bool HasStorageAccessGranted(nsPIDOMWindowInner* aWindow);
static bool HasStorageAccessGranted(dom::BrowsingContext* aBrowsingContext,
const nsACString& aPermissionKey);
static void UpdateAllowAccessOnCurrentProcess(
dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin);
......
<html>
<head>
<title>Tracker</title>
<script type="text/javascript" src="https://example.com/browser/toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js"></script>
</head>
<body>
<h1>Tracker</h1>
<script>
function info(msg) {
parent.postMessage({ type: "info", msg }, "*");
}
function ok(what, msg) {
parent.postMessage({ type: "ok", what: !!what, msg }, "*");
}
function is(a, b, msg) {
ok(a === b, msg);
}
function workerCode() {
onmessage = e => {
try {
indexedDB.open("test", "1");
postMessage(true);
} catch (e) {
postMessage(false);
}
};
}
var worker;
function createWorker() {
let blob = new Blob([workerCode.toString() + "; workerCode();"]);
let blobURL = URL.createObjectURL(blob);
info("Blob created");
worker = new Worker(blobURL);
info("Worker created");
}
onmessage = function(e) {
let runnableStr = `(() => {return (${e.data.callback});})();`;
let runnable = eval(runnableStr); // eslint-disable-line no-eval
runnable.call(this, e.data.arg || /* Phase */ 3).then(_ => {
parent.postMessage({ type: "finish" }, "*");
});
};
createWorker();
</script>
</body>
</html>
......@@ -28,7 +28,6 @@ support-files =
3rdPartySVG.html
3rdPartyUI.html
3rdPartyWO.html
3rdPartyWorker.html
3rdPartyOpen.html
3rdPartyOpenUI.html
empty.js
......@@ -92,8 +91,6 @@ skip-if = fission #Bug 1578038
skip-if = fission
[browser_permissionInPrivateWindows.js]
skip-if = fission
[browser_permissionPropagation.js]
skip-if = fission
[browser_referrerDefaultPolicy.js]
support-files = referrer.sjs
[browser_siteSpecificWorkArounds.js]
......