author | Andrea Marchesini <amarchesini@mozilla.com> |
Fri, 10 Aug 2018 15:55:22 -0400 | |
changeset 489054 | e70b1d7ba1ebeb23000e6c1a97dafafd6b79a324 |
parent 489028 | 6f69e808328401eba4d3984f5c755f82ebbcd631 |
child 489055 | f93a51060a07cb216d9c44cb538a948155e1ad32 |
push id | 1815 |
push user | ffxbld-merge |
push date | Mon, 15 Oct 2018 10:40:45 +0000 |
treeherder | mozilla-release@18d4c09e9378 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ehsan |
bugs | 1480780 |
milestone | 63.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -6,16 +6,17 @@ // Needs to be first. #include "base/basictypes.h" #include "Navigator.h" #include "nsIXULAppInfo.h" #include "nsPluginArray.h" #include "nsMimeTypeArray.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/MemoryReporting.h" #include "mozilla/dom/BodyExtractor.h" #include "mozilla/dom/FetchBinding.h" #include "mozilla/dom/File.h" #include "nsGeolocation.h" #include "nsIClassOfService.h" #include "nsIHttpProtocolHandler.h" #include "nsIContentPolicy.h" @@ -58,16 +59,17 @@ #include "mozilla/dom/Event.h" // for Event #include "nsGlobalWindow.h" #include "nsIPermissionManager.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" #include "nsRFPService.h" #include "nsStringStream.h" #include "nsComponentManagerUtils.h" +#include "nsICookieService.h" #include "nsIStringStream.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsStreamUtils.h" #include "WidgetUtils.h" #include "nsIPresentationService.h" #include "nsIScriptError.h" @@ -508,25 +510,21 @@ Navigator::Storage() if(!mStorageManager) { mStorageManager = new StorageManager(mWindow->AsGlobal()); } return mStorageManager; } -// Values for the network.cookie.cookieBehavior pref are documented in -// nsCookieService.cpp. -#define COOKIE_BEHAVIOR_REJECT 2 - bool Navigator::CookieEnabled() { bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() != - COOKIE_BEHAVIOR_REJECT); + nsICookieService::BEHAVIOR_REJECT); // Check whether an exception overrides the global cookie behavior // Note that the code for getting the URI here matches that in // nsHTMLDocument::SetCookie. if (!mWindow || !mWindow->GetDocShell()) { return cookieEnabled; } @@ -539,30 +537,18 @@ Navigator::CookieEnabled() doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); if (!codebaseURI) { // Not a codebase, so technically can't set cookies, but let's // just return the default value. return cookieEnabled; } - nsCOMPtr<nsICookiePermission> permMgr = - do_GetService(NS_COOKIEPERMISSION_CONTRACTID); - NS_ENSURE_TRUE(permMgr, cookieEnabled); - - // Pass null for the channel, just like the cookie service does. - nsCookieAccess access; - nsresult rv = permMgr->CanAccess(doc->NodePrincipal(), &access); - NS_ENSURE_SUCCESS(rv, cookieEnabled); - - if (access != nsICookiePermission::ACCESS_DEFAULT) { - cookieEnabled = access != nsICookiePermission::ACCESS_DENY; - } - - return cookieEnabled; + return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow, + codebaseURI); } bool Navigator::OnLine() { return !NS_IsOffline(); }
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -212,18 +212,18 @@ #include "nsWidgetsCID.h" #include "nsIWindowProvider.h" #include "nsWrapperCacheInlines.h" #include "nsXULPopupManager.h" #include "xpcprivate.h" // nsXPConnect #include "HTMLSplitOnSpacesTokenizer.h" #include "nsContentTypeParser.h" #include "nsICookiePermission.h" +#include "nsICookieService.h" #include "mozIThirdPartyUtil.h" -#include "nsICookieService.h" #include "mozilla/EnumSet.h" #include "mozilla/BloomFilter.h" #include "TabChild.h" #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/TabGroup.h" #include "nsIWebNavigationInfo.h" #include "nsPluginHost.h" #include "mozilla/HangAnnotations.h" @@ -8746,57 +8746,50 @@ nsContentUtils::StorageAccess nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal) { return InternalStorageAllowedForPrincipal(aPrincipal, nullptr, nullptr, nullptr); } // static, private void -nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal, - uint32_t* aLifetimePolicy, - uint32_t* aBehavior) +nsContentUtils::GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal, + uint32_t* aLifetimePolicy) { *aLifetimePolicy = sCookiesLifetimePolicy; - *aBehavior = StaticPrefs::network_cookie_cookieBehavior(); // Any permissions set for the given principal will override our default // settings from preferences. nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager(); if (!permissionManager) { return; } uint32_t perm; permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm); switch (perm) { case nsICookiePermission::ACCESS_ALLOW: - *aBehavior = nsICookieService::BEHAVIOR_ACCEPT; *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_DENY: - *aBehavior = nsICookieService::BEHAVIOR_REJECT; *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_SESSION: - *aBehavior = nsICookieService::BEHAVIOR_ACCEPT; *aLifetimePolicy = nsICookieService::ACCEPT_SESSION; break; case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY: - *aBehavior = nsICookieService::BEHAVIOR_REJECT_FOREIGN; // NOTE: The decision was made here to override the lifetime policy to be // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a // specific domain. As BEHAVIOR_REJECT_FOREIGN isn't visible in our UI, // this is probably not an issue. *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY: - *aBehavior = nsICookieService::BEHAVIOR_LIMIT_FOREIGN; // NOTE: The decision was made here to override the lifetime policy to be // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a // specific domain. As BEHAVIOR_LIMIT_FOREIGN isn't visible in our UI, // this is probably not an issue. *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY; break; } @@ -8856,88 +8849,66 @@ nsContentUtils::IsTrackingResourceWindow } return httpChannel->GetIsTrackingResource(); } static bool StorageDisabledByAntiTrackingInternal(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI) { - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { - return false; - } - - // Let's check if this is a 3rd party context. - if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) { - return false; - } + MOZ_ASSERT(aWindow || aChannel || aPrincipal); if (aWindow) { - nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow); - nsGlobalWindowOuter* outerWindow = - nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow()); - if (NS_WARN_IF(!outerWindow)) { - return false; - } - - // We are a first party resource. - if (outerWindow->IsTopLevelWindow()) { - return false; - } - nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI(); - if (documentURI && - AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow, - documentURI)) { + return !documentURI || + !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow, + documentURI); + } + + if (aChannel) { + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); + if (!httpChannel) { return false; } - return true; - } - - // aChannel and aWindow are mutually exclusive. - MOZ_ASSERT(aChannel); - - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); - if (!httpChannel) { - return false; - } - - // If this is not a tracking resource, nothing is disabled. - if (!httpChannel->GetIsTrackingResource()) { - return false; - } - - nsCOMPtr<nsIURI> uri; - nsresult rv = httpChannel->GetURI(getter_AddRefs(uri)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, - uri); + nsCOMPtr<nsIURI> uri; + nsresult rv = httpChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, + uri); + } + + MOZ_ASSERT(aPrincipal); + return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aPrincipal); } // static public bool nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI) { bool disabled = - StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aURI); + StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI); if (disabled && StaticPrefs::privacy_restrict3rdpartystorage_ui_enabled()) { nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); if (!thirdPartyUtil) { return false; } + // FIXME: this is wrong. This method is called also with aWindow and a null + // aChannel. nsCOMPtr<mozIDOMWindowProxy> win; nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, getter_AddRefs(win)); NS_ENSURE_SUCCESS(rv, false); auto* pwin = nsPIDOMWindowOuter::From(win); pwin->NotifyContentBlockingState( nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel); @@ -8957,45 +8928,39 @@ nsContentUtils::InternalStorageAllowedFo StorageAccess access = StorageAccess::eAllow; // We don't allow storage on the null principal, in general. Even if the // calling context is chrome. if (aPrincipal->GetIsNullPrincipal()) { return StorageAccess::eDeny; } - if (StorageDisabledByAntiTracking(aWindow, aChannel, aURI)) { - return StorageAccess::eDeny; - } - if (aWindow) { // If the document is sandboxed, then it is not permitted to use storage nsIDocument* document = aWindow->GetExtantDoc(); if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) { return StorageAccess::eDeny; } // Check if we are in private browsing, and record that fact if (IsInPrivateBrowsing(document)) { access = StorageAccess::ePrivateBrowsing; } } uint32_t lifetimePolicy; - uint32_t behavior; // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior // and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale). auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy(); if (policy) { - behavior = nsICookieService::BEHAVIOR_ACCEPT; lifetimePolicy = nsICookieService::ACCEPT_NORMALLY; } else { - GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior); + GetCookieLifetimePolicyForPrincipal(aPrincipal, &lifetimePolicy); } // Check if we should only allow storage for the session, and record that fact if (lifetimePolicy == nsICookieService::ACCEPT_SESSION) { // Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow // so perform a std::min comparison to make sure we preserve ePrivateBrowsing // if it has been set. access = std::min(StorageAccess::eSessionScoped, access); @@ -9031,29 +8996,17 @@ nsContentUtils::InternalStorageAllowedFo if (uri) { bool isAbout = false; MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout)); if (isAbout) { return access; } } - // We don't want to prompt for every attempt to access permissions. - if (behavior == nsICookieService::BEHAVIOR_REJECT) { - return StorageAccess::eDeny; - } - - if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || - behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) && - IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) { - // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by - // simply rejecting the request to use the storage. In the future, if we - // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense - // for non-cookie storage types, this may change. - + if (StorageDisabledByAntiTracking(aWindow, aChannel, aPrincipal, aURI)) { return StorageAccess::eDeny; } return access; } namespace {
--- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2946,21 +2946,22 @@ public: /* * Checks if storage for the given principal is permitted by the user's * preferences. The caller is assumed to not be a third-party iframe. * (if that is possible, the caller should use StorageAllowedForWindow) */ static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal); /* - * Returns true if this window/channel should disable storages because of the - * anti-tracking feature. + * Returns true if this window/channel/aPrincipal should disable storages + * because of the anti-tracking feature. */ static bool StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, + nsIPrincipal* aPrincipal, nsIURI* aURI); /* * Returns true if this window/channel is a 3rd party context. */ static bool IsThirdPartyWindowOrChannel(nsPIDOMWindowInner* aWindow, nsIChannel* aChannel, nsIURI* aURI); @@ -3337,24 +3338,23 @@ private: mozilla::dom::AutocompleteInfo& aInfo, bool aGrantAllValidValue = false); static bool CallOnAllRemoteChildren(mozilla::dom::MessageBroadcaster* aManager, CallOnRemoteChildFunction aCallback, void* aArg); /** - * Gets the current cookie lifetime policy and cookie behavior for a given - * principal by checking with preferences and the permission manager. + * Gets the current cookie lifetime policy for a given principal by checking + * with preferences and the permission manager. * * Used in the implementation of InternalStorageAllowedForPrincipal. */ - static void GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal, - uint32_t* aLifetimePolicy, - uint32_t* aBehavior); + static void GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal, + uint32_t* aLifetimePolicy); /* * Checks if storage for a given principal is permitted by the user's * preferences. If aWindow is non-null, its principal must be passed as * aPrincipal, and the third-party iframe and sandboxing status of the window * are also checked. If aURI is non-null, then it is used as the comparison * against aWindow to determine if this is a third-party load. We also * allow a channel instead of the window reference when determining 3rd party
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -12638,17 +12638,18 @@ nsIDocument::SetDocTreeHadPlayRevoked() if (topLevelDoc) { topLevelDoc->mDocTreeHadPlayRevoked = true; } } void nsIDocument::MaybeAllowStorageForOpener() { - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return; } // This will probably change for project fission, but currently this document // and the opener are on the same process. In the future, we should make this // part async. nsPIDOMWindowInner* inner = GetInnerWindow();
--- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -12,20 +12,20 @@ #include "mozilla/dom/StructuredCloneHolder.h" #include "mozilla/dom/ipc/StructuredCloneData.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundChild.h" -#include "mozilla/StaticPrefs.h" #include "nsContentUtils.h" #include "nsIBFCacheEntry.h" +#include "nsICookieService.h" #include "nsIDocument.h" #include "nsISupportsPrimitives.h" #ifdef XP_WIN #undef PostMessage #endif namespace mozilla { @@ -68,22 +68,24 @@ GetPrincipalFromThreadSafeWorkerRef(Thre return wp->GetPrincipal(); } class InitializeRunnable final : public WorkerMainThreadRunnable { public: InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin, - PrincipalInfo& aPrincipalInfo, ErrorResult& aRv) + PrincipalInfo& aPrincipalInfo, bool* aThirdPartyWindow, + ErrorResult& aRv) : WorkerMainThreadRunnable(aWorkerRef->Private(), NS_LITERAL_CSTRING("BroadcastChannel :: Initialize")) , mWorkerRef(aWorkerRef) , mOrigin(aOrigin) , mPrincipalInfo(aPrincipalInfo) + , mThirdPartyWindow(aThirdPartyWindow) , mRv(aRv) { MOZ_ASSERT(mWorkerRef); } bool MainThreadRun() override { MOZ_ASSERT(NS_IsMainThread()); @@ -111,23 +113,27 @@ public: } // Window doesn't exist for some kind of workers (eg: SharedWorkers) nsPIDOMWindowInner* window = wp->GetWindow(); if (!window) { return true; } + *mThirdPartyWindow = + nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr); + return true; } private: RefPtr<ThreadSafeWorkerRef> mWorkerRef; nsACString& mOrigin; PrincipalInfo& mPrincipalInfo; + bool* mThirdPartyWindow; ErrorResult& mRv; }; class CloseRunnable final : public nsIRunnable, public nsICancelableRunnable { public: NS_DECL_ISUPPORTS @@ -296,53 +302,56 @@ BroadcastChannel::Constructor(const Glob return nullptr; } aRv = PrincipalToPrincipalInfo(principal, &principalInfo); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && + if (nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, + nullptr) && nsContentUtils::StorageAllowedForWindow(window) != nsContentUtils::StorageAccess::eAllow) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } } else { JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && - !workerPrivate->IsStorageAllowed()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(workerPrivate, "BroadcastChannel", [bc] () { bc->Shutdown(); }); // We are already shutting down the worker. Let's return a non-active // object. if (NS_WARN_IF(!workerRef)) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef); + bool thirdPartyWindow = false; + RefPtr<InitializeRunnable> runnable = - new InitializeRunnable(tsr, origin, principalInfo, aRv); + new InitializeRunnable(tsr, origin, principalInfo, &thirdPartyWindow, + aRv); runnable->Dispatch(Canceling, aRv); if (aRv.Failed()) { return nullptr; } + if (thirdPartyWindow && !workerPrivate->IsStorageAllowed()) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + bc->mWorkerRef = std::move(workerRef); } // Register this component to PBackground. PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!actorChild)) { // Firefox is probably shutting down. Let's return a 'generic' error. aRv.Throw(NS_ERROR_FAILURE);
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1102,17 +1102,17 @@ nsHTMLDocument::GetCookie(nsAString& aCo // If the document's sandboxed origin flag is set, access to read cookies // is prohibited. if (mSandboxFlags & SANDBOXED_ORIGIN) { rv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr, - nullptr)) { + NodePrincipal(), nullptr)) { return; } // If the document is a cookie-averse Document... return the empty string. if (IsCookieAverse()) { return; } @@ -1157,17 +1157,17 @@ nsHTMLDocument::SetCookie(const nsAStrin // If the document's sandboxed origin flag is set, access to write cookies // is prohibited. if (mSandboxFlags & SANDBOXED_ORIGIN) { rv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr, - nullptr)) { + NodePrincipal(), nullptr)) { return; } // If the document is a cookie-averse Document... do nothing. if (IsCookieAverse()) { return; }
--- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -4,16 +4,17 @@ * 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 "RuntimeService.h" #include "nsAutoPtr.h" #include "nsIChannel.h" #include "nsIContentSecurityPolicy.h" +#include "nsICookieService.h" #include "nsIDocument.h" #include "nsIDOMChromeWindow.h" #include "nsIEffectiveTLDService.h" #include "nsIObserverService.h" #include "nsIPrincipal.h" #include "nsIScriptContext.h" #include "nsIScriptError.h" #include "nsIScriptSecurityManager.h" @@ -2263,17 +2264,18 @@ RuntimeService::ResumeWorkersForWindow(n } } void RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow) { AssertIsOnMainThread(); MOZ_ASSERT(aWindow); - MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); nsTArray<WorkerPrivate*> workers; GetWorkersForWindow(aWindow, workers); for (uint32_t index = 0; index < workers.Length(); index++) { workers[index]->PropagateFirstPartyStorageAccessGranted(); } } @@ -2876,17 +2878,18 @@ ResumeWorkersForWindow(nsPIDOMWindowInne runtime->ResumeWorkersForWindow(aWindow); } } void PropagateFirstPartyStorageAccessGrantedToWorkers(nsPIDOMWindowInner* aWindow) { AssertIsOnMainThread(); - MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { runtime->PropagateFirstPartyStorageAccessGranted(aWindow); } } WorkerPrivate*
--- a/image/ImageCacheKey.cpp +++ b/image/ImageCacheKey.cpp @@ -3,23 +3,23 @@ * 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 "ImageCacheKey.h" #include "mozilla/HashFunctions.h" #include "mozilla/Move.h" #include "nsContentUtils.h" +#include "nsICookieService.h" #include "nsLayoutUtils.h" #include "nsString.h" #include "mozilla/AntiTrackingCommon.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/File.h" #include "mozilla/dom/ServiceWorkerManager.h" -#include "mozilla/StaticPrefs.h" #include "nsIDocument.h" #include "nsPrintfCString.h" namespace mozilla { using namespace dom; namespace image { @@ -136,39 +136,33 @@ ImageCacheKey::GetSpecialCaseDocumentTok // For controlled documents, we cast the pointer into a void* to avoid // dereferencing it (since we only use it for comparisons). RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); if (swm && aDocument->GetController().isSome()) { return aDocument; } - // We want to have a unique image cache if the anti-tracking feature is - // enabled for 3rd party resources. - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled() || - !nsContentUtils::IsThirdPartyWindowOrChannel(aDocument->GetInnerWindow(), - nullptr, aURI)) { - return nullptr; - } - - // If the window is 3rd party resource, let's see if the first party storage - // access is granted for this image. - if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) { - return nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(), - nullptr, aURI) - ? aDocument : nullptr; + // If we must disable the storage, we want to create a unique cache key for + // this image. + if (nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(), + nullptr, + aDocument->NodePrincipal(), + aURI)) { + return aDocument; } // Another scenario is if this image is a 3rd party resource loaded by a // first party context. In this case, we should check if the nsIChannel has // been marked as tracking resource, but we don't have the channel yet at // this point. The best approach here is to be conservative: if we are sure // that the permission is granted, let's return a nullptr. Otherwise, let's // make a unique image cache. - if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(), + if (!aDocument->IsCookieAverse() && + !AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(), aURI)) { return aDocument; } return nullptr; } } // namespace image
--- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -1086,22 +1086,23 @@ VARCACHE_PREF( // - true: They are allow to present http auth. dialog // - false: They are not allow to present http auth. dialog. VARCACHE_PREF( "network.auth.non-web-content-triggered-resources-http-auth-allow", network_auth_non_web_content_triggered_resources_http_auth_allow, bool, false ) -// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign +// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign, +// 4-rejectTracker // Keep the old default of accepting all cookies VARCACHE_PREF( "network.cookie.cookieBehavior", network_cookie_cookieBehavior, - int32_t, 0 + RelaxedAtomicInt32, 0 ) // Enables the predictive service. VARCACHE_PREF( "network.predictor.enabled", network_predictor_enabled, bool, true ) @@ -1227,22 +1228,16 @@ VARCACHE_PREF( PREF("preferences.allow.omt-write", bool, true) //--------------------------------------------------------------------------- // Privacy prefs //--------------------------------------------------------------------------- VARCACHE_PREF( - "privacy.restrict3rdpartystorage.enabled", - privacy_restrict3rdpartystorage_enabled, - RelaxedAtomicBool, false -) - -VARCACHE_PREF( "privacy.restrict3rdpartystorage.ui.enabled", privacy_restrict3rdpartystorage_ui_enabled, RelaxedAtomicBool, false ) // Anti-tracking permission expiration VARCACHE_PREF( "privacy.restrict3rdpartystorage.expiration",
--- a/netwerk/base/nsChannelClassifier.cpp +++ b/netwerk/base/nsChannelClassifier.cpp @@ -7,16 +7,17 @@ #include "nsChannelClassifier.h" #include "mozIThirdPartyUtil.h" #include "nsCharSeparatedTokenizer.h" #include "nsContentUtils.h" #include "nsIAddonPolicyService.h" #include "nsICacheEntry.h" #include "nsICachingChannel.h" +#include "nsICookieService.h" #include "nsIChannel.h" #include "nsIClassOfService.h" #include "nsIDocShell.h" #include "nsIDocument.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIIOService.h" #include "nsIParentChannel.h" @@ -946,17 +947,18 @@ TrackingURICallback::OnClassifyComplete( const nsACString& aFullHash) { MOZ_ASSERT(aErrorCode == NS_OK); const bool shouldEnableTrackingProtection = mChannelClassifier->ShouldEnableTrackingProtection(); const bool shouldEnableTrackingAnnotation = mChannelClassifier->ShouldEnableTrackingAnnotation() || - StaticPrefs::privacy_restrict3rdpartystorage_enabled(); + StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER; MOZ_ASSERT(shouldEnableTrackingProtection || shouldEnableTrackingAnnotation); LOG(("TrackingURICallback[%p]:OnClassifyComplete " "shouldEnableTrackingProtection=%d, shouldEnableTrackingAnnnotation=%d", mChannelClassifier.get(), shouldEnableTrackingProtection, shouldEnableTrackingAnnotation)); // Figure out whether we are receiving the results of a blacklist or @@ -1194,17 +1196,18 @@ TrackingURICallback::OnTrackerFound(nsre mChannelClassifier->SetBlockedContent(channel, aErrorCode, mList, mProvider, mFullHash); LOG(("TrackingURICallback[%p]::OnTrackerFound, cancelling channel[%p]", mChannelClassifier.get(), channel.get())); channel->Cancel(aErrorCode); } else { MOZ_ASSERT(aErrorCode == NS_ERROR_TRACKING_ANNOTATION_URI); MOZ_ASSERT(mChannelClassifier->ShouldEnableTrackingAnnotation() || - StaticPrefs::privacy_restrict3rdpartystorage_enabled()); + StaticPrefs::network_cookie_cookieBehavior() == + nsICookieService::BEHAVIOR_REJECT_TRACKER); LOG(("TrackingURICallback[%p]::OnTrackerFound, annotating channel[%p]", mChannelClassifier.get(), channel.get())); // Even with TP disabled, we still want to show the user that there // are unblocked trackers on the site, so notify the UI that we loaded // tracking content. UI code can treat this notification differently // depending on whether TP is enabled or disabled. @@ -1416,17 +1419,18 @@ nsChannelClassifier::CheckIsTrackerWithL nsCOMPtr<nsIURIClassifier> uriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } const bool shouldEnableTrackingProtection = ShouldEnableTrackingProtection(); - const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || StaticPrefs::privacy_restrict3rdpartystorage_enabled(); + const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || + StaticPrefs::network_cookie_cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER; if (!shouldEnableTrackingProtection && !shouldEnableTrackingAnnotation) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIURI> uri; rv = mChannel->GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv) || !uri) { return rv;
--- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -2405,17 +2405,17 @@ nsCookieService::RunInTransaction(nsICoo * pref observer impl ******************************************************************************/ void nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch) { int32_t val; if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val))) - mCookieBehavior = (uint8_t) LIMIT(val, 0, 3, 0); + mCookieBehavior = (uint8_t) LIMIT(val, 0, nsICookieService::BEHAVIOR_LAST, 0); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val))) mMaxNumberOfCookies = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxNumberOfCookies); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val))) mMaxCookiesPerHost = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxCookiesPerHost); if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiePurgeAge, &val))) { @@ -4194,24 +4194,16 @@ nsCookieService::CheckPrefs(nsICookiePer nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateCodebasePrincipal(aHostURI, aOriginAttrs); if (!principal) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "non-codebase principals cannot get/set cookies"); return STATUS_REJECTED_WITH_ERROR; } - // No cookies allowed if this request comes from a tracker, in a 3rd party - // context, when anti-tracking protection is enabled and when we don't have - // access to the first-party cookie jar. - if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted && - StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { - return STATUS_REJECTED; - } - // check the permission list first; if we find an entry, it overrides // default prefs. see bug 184059. if (aPermissionService) { nsCookieAccess access; // Not passing an nsIChannel here is probably OK; our implementation // doesn't do anything with it anyway. rv = aPermissionService->CanAccess(principal, &access); @@ -4245,16 +4237,25 @@ nsCookieService::CheckPrefs(nsICookiePer "for this site"); return STATUS_REJECTED; } return STATUS_ACCEPTED; } } } + // No cookies allowed if this request comes from a tracker, in a 3rd party + // context, when anti-tracking protection is enabled and when we don't have + // access to the first-party cookie jar. + if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted && + aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) { + COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled in trackers"); + return STATUS_REJECTED; + } + // check default prefs if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled"); return STATUS_REJECTED; } // check if cookie is foreign if (aIsForeign) { @@ -4266,17 +4267,19 @@ nsCookieService::CheckPrefs(nsICookiePer if (aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { if (aNumOfCookies == 0) { COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party"); return STATUS_REJECTED; } } MOZ_ASSERT(aCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT || - aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN); + aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN || + // But with permission granted. + aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); if (aThirdPartySession) return STATUS_ACCEPT_SESSION; if (aThirdPartyNonsecureSession) { bool isHTTPS = false; aHostURI->SchemeIs("https", &isHTTPS); if (!isHTTPS)
--- a/netwerk/cookie/nsICookiePermission.idl +++ b/netwerk/cookie/nsICookiePermission.idl @@ -47,17 +47,17 @@ interface nsICookiePermission : nsISuppo * the new cookie access for the URI. */ void setAccess(in nsIURI aURI, in nsCookieAccess aAccess); /** * canAccess * - * this method is called to test whether or not the given URI/channel may + * this method is called to test whether or not the given principal may * access the cookie database, either to set or get cookies. * * @param aPrincipal * the principal trying to access cookies. * * @return one of the following nsCookieAccess values: * ACCESS_DEFAULT, ACCESS_ALLOW, ACCESS_DENY, or * ACCESS_ALLOW_FIRST_PARTY_ONLY
--- a/netwerk/cookie/nsICookieService.idl +++ b/netwerk/cookie/nsICookieService.idl @@ -84,16 +84,19 @@ interface nsICookieService : nsISupports /* * Possible values for the "network.cookie.cookieBehavior" preference. */ const uint32_t BEHAVIOR_ACCEPT = 0; // allow all cookies const uint32_t BEHAVIOR_REJECT_FOREIGN = 1; // reject all third-party cookies const uint32_t BEHAVIOR_REJECT = 2; // reject all cookies const uint32_t BEHAVIOR_LIMIT_FOREIGN = 3; // reject third-party cookies unless the // eTLD already has at least one cookie + const uint32_t BEHAVIOR_REJECT_TRACKER = 4; // reject trackers + // When adding a new cookie behavior, please increase this value! + const uint32_t BEHAVIOR_LAST = 4; /* * Possible values for the "network.cookie.lifetimePolicy" preference. */ const uint32_t ACCEPT_NORMALLY = 0; // accept normally // Value = 1 is considered the same as 0 (See Bug 606655). const uint32_t ACCEPT_SESSION = 2; // downgrade to session // Value = 3 is considered the same as 0
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -17,16 +17,17 @@ #include "nsHttpChannel.h" #include "nsHttpHandler.h" #include "nsIApplicationCacheService.h" #include "nsIApplicationCacheContainer.h" #include "nsICacheStorageService.h" #include "nsICacheStorage.h" #include "nsICacheEntry.h" #include "nsICaptivePortalService.h" +#include "nsICookieService.h" #include "nsICryptoHash.h" #include "nsINetworkInterceptController.h" #include "nsINSSErrorsService.h" #include "nsISecurityReporter.h" #include "nsIStringBundle.h" #include "nsIStreamListenerTee.h" #include "nsISeekableStream.h" #include "nsILoadGroupChild.h" @@ -50,16 +51,17 @@ #include "mozilla/TimeStamp.h" #include "nsError.h" #include "nsPrintfCString.h" #include "nsAlgorithm.h" #include "nsQueryObject.h" #include "nsThreadUtils.h" #include "GeckoProfiler.h" #include "nsIConsoleService.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsISSLSocketControl.h" #include "sslt.h" #include "nsContentUtils.h" #include "nsContentSecurityManager.h" @@ -98,17 +100,16 @@ #include "nsIDocument.h" #include "nsICompressConvStats.h" #include "nsCORSListenerProxy.h" #include "nsISocketProvider.h" #include "mozilla/extensions/StreamFilterParent.h" #include "mozilla/net/Predictor.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/NullPrincipal.h" -#include "mozilla/StaticPrefs.h" #include "CacheControlParser.h" #include "nsMixedContentBlocker.h" #include "CacheStorageService.h" #include "HttpChannelParent.h" #include "InterceptedHttpChannel.h" #include "nsIBufferedStreams.h" #include "nsIFileStreams.h" #include "nsIMIMEInputStream.h" @@ -3822,38 +3823,28 @@ nsHttpChannel::OpenCacheEntryInternal(bo if (mPostID) { extension.Append(nsPrintfCString("%d", mPostID)); } if (mTRR) { extension.Append("TRR"); } - if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() && - mIsTrackingResource) { - nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = - services::GetThirdPartyUtil(); - if (thirdPartyUtil) { - bool thirdParty = false; - Unused << thirdPartyUtil->IsThirdPartyChannel(this, - nullptr, - &thirdParty); - if (thirdParty) { - nsCOMPtr<nsIURI> topWindowURI; - rv = GetTopWindowURI(getter_AddRefs(topWindowURI)); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString topWindowOrigin; - rv = nsContentUtils::GetUTFOrigin(topWindowURI, topWindowOrigin); - NS_ENSURE_SUCCESS(rv, rv); - - extension.Append("-trackerFor:"); - extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin)); - } - } + if (!AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(this, mURI)) { + nsCOMPtr<nsIURI> topWindowURI; + rv = GetTopWindowURI(getter_AddRefs(topWindowURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString topWindowOrigin; + rv = nsContentUtils::GetUTFOrigin(topWindowURI ? topWindowURI : mURI, + topWindowOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + extension.Append("-unique:"); + extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin)); } mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY; mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority); if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite) { bool hasAltData = false; uint32_t sizeInKb = 0;
--- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -474,17 +474,17 @@ interface nsIHttpChannel : nsIChannel */ [must_use] attribute uint64_t topLevelContentWindowId; /** * Returns true if the channel has loaded a resource that is on the tracking * protection list. This is only available if the * privacy.trackingprotection.annotate_channels pref is set and its value * should only be relied on after the channel has established a connection. - * Note that, if privacy.restrict3rdpartystorage.enabled pref is set, also + * Note that, if the privacy.trackingprotection.annotate_channels pref is set, also * top-level channels could be marked as tracking resource. */ [infallible] readonly attribute boolean isTrackingResource; /** * This method is used in order to override the tracking status of an HTTP * channel. This should only be called by Gecko under certain circumstances * when Gecko can guarantee that the channel classifier service will not be
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -8,20 +8,23 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/ipc/MessageChannel.h" #include "mozilla/AbstractThread.h" #include "mozilla/StaticPrefs.h" #include "mozIThirdPartyUtil.h" #include "nsContentUtils.h" #include "nsGlobalWindowInner.h" +#include "nsICookiePermission.h" +#include "nsICookieService.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIURI.h" #include "nsPIDOMWindow.h" +#include "nsScriptSecurityManager.h" #include "prtime.h" #define ANTITRACKING_PERM_KEY "3rdPartyStorage" using namespace mozilla; using mozilla::dom::ContentChild; namespace { @@ -66,25 +69,63 @@ CreatePermissionKey(const nsCString& aTr return; } aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s", aTrackingOrigin.get(), aGrantedOrigin.get()); } +// This internal method returns ACCESS_DENY if the access is denied, +// ACCESS_DEFAULT if unknown, some other access code if granted. +nsCookieAccess +CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal) +{ + nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT; + if (!aPrincipal->GetIsCodebasePrincipal()) { + return access; + } + + nsCOMPtr<nsICookiePermission> cps = + do_GetService(NS_COOKIEPERMISSION_CONTRACTID); + if (NS_WARN_IF(!cps)) { + return access; + } + + nsresult rv = cps->CanAccess(aPrincipal, &access); + if (NS_WARN_IF(NS_FAILED(rv))) { + return access; + } + + // If we have a custom cookie permission, let's use it. + return access; +} + +int32_t +CookiesBehavior(nsIPrincipal* aPrincipal) +{ + // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior + // (See Bug 1406675 for rationale). + if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) { + return nsICookieService::BEHAVIOR_ACCEPT; + } + + return StaticPrefs::network_cookie_cookieBehavior(); +} + } // anonymous /* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise> AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin, nsPIDOMWindowInner* aParentWindow) { MOZ_ASSERT(aParentWindow); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return StorageAccessGrantPromise::CreateAndResolve(true, __func__); } nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal; nsAutoCString trackingOrigin; nsGlobalWindowInner* parentWindow = nsGlobalWindowInner::Cast(aParentWindow); nsGlobalWindowOuter* outerParentWindow = @@ -170,35 +211,70 @@ AntiTrackingCommon::SaveFirstPartyStorag nsresult rv = pm->AddFromPrincipal(aParentPrincipal, type.get(), nsIPermissionManager::ALLOW_ACTION, nsIPermissionManager::EXPIRE_TIME, when); Unused << NS_WARN_IF(NS_FAILED(rv)); aResolver(NS_SUCCEEDED(rv)); } bool -AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow, +AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow, nsIURI* aURI) { - MOZ_ASSERT(a3rdPartyTrackingWindow); + MOZ_ASSERT(aWindow); MOZ_ASSERT(aURI); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow); + nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal(); + if (!toplevelPrincipal) { + // We are already the top-level principal. Let's use the window's principal. + toplevelPrincipal = innerWindow->GetPrincipal(); + } + + if (!toplevelPrincipal) { + // This should not be possible, right? + return false; + } + + nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + int32_t behavior = CookiesBehavior(toplevelPrincipal); + if (behavior == nsICookieService::BEHAVIOR_ACCEPT) { return true; } - if (!nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow, - nullptr, aURI) || - !nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) { + if (behavior == nsICookieService::BEHAVIOR_REJECT) { + return false; + } + + // Let's check if this is a 3rd party context. + if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, aURI)) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || + behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { + // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by + // simply rejecting the request to use the storage. In the future, if we + // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense + // for non-cookie storage types, this may change. + return false; + } + + MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); + if (!nsContentUtils::IsTrackingResourceWindow(aWindow)) { return true; } nsCOMPtr<nsIPrincipal> parentPrincipal; nsAutoCString trackingOrigin; - if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(a3rdPartyTrackingWindow), + if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(aWindow), getter_AddRefs(parentPrincipal), trackingOrigin)) { return false; } nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -223,40 +299,124 @@ AntiTrackingCommon::IsFirstPartyStorageA } bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI) { MOZ_ASSERT(aURI); MOZ_ASSERT(aChannel); - MOZ_ASSERT(aChannel->GetIsTrackingResource()); nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); if (!loadInfo) { return true; } + // We need to find the correct principal to check the cookie permission. For + // third-party contexts, we want to check if the top-level window has a custom + // cookie permission. + nsIPrincipal* toplevelPrincipal = loadInfo->TopLevelPrincipal(); + + // If this is already the top-level window, we should use the loading + // principal. + if (!toplevelPrincipal) { + toplevelPrincipal = loadInfo->LoadingPrincipal(); + } + + nsCOMPtr<nsIPrincipal> channelPrincipal; + nsIScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager(); + nsresult rv = ssm->GetChannelResultPrincipal(aChannel, + getter_AddRefs(channelPrincipal)); + + // If we don't have a loading principal and this is a document channel, we are + // a top-level window! + if (!toplevelPrincipal) { + bool isDocument = false; + nsresult rv2 = aChannel->GetIsMainDocumentChannel(&isDocument); + if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && isDocument) { + toplevelPrincipal = channelPrincipal; + } + } + + // Let's use the triggering principal then. + if (!toplevelPrincipal) { + toplevelPrincipal = loadInfo->TriggeringPrincipal(); + } + + if (NS_WARN_IF(!toplevelPrincipal)) { + return false; + } + + nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + if (NS_WARN_IF(NS_FAILED(rv) || !channelPrincipal)) { + return false; + } + + int32_t behavior = CookiesBehavior(channelPrincipal); + if (behavior == nsICookieService::BEHAVIOR_ACCEPT) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT) { + return false; + } + + nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil(); + if (!thirdPartyUtil) { + return true; + } + + bool thirdParty = false; + Unused << thirdPartyUtil->IsThirdPartyChannel(aChannel, + nullptr, + &thirdParty); + // Grant if it's not a 3rd party. + if (!thirdParty) { + return true; + } + + if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN || + behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) { + // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by + // simply rejecting the request to use the storage. In the future, if we + // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense + // for non-cookie storage types, this may change. + return false; + } + + MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER); + nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal(); if (!parentPrincipal) { // parentPrincipal can be null if the parent window is not the top-level // window. if (loadInfo->TopLevelPrincipal()) { return false; } parentPrincipal = loadInfo->TriggeringPrincipal(); if (NS_WARN_IF(!parentPrincipal)) { // Why we are here?!? return true; } } + // Not a tracker. + if (!aChannel->GetIsTrackingResource()) { + return true; + } + + // Let's see if we have to grant the access for this particular channel. + nsCOMPtr<nsIURI> trackingURI; - nsresult rv = aChannel->GetURI(getter_AddRefs(trackingURI)); + rv = aChannel->GetURI(getter_AddRefs(trackingURI)); if (NS_WARN_IF(NS_FAILED(rv))) { return true; } nsAutoString trackingOrigin; rv = nsContentUtils::GetUTFOrigin(trackingURI, trackingOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return false; @@ -281,39 +441,59 @@ AntiTrackingCommon::IsFirstPartyStorageA rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } return result == nsIPermissionManager::ALLOW_ACTION; } +bool +AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal) +{ + MOZ_ASSERT(aPrincipal); + + nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + + int32_t behavior = CookiesBehavior(aPrincipal); + return behavior != nsICookieService::BEHAVIOR_REJECT; +} + /* static */ bool AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI) { MOZ_ASSERT(aFirstPartyWindow); MOZ_ASSERT(!nsContentUtils::IsTrackingResourceWindow(aFirstPartyWindow)); MOZ_ASSERT(aURI); - if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) { + if (StaticPrefs::network_cookie_cookieBehavior() != + nsICookieService::BEHAVIOR_REJECT_TRACKER) { return true; } if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow, nullptr, aURI)) { return true; } nsCOMPtr<nsIPrincipal> parentPrincipal = nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetPrincipal(); if (NS_WARN_IF(!parentPrincipal)) { return false; } + nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal); + if (access != nsICookiePermission::ACCESS_DEFAULT) { + return access != nsICookiePermission::ACCESS_DENY; + } + nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } NS_ConvertUTF16toUTF8 utf8Origin(origin);
--- a/toolkit/components/antitracking/AntiTrackingCommon.h +++ b/toolkit/components/antitracking/AntiTrackingCommon.h @@ -41,22 +41,25 @@ public: // For first party window, it's impossible to know if the aURI is a tracking // resource synchronously, so here we return the best guest: if we are sure // that the permission is granted for the origin of aURI, this method returns // true, otherwise false. static bool MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow, nsIURI* aURI); - // This can be called only if the a3rdPartyTrackingChannel is _really_ a 3rd - // party context and marked as tracking resource. // It returns true if the URI has access to the first party storage. + // aChannel can be a 3rd party channel, or not. static bool - IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* a3rdPartyTrackingChannel, - nsIURI* aURI); + IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI); + + // This method checks if the principal has the permission to access to the + // first party storage. + static bool + IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal); // Grant the permission for aOrigin to have access to the first party storage. // This method can handle 2 different scenarios: // - aParentWindow is a 3rd party context, it opens an aOrigin window and the // user interacts with it. We want to grant the permission at the // combination: top-level + aParentWindow + aOrigin. // Ex: example.net loads an iframe tracker.com, which opens a popup // tracker.prg and the user interacts with it. tracker.org is allowed if
--- a/toolkit/components/antitracking/test/browser/browser_script.js +++ b/toolkit/components/antitracking/test/browser/browser_script.js @@ -1,16 +1,16 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); add_task(async function() { info("Starting subResources test"); await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", true], + ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", true], ]}); await UrlClassifierTestUtils.addTestTrackers(); info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/browser_subResources.js +++ b/toolkit/components/antitracking/test/browser/browser_subResources.js @@ -1,16 +1,16 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); add_task(async function() { info("Starting subResources test"); await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", true], + ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", true], ]}); await UrlClassifierTestUtils.addTestTrackers(); info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/head.js +++ b/toolkit/components/antitracking/test/browser/head.js @@ -34,17 +34,17 @@ this.AntiTracking = { this._createCleanupTask(cleanupFunction); } } }, async _setupTest(blocking, extraPrefs) { await SpecialPowers.flushPrefEnv(); await SpecialPowers.pushPrefEnv({"set": [ - ["privacy.restrict3rdpartystorage.enabled", blocking], + ["network.cookie.cookieBehavior", blocking ? Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER : Ci.nsICookieService.BEHAVIOR_ACCEPT], ["privacy.trackingprotection.enabled", false], ["privacy.trackingprotection.pbmode.enabled", false], ["privacy.trackingprotection.annotate_channels", blocking], ]}); if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) { await SpecialPowers.pushPrefEnv({"set": extraPrefs }); }