commit 235ee754cf9f1e18925e9c10cf14e4f3be155b8b
parent 77a7566252f4d7b36c1f1fa5ae7e77dde870c044
Author: Tom Ritter <tom@mozilla.com>
Date: Tue, 9 Dec 2025 16:34:58 +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:
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);