Commit 7db5efc6 authored by Pier Angelo Vendrame's avatar Pier Angelo Vendrame 🎃
Browse files

Bug 1787790: Normalize system fonts with RFP on. r=emilio

System fonts can leak any user customization of system fonts, or user's
locale (e.g., en-US and ja Windows have different system fonts).
Also, Linux distributions/desktop environments set default fonts in
different ways.

Customization can be detected either with font metrics, the font allowed
list is not enabled or the font is included in it, or with
getComputedStyle, that leaks the name of the font that Firefox tries to
apply.

This patch try to prevent these leaks by using a generic "sans-serif"
for all system fonts, except on macOS, where it uses "-apple-system",
and on Android, where these fonts always use Roboto.

Differential Revision: https://phabricator.services.mozilla.com/D163576
parent 1f4d976d
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentProcessMessageManager.h"
#include "mozilla/dom/Document.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "mozilla/ResultExtensions.h"
@@ -1971,13 +1972,26 @@ void gfxPlatformFontList::MaybeRemoveCmap(gfxCharacterMap* aCharMap) {
  }
}

static void GetSystemUIFontFamilies([[maybe_unused]] nsAtom* aLangGroup,
static void GetSystemUIFontFamilies(const nsPresContext* aPresContext,
                                    [[maybe_unused]] nsAtom* aLangGroup,
                                    nsTArray<nsCString>& aFamilies) {
  // TODO: On macOS, use CTCreateUIFontForLanguage or such thing (though the
  // code below ends up using [NSFont systemFontOfSize: 0.0].
  nsFont systemFont;
  gfxFontStyle fontStyle;
  nsAutoString systemFontName;
  if (aPresContext ? aPresContext->Document()->ShouldResistFingerprinting(
                         RFPTarget::Unknown)
                   : nsContentUtils::ShouldResistFingerprinting(
                         "aPresContext not available", RFPTarget::Unknown)) {
#if defined(XP_MACOSX) || defined(MOZ_WIDGET_UIKIT)
    *aFamilies.AppendElement() = "-apple-system"_ns;
    return;
#elif !defined(MOZ_WIDGET_ANDROID)
    *aFamilies.AppendElement() = "sans-serif"_ns;
    return;
#endif
  }
  if (!LookAndFeel::GetFont(StyleSystemFont::Menu, systemFontName, fontStyle)) {
    return;
  }
@@ -2013,7 +2027,7 @@ void gfxPlatformFontList::ResolveGenericFontNames(
  MOZ_ASSERT(langGroup, "null lang group for pref lang");

  if (aGenericType == StyleGenericFontFamily::SystemUi) {
    GetSystemUIFontFamilies(langGroup, genericFamilies);
    GetSystemUIFontFamilies(aPresContext, langGroup, genericFamilies);
  }

  GetFontFamiliesFromGenericFamilies(
+51 −1
Original line number Diff line number Diff line
@@ -9679,6 +9679,54 @@ already_AddRefed<nsFontMetrics> nsLayoutUtils::GetMetricsFor(
  return aPresContext->GetMetricsFor(font, params);
}

static void GetSpoofedSystemFontForRFP(LookAndFeel::FontID aFontID,
                                       gfxFontStyle& aStyle, nsAString& aName) {
#if defined(XP_MACOSX) || defined(MOZ_WIDGET_UIKIT)
  aName = u"-apple-system"_ns;
  // Values taken from a macOS 10.15 system.
  switch (aFontID) {
    case LookAndFeel::FontID::Caption:
    case LookAndFeel::FontID::Menu:
      aStyle.size = 13;
      break;
    case LookAndFeel::FontID::SmallCaption:
      aStyle.weight = gfxFontStyle::FontWeight::BOLD;
      // fall-through for font-size
      [[fallthrough]];
    case LookAndFeel::FontID::MessageBox:
    case LookAndFeel::FontID::StatusBar:
      aStyle.size = 11;
      break;
    default:
      aStyle.size = 12;
      break;
  }
#elif defined(XP_WIN)
  // Windows uses Segoe UI for Latin alphabets, but other fonts for some RTL
  // languages, so we fallback to sans-serif to fall back to the user's
  // default sans-serif. Size is 12px for all system fonts (tried in an en-US
  // system).
  aName = u"sans-serif"_ns;
  aStyle.size = 12;
#elif defined(MOZ_WIDGET_ANDROID)
  // Keep consistency with nsLookAndFeel::NativeGetFont.
  aName = u"Roboto"_ns;
  aStyle.size = 12;
#elif defined(MOZ_WIDGET_GTK)
  // On Linux, there is not a default. For example, GNOME on Debian uses
  // Cantarell, 14.667px. Ubuntu Mate uses the Ubuntu font, but also 14.667px.
  // Fedora with KDE uses Noto Sans, 13.3333px, but it uses Noto Sans on
  // GNOME, too.
  // In general, Linux uses some sans-serif, but its size can vary between
  // 12px and 16px. We chose 15px because it is what Firefox is doing for the
  // UI font-size.
  aName = u"sans-serif"_ns;
  aStyle.size = 15;
#else
#  error "Unknown platform"
#endif
}

/* static */
void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont,
                                      LookAndFeel::FontID aFontID,
@@ -9686,7 +9734,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont,
                                      const Document* aDocument) {
  gfxFontStyle fontStyle;
  nsAutoString systemFontName;
  if (!LookAndFeel::GetFont(aFontID, systemFontName, fontStyle)) {
  if (aDocument->ShouldResistFingerprinting(RFPTarget::Unknown)) {
    GetSpoofedSystemFontForRFP(aFontID, fontStyle, systemFontName);
  } else if (!LookAndFeel::GetFont(aFontID, systemFontName, fontStyle)) {
    return;
  }
  systemFontName.Trim("\"'");
+3 −0
Original line number Diff line number Diff line
@@ -195,3 +195,6 @@ pref(ui.font.menu,"serif") test-pref(ui.font.menu.weight,"800") != system-font-p

# Reset default prefs.
defaults

# Bug 1787790 - Normalize system fonts when using RFP
test-pref(privacy.resistFingerprinting,true) == system-font-rfp.html system-font-rfp-ref.html
+44 −0
Original line number Diff line number Diff line
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
  font-family: -apple-system, sans-serif;
  font-size: 12px;
}

.android {
  font-family: Roboto;
}

.linux {
  font-size: 15px;
}

.mac {
  .caption, .menu {
    font-size: 13px;
  }
  .message-box, .status-bar {
    font-size: 11px;
  }
  .small-caption {
    font-size: 11px;
    font-weight: 700;
  }
}
</style>
<div class="caption">Caption</div>
<div class="icon">Icon</div>
<div class="menu">Menu</div>
<div class="message-box">Message box</div>
<div class="small-caption">Small caption</div>
<div class="status-bar">Status bar</div>
<script>
if (navigator.platform.startsWith("Mac")) {
  document.querySelector("body").className = "mac";
} else if (navigator.userAgent.includes("Android")) {
  document.querySelector("body").className = "android";
} else if (navigator.platform.startsWith("Linux")) {
  document.querySelector("body").className = "linux";
}
</script>
+8 −0
Original line number Diff line number Diff line
<!DOCTYPE html>
<meta charset="utf-8">
<div style="font: caption">Caption</div>
<div style="font: icon">Icon</div>
<div style="font: menu">Menu</div>
<div style="font: message-box">Message box</div>
<div style="font: small-caption">Small caption</div>
<div style="font: status-bar">Status bar</div>