tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a66fab0931d975204ebe2cf943bf6885c756acf1
parent 8c90d9ae564a073cbdb3be184c60bc166c20c0c4
Author: Tom Ritter <tom@mozilla.com>
Date:   Mon,  8 Dec 2025 16:31:01 +0000

Bug 1873716: Switch to using a bitmask for known text r=timhuang

SKIP_BMO_CHECK

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

Diffstat:
Mdom/canvas/CanvasRenderingContext2D.cpp | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mtoolkit/components/resistfingerprinting/nsRFPService.cpp | 26++++++++++++--------------
Mtoolkit/components/resistfingerprinting/nsRFPService.h | 45+++++++++++++++++++++++++++++++++++++++------
3 files changed, 111 insertions(+), 38 deletions(-)

diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp @@ -135,6 +135,8 @@ using namespace mozilla::image; using namespace mozilla::ipc; using namespace mozilla::layers; +static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection"); + namespace mozilla::dom { // Cap sigma to avoid overly large temp surfaces. @@ -4566,25 +4568,65 @@ void CanvasRenderingContext2D::FillText(const nsAString& aText, double aX, const Optional<double>& aMaxWidth, ErrorResult& aError) { // We try to match the most commonly observed strings used by canvas - // fingerprinting scripts. We do a prefix match, because that means having to - // match fewer bytes and sometimes the strings is followed by a few random - // characters. - // - Cwm fjordbank gly - // Used by FingerprintJS - // (https://github.com/fingerprintjs/fingerprintjs/blob/4c4b2c8455e701b8341b2b766d1939cf5de4b615/src/sources/canvas.ts#L119) - // and others - // - Hel$&?6%){mZ+#@ - // - <@nv45. F1n63r,Pr1n71n6! - // Usually there are at most a handful (usually ~1/2) fillText calls by - // fingerprinters + // fingerprinting scripts. + MOZ_LOG(gFingerprinterDetection, LogLevel::Verbose, + ("mFillTextCalls %i FillText: " + "\"%s\"\n", + mFillTextCalls, NS_ConvertUTF16toUTF8(aText).get())); if (mFillTextCalls <= 5) { - if (StringBeginsWith(aText, u"Cwm fjord"_ns) || - StringBeginsWith(aText, u"Hel$&?6%"_ns) || - StringBeginsWith(aText, u"<@nv45. "_ns)) { - mFeatureUsage |= CanvasFeatureUsage::KnownFingerprintText; - } - mFillTextCalls++; - } + if (aText == u"Cwm fjordbank glyphs vext quiz, 😃"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_1; + } else if (aText == u"Cwm fjordbank gly 😃"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_1; + } else if (StringBeginsWith(aText, u"Hel$&?6%"_ns)) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_2; + } else if (StringBeginsWith(aText, u"<@nv45. "_ns)) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_3; + } else if (aText == u"Cañvas FP 😎 12345"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_4; + } else if (StringBeginsWith(aText, u"❤️🤪🎉👋"_ns)) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_5; + } else if (aText == u"SomeCanvasFingerPrint.65@345876"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_6; + } else if (aText == u"Browser,Signal <canvas> 2.0"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_7; + } else if (aText == u"@Browsers~%fingGPRint$&,<canvas>"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_8; + } else if (aText == u"M"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_9; + } else if (aText == u"E"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_10; + } else if (aText == u"g"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_11; + } else if (aText == u"Soft Ruddy Foothold 2"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_12; + } else if (aText == u"!H71JCaj)]# 1@#"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_13; + } else if (aText == u"oubrg5h56e@!$3t4"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_14; + } else if (aText == u"Cwm fjordbank glyphs vext quiz,"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_15; + } else if (aText == u"ClientJS,org <canvas> 1.0"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_16; + } else if (aText == u"IaID,org <canvas> 1.0"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_17; + } else if (aText == u"conviva"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_18; + } else if (aText == u"Random Text WMwmil10Oo"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_19; + } else if (aText == u"-0.5753861119575491"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_20; + } else if (aText == u"0.8178819121159085"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_21; + } else if (StringBeginsWith(aText, u"Cwm fjordbank"_ns)) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_22; + } else if (StringBeginsWith(aText, u"iO0A"_ns)) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_23; + } else if (aText == u"<@nv45. F1n63r,Pr1n71n6!"_ns) { + mFeatureUsage |= CanvasFeatureUsage::KnownText_24; + } + } + mFillTextCalls++; DebugOnly<UniquePtr<TextMetrics>> metrics = DrawOrMeasureText( aText, aX, aY, aMaxWidth, TextDrawOperation::FILL, aError); diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -1986,7 +1986,7 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, bool seenExtracted2D_240x60 = false; bool seenExtracted2D_280x60 = false; bool seenExtracted2D_860x6 = false; - CanvasFeatureUsage featureUsage = CanvasFeatureUsage::None; + CanvasFeatureUsage accumulatedFeatureUsage = CanvasFeatureUsage::None; uint32_t extractedOther = 0; @@ -2000,7 +2000,7 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, } if (usage.mType == dom::CanvasContextType::Canvas2D) { - featureUsage |= usage.mFeatureUsage; + accumulatedFeatureUsage |= usage.mFeatureUsage; extracted2D++; if (width == 16 && height == 16) { seenExtracted2D_16x16 = true; @@ -2024,6 +2024,8 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, } CanvasFingerprinterAlias fingerprinter = eNoneIdentified; + uint32_t knownTextBitmask = static_cast<uint32_t>( + static_cast<uint64_t>(accumulatedFeatureUsage) & 0xFFFFFFFFu); if (seenExtractedWebGL_300x150 && seenExtracted2D_240x60 && seenExtracted2D_122x110) { @@ -2032,14 +2034,15 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, seenExtracted2D_16x16) { fingerprinter = CanvasFingerprinterAlias::eAkamai; } else if (seenExtractedWebGL_300x150 && extracted2D > 0 && - (featureUsage & CanvasFeatureUsage::SetFont)) { + (accumulatedFeatureUsage & CanvasFeatureUsage::SetFont)) { fingerprinter = CanvasFingerprinterAlias::eVariant1; } else if (extractedWebGL > 0 && extracted2D > 1 && seenExtracted2D_860x6) { fingerprinter = CanvasFingerprinterAlias::eVariant2; } else if (extractedOther > 0 && (extractedWebGL > 0 || extracted2D > 0)) { fingerprinter = CanvasFingerprinterAlias::eVariant3; - } else if (extracted2D > 0 && (featureUsage & CanvasFeatureUsage::SetFont) && - (featureUsage & + } else if (extracted2D > 0 && + (accumulatedFeatureUsage & CanvasFeatureUsage::SetFont) && + (accumulatedFeatureUsage & (CanvasFeatureUsage::FillRect | CanvasFeatureUsage::LineTo | CanvasFeatureUsage::Stroke))) { fingerprinter = CanvasFingerprinterAlias::eVariant4; @@ -2049,9 +2052,7 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, fingerprinter = CanvasFingerprinterAlias::eMaybe; } - bool knownFingerprintText = - bool(featureUsage & CanvasFeatureUsage::KnownFingerprintText); - if (!knownFingerprintText && fingerprinter == eNoneIdentified) { + if (knownTextBitmask == 0 && fingerprinter == eNoneIdentified) { return; } @@ -2068,12 +2069,9 @@ static void MaybeCurrentCaller(nsACString& aFilename, uint32_t& aLineNum, MOZ_LOG( gFingerprinterDetection, LogLevel::Info, ("Detected a potential canvas fingerprinter on %s in script %s:%d:%d " - "(KnownFingerprintText: %s, CanvasFingerprinter: %s)", - origin.get(), filename.get(), lineNum, columnNum, - knownFingerprintText ? "true" : "false", - fingerprinter.isSome() - ? CanvasFingerprinterToString(fingerprinter.value()) - : "<none>")); + "(KnownFingerprintTextBitmask: %u, CanvasFingerprinterAlias: %s)", + origin.get(), filename.get(), lineNum, columnNum, knownTextBitmask, + CanvasFingerprinterToString(fingerprinter))); } ContentBlockingNotifier::OnEvent( diff --git a/toolkit/components/resistfingerprinting/nsRFPService.h b/toolkit/components/resistfingerprinting/nsRFPService.h @@ -164,13 +164,46 @@ enum TimerPrecisionType { // ============================================================================ -enum class CanvasFeatureUsage : uint8_t { +enum class CanvasFeatureUsage : uint64_t { None = 0, - KnownFingerprintText = 1 << 0, - SetFont = 1 << 1, - FillRect = 1 << 2, - LineTo = 1 << 3, - Stroke = 1 << 4 + + KnownText_1 = 1llu << 0, + KnownText_2 = 1llu << 1, + KnownText_3 = 1llu << 2, + KnownText_4 = 1llu << 3, + KnownText_5 = 1llu << 4, + KnownText_6 = 1llu << 5, + KnownText_7 = 1llu << 6, + KnownText_8 = 1llu << 7, + KnownText_9 = 1llu << 8, + KnownText_10 = 1llu << 9, + KnownText_11 = 1llu << 10, + KnownText_12 = 1llu << 11, + KnownText_13 = 1llu << 12, + KnownText_14 = 1llu << 13, + KnownText_15 = 1llu << 14, + KnownText_16 = 1llu << 15, + KnownText_17 = 1llu << 16, + KnownText_18 = 1llu << 17, + KnownText_19 = 1llu << 18, + KnownText_20 = 1llu << 19, + KnownText_21 = 1llu << 20, + KnownText_22 = 1llu << 21, + KnownText_23 = 1llu << 22, + KnownText_24 = 1llu << 23, + KnownText_25 = 1llu << 24, + KnownText_26 = 1llu << 25, + KnownText_27 = 1llu << 26, + KnownText_28 = 1llu << 27, + KnownText_29 = 1llu << 28, + KnownText_30 = 1llu << 29, + KnownText_31 = 1llu << 30, + KnownText_32 = 1llu << 31, + + SetFont = 1llu << 32, + FillRect = 1llu << 33, + LineTo = 1llu << 34, + Stroke = 1llu << 35, }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CanvasFeatureUsage);