From c3a7e588283843fe15edd1b12b28400926c60ffa Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 5 May 2020 14:34:34 +0000 Subject: [PATCH] Bug 1635050 - Implement a whitelist system for cookieBehavior REJECT_FOREIGN with exceptions, r=dimi Differential Revision: https://phabricator.services.mozilla.com/D73615 --- .../antitracking/ContentBlocking.cpp | 10 ++ .../antitracking/RejectForeignAllowList.cpp | 100 ++++++++++++++++++ .../antitracking/RejectForeignAllowList.h | 42 ++++++++ toolkit/components/antitracking/moz.build | 1 + 4 files changed, 153 insertions(+) create mode 100644 toolkit/components/antitracking/RejectForeignAllowList.cpp create mode 100644 toolkit/components/antitracking/RejectForeignAllowList.h diff --git a/toolkit/components/antitracking/ContentBlocking.cpp b/toolkit/components/antitracking/ContentBlocking.cpp index 224a0a0c7217..9db3757944f6 100644 --- a/toolkit/components/antitracking/ContentBlocking.cpp +++ b/toolkit/components/antitracking/ContentBlocking.cpp @@ -31,6 +31,7 @@ #include "nsIOService.h" #include "nsIWebProgressListener.h" #include "nsScriptSecurityManager.h" +#include "RejectForeignAllowList.h" namespace mozilla { @@ -960,6 +961,11 @@ bool ContentBlocking::ShouldAllowAccessFor(nsPIDOMWindowInner* aWindow, } } else { MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)); + if (RejectForeignAllowList::Check(document)) { + LOG(("This window is whitelisted for reject foreign")); + return true; + } + blockedReason = nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN; } @@ -1166,6 +1172,10 @@ bool ContentBlocking::ShouldAllowAccessFor(nsIChannel* aChannel, nsIURI* aURI, } } else { MOZ_ASSERT(CookieJarSettings::IsRejectThirdPartyWithExceptions(behavior)); + if (httpChannel && RejectForeignAllowList::Check(httpChannel)) { + LOG(("This channel is whitelisted")); + return true; + } blockedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN; } diff --git a/toolkit/components/antitracking/RejectForeignAllowList.cpp b/toolkit/components/antitracking/RejectForeignAllowList.cpp new file mode 100644 index 000000000000..9d9ab2e3d9d9 --- /dev/null +++ b/toolkit/components/antitracking/RejectForeignAllowList.cpp @@ -0,0 +1,100 @@ +/* -*- 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 "RejectForeignAllowList.h" +#include "mozilla/dom/Document.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/StaticPtr.h" +#include "nsNetUtil.h" + +#define REJECTFOREIGNALLOWLIST_PREF \ + NS_LITERAL_CSTRING("urlclassifier.trackingAnnotationSkipURLs") +#define REJECTFOREIGNALLOWLIST_NAME NS_LITERAL_CSTRING("RejectForeignAllowList") + +namespace mozilla { + +namespace { + +StaticRefPtr gRejectForeignAllowList; + +} // namespace + +// static +bool RejectForeignAllowList::Check(dom::Document* aDocument) { + MOZ_ASSERT(aDocument); + + nsIURI* documentURI = aDocument->GetDocumentURI(); + if (!documentURI) { + return false; + } + + return GetOrCreate()->CheckInternal(documentURI); +} + +// static +bool RejectForeignAllowList::Check(nsIHttpChannel* aChannel) { + MOZ_ASSERT(aChannel); + + nsCOMPtr channelURI; + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return GetOrCreate()->CheckInternal(channelURI); +} + +// static +RejectForeignAllowList* RejectForeignAllowList::GetOrCreate() { + if (!gRejectForeignAllowList) { + gRejectForeignAllowList = new RejectForeignAllowList(); + + nsCOMPtr skipListService = + do_GetService("@mozilla.org/url-classifier/skip-list-service;1"); + if (skipListService) { + skipListService->RegisterAndRunSkipListObserver( + REJECTFOREIGNALLOWLIST_NAME, REJECTFOREIGNALLOWLIST_PREF, + gRejectForeignAllowList); + } + + RunOnShutdown([skipListService] { + if (gRejectForeignAllowList) { + if (skipListService) { + skipListService->UnregisterSkipListObserver( + REJECTFOREIGNALLOWLIST_NAME, gRejectForeignAllowList); + } + gRejectForeignAllowList = nullptr; + } + }); + } + + return gRejectForeignAllowList; +} + +bool RejectForeignAllowList::CheckInternal(nsIURI* aURI) { + MOZ_ASSERT(aURI); + return nsContentUtils::IsURIInList(aURI, mList); +} + +NS_IMETHODIMP +RejectForeignAllowList::OnSkipListUpdate(const nsACString& aList) { + mList = aList; + return NS_OK; +} + +RejectForeignAllowList::RejectForeignAllowList() = default; +RejectForeignAllowList::~RejectForeignAllowList() = default; + +NS_INTERFACE_MAP_BEGIN(RejectForeignAllowList) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, + nsIUrlClassifierSkipListObserver) + NS_INTERFACE_MAP_ENTRY(nsIUrlClassifierSkipListObserver) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(RejectForeignAllowList) +NS_IMPL_RELEASE(RejectForeignAllowList) + +} // namespace mozilla diff --git a/toolkit/components/antitracking/RejectForeignAllowList.h b/toolkit/components/antitracking/RejectForeignAllowList.h new file mode 100644 index 000000000000..56b54debd9d7 --- /dev/null +++ b/toolkit/components/antitracking/RejectForeignAllowList.h @@ -0,0 +1,42 @@ +/* -*- 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_RejectForeignAllowList_h +#define mozilla_RejectForeignAllowList_h + +#include "nsIUrlClassifierSkipListService.h" + +class nsIHttpChannel; +class nsIURI; + +namespace mozilla { + +namespace dom { +class Document; +} + +class RejectForeignAllowList final : public nsIUrlClassifierSkipListObserver { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIURLCLASSIFIERSKIPLISTOBSERVER + + static bool Check(dom::Document* aDocument); + static bool Check(nsIHttpChannel* aChannel); + + private: + static RejectForeignAllowList* GetOrCreate(); + + RejectForeignAllowList(); + ~RejectForeignAllowList(); + + bool CheckInternal(nsIURI* aURI); + + nsCString mList; +}; + +} // namespace mozilla + +#endif // mozilla_RejectForeignAllowList_h diff --git a/toolkit/components/antitracking/moz.build b/toolkit/components/antitracking/moz.build index ea94c04085bd..f1c63a92225f 100644 --- a/toolkit/components/antitracking/moz.build +++ b/toolkit/components/antitracking/moz.build @@ -54,6 +54,7 @@ UNIFIED_SOURCES += [ 'ContentBlockingNotifier.cpp', 'ContentBlockingUserInteraction.cpp', 'DynamicFpiRedirectHeuristic.cpp', + 'RejectForeignAllowList.cpp', 'SettingsChangeObserver.cpp', 'StorageAccess.cpp', 'StoragePrincipalHelper.cpp',