author | Andrea Marchesini <amarchesini@mozilla.com> |
Wed, 09 Jan 2019 12:16:04 +0100 | |
changeset 453039 | d503dc3fd033d3c2e6bbde69f60e7665fb69efe6 |
parent 453038 | a11f752f828ceca6aed6cda69fc336f4624434fc |
child 453040 | 99db2eabbf072cc9915d0b4956d20b1ec2f2eb28 |
push id | 35341 |
push user | csabou@mozilla.com |
push date | Wed, 09 Jan 2019 16:06:01 +0000 |
treeherder | mozilla-central@29b2c2f57879 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dimi |
bugs | 1513300 |
milestone | 66.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/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -1786,16 +1786,23 @@ VARCACHE_PREF( // Block 3rd party fingerprinting resources. VARCACHE_PREF( "privacy.trackingprotection.fingerprinting.enabled", privacy_trackingprotection_fingerprinting_enabled, bool, true ) +// Block 3rd party cryptomining resources. +VARCACHE_PREF( + "privacy.trackingprotection.cryptomining.enabled", + privacy_trackingprotection_cryptomining_enabled, + bool, true +) + // Lower the priority of network loads for resources on the tracking protection // list. Note that this requires the // privacy.trackingprotection.annotate_channels pref to be on in order to have // any effect. #ifdef NIGHTLY_BUILD # define PREF_VALUE true #else # define PREF_VALUE false
--- a/netwerk/url-classifier/UrlClassifierCommon.cpp +++ b/netwerk/url-classifier/UrlClassifierCommon.cpp @@ -88,17 +88,18 @@ LazyLogModule UrlClassifierCommon::sLog( } /* static */ bool UrlClassifierCommon::ShouldEnableClassifier( nsIChannel* aChannel, AntiTrackingCommon::ContentBlockingAllowListPurpose aBlockingPurpose) { MOZ_ASSERT(aChannel); MOZ_ASSERT(aBlockingPurpose == AntiTrackingCommon::eTrackingProtection || aBlockingPurpose == AntiTrackingCommon::eTrackingAnnotations || - aBlockingPurpose == AntiTrackingCommon::eFingerprinting); + aBlockingPurpose == AntiTrackingCommon::eFingerprinting || + aBlockingPurpose == AntiTrackingCommon::eCryptomining); nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel); if (!channel) { UC_LOG(("nsChannelClassifier: Not an HTTP channel")); return false; } nsCOMPtr<nsIURI> chanURI;
new file mode 100644 --- /dev/null +++ b/netwerk/url-classifier/UrlClassifierFeatureCryptomining.cpp @@ -0,0 +1,175 @@ +/* -*- 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 "UrlClassifierFeatureCryptomining.h" + +#include "mozilla/AntiTrackingCommon.h" +#include "mozilla/net/UrlClassifierCommon.h" +#include "mozilla/StaticPrefs.h" +#include "nsContentUtils.h" +#include "nsNetUtil.h" + +namespace mozilla { +namespace net { + +namespace { + +#define CRYPTOMINING_FEATURE_NAME "cryptomining" + +#define URLCLASSIFIER_CRYPTOMINING_BLACKLIST \ + "urlclassifier.features.cryptomining.blacklistTables" +#define URLCLASSIFIER_CRYPTOMINING_BLACKLIST_TEST_ENTRIES \ + "urlclassifier.features.cryptomining.blacklistHosts" +#define URLCLASSIFIER_CRYPTOMINING_WHITELIST \ + "urlclassifier.features.cryptomining.whitelistTables" +#define URLCLASSIFIER_CRYPTOMINING_WHITELIST_TEST_ENTRIES \ + "urlclassifier.features.cryptomining.whitelistHosts" +#define TABLE_CRYPTOMINING_BLACKLIST_PREF "cryptomining-blacklist-pref" +#define TABLE_CRYPTOMINING_WHITELIST_PREF "cryptomining-whitelist-pref" + +StaticRefPtr<UrlClassifierFeatureCryptomining> gFeatureCryptomining; + +} // namespace + +UrlClassifierFeatureCryptomining::UrlClassifierFeatureCryptomining() + : UrlClassifierFeatureBase( + NS_LITERAL_CSTRING(CRYPTOMINING_FEATURE_NAME), + NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_BLACKLIST), + NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_WHITELIST), + NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_BLACKLIST_TEST_ENTRIES), + NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_WHITELIST_TEST_ENTRIES), + NS_LITERAL_CSTRING(TABLE_CRYPTOMINING_BLACKLIST_PREF), + NS_LITERAL_CSTRING(TABLE_CRYPTOMINING_WHITELIST_PREF), + EmptyCString()) {} + +/* static */ const char* UrlClassifierFeatureCryptomining::Name() { + return CRYPTOMINING_FEATURE_NAME; +} + +/* static */ void UrlClassifierFeatureCryptomining::MaybeInitialize() { + UC_LOG(("UrlClassifierFeatureCryptomining: MaybeInitialize")); + + if (!gFeatureCryptomining) { + gFeatureCryptomining = new UrlClassifierFeatureCryptomining(); + gFeatureCryptomining->InitializePreferences(); + } +} + +/* static */ void UrlClassifierFeatureCryptomining::MaybeShutdown() { + UC_LOG(("UrlClassifierFeatureCryptomining: MaybeShutdown")); + + if (gFeatureCryptomining) { + gFeatureCryptomining->ShutdownPreferences(); + gFeatureCryptomining = nullptr; + } +} + +/* static */ already_AddRefed<UrlClassifierFeatureCryptomining> +UrlClassifierFeatureCryptomining::MaybeCreate(nsIChannel* aChannel) { + MOZ_ASSERT(aChannel); + + UC_LOG(("UrlClassifierFeatureCryptomining: MaybeCreate for channel %p", + aChannel)); + + if (!StaticPrefs::privacy_trackingprotection_cryptomining_enabled()) { + return nullptr; + } + + nsCOMPtr<nsIURI> chanURI; + nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + bool isThirdParty = + nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, chanURI); + if (!isThirdParty) { + if (UC_LOG_ENABLED()) { + nsCString spec = chanURI->GetSpecOrDefault(); + spec.Truncate( + std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength)); + UC_LOG( + ("UrlClassifierFeatureCryptomining: Skipping cryptomining checks " + "for first party or top-level load channel[%p] " + "with uri %s", + aChannel, spec.get())); + } + + return nullptr; + } + + if (!UrlClassifierCommon::ShouldEnableClassifier( + aChannel, AntiTrackingCommon::eCryptomining)) { + return nullptr; + } + + MaybeInitialize(); + MOZ_ASSERT(gFeatureCryptomining); + + RefPtr<UrlClassifierFeatureCryptomining> self = gFeatureCryptomining; + return self.forget(); +} + +/* static */ already_AddRefed<nsIUrlClassifierFeature> +UrlClassifierFeatureCryptomining::GetIfNameMatches(const nsACString& aName) { + if (!aName.EqualsLiteral(CRYPTOMINING_FEATURE_NAME)) { + return nullptr; + } + + MaybeInitialize(); + MOZ_ASSERT(gFeatureCryptomining); + + RefPtr<UrlClassifierFeatureCryptomining> self = gFeatureCryptomining; + return self.forget(); +} + +NS_IMETHODIMP +UrlClassifierFeatureCryptomining::ProcessChannel(nsIChannel* aChannel, + const nsACString& aList, + bool* aShouldContinue) { + NS_ENSURE_ARG_POINTER(aChannel); + NS_ENSURE_ARG_POINTER(aShouldContinue); + + // This is a blocking feature. + *aShouldContinue = false; + + UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_TRACKING_URI, aList, + EmptyCString(), EmptyCString()); + + UC_LOG( + ("UrlClassifierFeatureCryptomining::ProcessChannel, cancelling " + "channel[%p]", + aChannel)); + nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel); + + // FIXME: the way we cancel the channel depends on what the UI wants to show. + // This needs to change, at some point. + if (httpChannel) { + Unused << httpChannel->CancelForTrackingProtection(); + } else { + Unused << aChannel->Cancel(NS_ERROR_TRACKING_URI); + } + + return NS_OK; +} + +NS_IMETHODIMP +UrlClassifierFeatureCryptomining::GetURIByListType( + nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType, + nsIURI** aURI) { + NS_ENSURE_ARG_POINTER(aChannel); + NS_ENSURE_ARG_POINTER(aURI); + + if (aListType == nsIUrlClassifierFeature::blacklist) { + return aChannel->GetURI(aURI); + } + + MOZ_ASSERT(aListType == nsIUrlClassifierFeature::whitelist); + return UrlClassifierCommon::CreatePairwiseWhiteListURI(aChannel, aURI); +} + +} // namespace net +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/netwerk/url-classifier/UrlClassifierFeatureCryptomining.h @@ -0,0 +1,45 @@ +/* -*- 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_net_UrlClassifierFeatureCryptomining_h +#define mozilla_net_UrlClassifierFeatureCryptomining_h + +#include "UrlClassifierFeatureBase.h" + +class nsIChannel; + +namespace mozilla { +namespace net { + +class UrlClassifierFeatureCryptomining final : public UrlClassifierFeatureBase { + public: + static const char* Name(); + + static void MaybeShutdown(); + + static already_AddRefed<UrlClassifierFeatureCryptomining> MaybeCreate( + nsIChannel* aChannel); + + static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches( + const nsACString& aName); + + NS_IMETHOD ProcessChannel(nsIChannel* aChannel, const nsACString& aList, + bool* aShouldContinue) override; + + NS_IMETHOD GetURIByListType(nsIChannel* aChannel, + nsIUrlClassifierFeature::listType aListType, + nsIURI** aURI) override; + + private: + UrlClassifierFeatureCryptomining(); + + static void MaybeInitialize(); +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_UrlClassifierFeatureCryptomining_h
--- a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp +++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp @@ -2,16 +2,17 @@ /* 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 "mozilla/net/UrlClassifierFeatureFactory.h" // List of Features +#include "UrlClassifierFeatureCryptomining.h" #include "UrlClassifierFeatureFingerprinting.h" #include "UrlClassifierFeatureFlash.h" #include "UrlClassifierFeatureLoginReputation.h" #include "UrlClassifierFeatureTrackingProtection.h" #include "UrlClassifierFeatureTrackingAnnotation.h" #include "UrlClassifierFeatureCustomTables.h" #include "nsAppRunner.h" @@ -20,16 +21,17 @@ namespace mozilla { namespace net { /* static */ void UrlClassifierFeatureFactory::Shutdown() { // We want to expose Features only in the parent process. if (!XRE_IsParentProcess()) { return; } + UrlClassifierFeatureCryptomining::MaybeShutdown(); UrlClassifierFeatureFingerprinting::MaybeShutdown(); UrlClassifierFeatureFlash::MaybeShutdown(); UrlClassifierFeatureLoginReputation::MaybeShutdown(); UrlClassifierFeatureTrackingAnnotation::MaybeShutdown(); UrlClassifierFeatureTrackingProtection::MaybeShutdown(); } /* static */ void UrlClassifierFeatureFactory::GetFeaturesFromChannel( @@ -40,16 +42,22 @@ namespace net { nsCOMPtr<nsIUrlClassifierFeature> feature; // Note that the order of the features is extremely important! When more than // 1 feature classifies the channel, we call ::ProcessChannel() following this // feature order, and this could produce different results with a different // feature ordering. + // Cryptomining + feature = UrlClassifierFeatureCryptomining::MaybeCreate(aChannel); + if (feature) { + aFeatures.AppendElement(feature); + } + // Fingerprinting feature = UrlClassifierFeatureFingerprinting::MaybeCreate(aChannel); if (feature) { aFeatures.AppendElement(feature); } // Tracking Protection feature = UrlClassifierFeatureTrackingProtection::MaybeCreate(aChannel); @@ -78,16 +86,22 @@ UrlClassifierFeatureFactory::GetFeatureL /* static */ already_AddRefed<nsIUrlClassifierFeature> UrlClassifierFeatureFactory::GetFeatureByName(const nsACString& aName) { if (!XRE_IsParentProcess()) { return nullptr; } nsCOMPtr<nsIUrlClassifierFeature> feature; + // Cryptomining + feature = UrlClassifierFeatureCryptomining::GetIfNameMatches(aName); + if (feature) { + return feature.forget(); + } + // Fingerprinting feature = UrlClassifierFeatureFingerprinting::GetIfNameMatches(aName); if (feature) { return feature.forget(); } // Tracking Protection feature = UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aName); @@ -117,18 +131,24 @@ UrlClassifierFeatureFactory::GetFeatureB } /* static */ void UrlClassifierFeatureFactory::GetFeatureNames( nsTArray<nsCString>& aArray) { if (!XRE_IsParentProcess()) { return; } + // Cryptomining + nsAutoCString name; + name.Assign(UrlClassifierFeatureCryptomining::Name()); + if (!name.IsEmpty()) { + aArray.AppendElement(name); + } + // Fingerprinting - nsAutoCString name; name.Assign(UrlClassifierFeatureFingerprinting::Name()); if (!name.IsEmpty()) { aArray.AppendElement(name); } // Tracking Protection name.Assign(UrlClassifierFeatureTrackingProtection::Name()); if (!name.IsEmpty()) {
--- a/netwerk/url-classifier/moz.build +++ b/netwerk/url-classifier/moz.build @@ -17,16 +17,17 @@ XPIDL_MODULE = 'url-classifier' DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True UNIFIED_SOURCES += [ 'AsyncUrlChannelClassifier.cpp', 'nsChannelClassifier.cpp', 'UrlClassifierCommon.cpp', 'UrlClassifierFeatureBase.cpp', + 'UrlClassifierFeatureCryptomining.cpp', 'UrlClassifierFeatureCustomTables.cpp', 'UrlClassifierFeatureFactory.cpp', 'UrlClassifierFeatureFingerprinting.cpp', 'UrlClassifierFeatureFlash.cpp', 'UrlClassifierFeatureLoginReputation.cpp', 'UrlClassifierFeatureResult.cpp', 'UrlClassifierFeatureTrackingAnnotation.cpp', 'UrlClassifierFeatureTrackingProtection.cpp',
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -1369,17 +1369,19 @@ nsresult AntiTrackingCommon::IsOnContent // For storage checks, check the storage pref, and for annotations checks, // check the corresponding pref as well. This allows each set of checks to // be disabled individually if needed. if ((aPurpose == eStorageChecks && !StaticPrefs::browser_contentblocking_allowlist_storage_enabled()) || (aPurpose == eTrackingAnnotations && !StaticPrefs::browser_contentblocking_allowlist_annotations_enabled()) || (aPurpose == eFingerprinting && - !StaticPrefs::privacy_trackingprotection_fingerprinting_enabled())) { + !StaticPrefs::privacy_trackingprotection_fingerprinting_enabled()) || + (aPurpose == eCryptomining && + !StaticPrefs::privacy_trackingprotection_cryptomining_enabled())) { LOG( ("Attempting to check the content blocking allow list aborted because " "the third-party cookies UI has been disabled.")); return NS_OK; } LOG_SPEC(("Deciding whether the user has overridden content blocking for %s", _spec),
--- a/toolkit/components/antitracking/AntiTrackingCommon.h +++ b/toolkit/components/antitracking/AntiTrackingCommon.h @@ -116,16 +116,17 @@ class AntiTrackingCommon final { const nsCString& aParentOrigin, const nsCString& aGrantedOrigin, int aAllowMode); enum ContentBlockingAllowListPurpose { eStorageChecks, eTrackingProtection, eTrackingAnnotations, eFingerprinting, + eCryptomining, }; // Check whether a top window URI is on the content blocking allow list. static nsresult IsOnContentBlockingAllowList( nsIURI* aTopWinURI, bool aIsPrivateBrowsing, ContentBlockingAllowListPurpose aPurpose, bool& aIsAllowListed); enum class BlockingDecision {
--- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini +++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini @@ -41,8 +41,9 @@ skip-if = (os == 'linux' && debug) #Bug skip-if = (verify && debug && (os == 'win' || os == 'mac')) [test_classify_track.html] [test_gethash.html] [test_bug1254766.html] [test_cachemiss.html] skip-if = verify [test_annotation_vs_TP.html] [test_fingerprinting.html] +[test_cryptomining.html]
new file mode 100644 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/test_cryptomining.html @@ -0,0 +1,106 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test the cryptomining classifier</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> +<script class="testbody" type="text/javascript"> + +/* eslint-env mozilla/frame-script */ + +var tests = [ + // All disabled. + { config: [ false, false ], loadExpected: true }, + + // Just whitelisted. + { config: [ false, true ], loadExpected: true }, + + // Just blacklisted. + { config: [ true, false ], loadExpected: false }, + + // whitelist + blacklist: whitelist wins + { config: [ true, true ], loadExpected: true }, +]; + +function prefValue(value, what) { + return value ? what : ""; +} + +async function runTest(test) { + await SpecialPowers.pushPrefEnv({set: [ + [ "urlclassifier.features.cryptomining.blacklistHosts", prefValue(test.config[0], "example.com") ], + [ "urlclassifier.features.cryptomining.whitelistHosts", prefValue(test.config[1], "mochi.test") ], + [ "urlclassifier.features.cryptomining.blacklistTables", prefValue(test.config[0], "mochitest1-track-simple") ], + [ "urlclassifier.features.cryptomining.whitelistTables", "" ], + [ "privacy.trackingprotection.enabled", false ], + [ "privacy.trackingprotection.annotate_channels", false ], + [ "privacy.trackingprotection.cryptomining.enabled", true ], + [ "privacy.trackingprotection.fingerprinting.enabled", false ], + ]}); + + info("Testing: " + test.config.toSource() + "\n"); + + // Let's load an image with a random query string, just to avoid network cache. + let result = await new Promise(resolve => { + let image = new Image(); + image.src = "http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg?" + Math.random(); + image.onload = _ => resolve(true); + image.onerror = _ => resolve(false); + }); + + is(result, test.loadExpected, "The loading happened correctly"); + + // Let's load an image with a random query string, just to avoid network cache. + result = await new Promise(resolve => { + let image = new Image(); + image.src = "http://tracking.example.org/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg?" + Math.random(); + image.onload = _ => resolve(true); + image.onerror = _ => resolve(false); + }); + + is(result, test.loadExpected, "The loading happened correctly (by table)"); +} + +async function runTests() { + let chromeScript = SpecialPowers.loadChromeScript(_ => { + ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm"); + + addMessageListener("loadTrackers", __ => { + UrlClassifierTestUtils.addTestTrackers().then(___ => { + sendAsyncMessage("trackersLoaded"); + }); + }); + + addMessageListener("unloadTrackers", __ => { + UrlClassifierTestUtils.cleanupTestTrackers(); + sendAsyncMessage("trackersUnloaded"); + }); + }); + + await new Promise(resolve => { + chromeScript.addMessageListener("trackersLoaded", resolve); + chromeScript.sendAsyncMessage("loadTrackers"); + }); + + for (let test in tests) { + await runTest(tests[test]); + } + + await new Promise(resolve => { + chromeScript.addMessageListener("trackersUnloaded", resolve); + chromeScript.sendSyncMessage("unloadTrackers"); + }); + + chromeScript.destroy(); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +runTests(); + +</script> +</body> +</html>
--- a/toolkit/components/url-classifier/tests/mochitest/test_fingerprinting.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_fingerprinting.html @@ -32,16 +32,17 @@ function prefValue(value, what) { async function runTest(test) { await SpecialPowers.pushPrefEnv({set: [ [ "urlclassifier.features.fingerprinting.blacklistHosts", prefValue(test.config[0], "example.com") ], [ "urlclassifier.features.fingerprinting.whitelistHosts", prefValue(test.config[1], "mochi.test") ], [ "urlclassifier.features.fingerprinting.blacklistTables", prefValue(test.config[0], "mochitest1-track-simple") ], [ "urlclassifier.features.fingerprinting.whitelistTables", "" ], [ "privacy.trackingprotection.enabled", false ], [ "privacy.trackingprotection.annotate_channels", false ], + [ "privacy.trackingprotection.cryptomining.enabled", false ], [ "privacy.trackingprotection.fingerprinting.enabled", true ], ]}); info("Testing: " + test.config.toSource() + "\n"); // Let's load an image with a random query string, just to avoid network cache. let result = await new Promise(resolve => { let image = new Image();