Bug 1121643 - Add "font.system.whitelist" pref to resist font-based fingerprinting. r=jfkthame

This commit is contained in:
Arthur Edelstein 2016-08-23 00:06:07 +00:00
parent b1a1141fb3
commit cdccbe2abb
15 changed files with 220 additions and 50 deletions

View File

@ -6,6 +6,7 @@ subsuite = gpu
fail-if = (os == "win" && os_version == "5.1" && e10s) # Bug 1253862
[test_bug509244.html]
[test_bug513439.html]
[test_font_whitelist.html]
[test_overdraw.html]
# Disable test until bug 1064136 is fixed
skip-if = true

View File

@ -0,0 +1,85 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1121643
-->
<head>
<title>Test for Bug 1121643</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1121643">Mozilla Bug 1121643</a>
<span id="mono" style="font-family: monospace; font-size: 64px;">M</span>
<span id="sans" style="font-family: sans-serif; font-size: 64px;">M</span>
<span id="serif" style="font-family: serif; font-size: 64px;">M</span>
<div id="content" style="display: none">
</div>
<script class="testbody" type="application/javascript;version=1.7">
/** Test for Bug 1121643 **/
const DOMUtils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(SpecialPowers.Ci.inIDOMUtils);
// Given an element id, returns the first font face name encountered.
let fontUsed = id => {
let element = document.getElementById(id),
range = document.createRange();
range.selectNode(element);
return DOMUtils.getUsedFontFaces(range).item(0).CSSFamilyName;
}
// A map of the default mono, sans and serif fonts, obtained when
// whitelisting is disabled.
const fonts = { mono : fontUsed("mono"),
sans : fontUsed("sans"),
serif : fontUsed("serif") };
// Set the font whitelist to contain none, some, or all of the
// default mono, sans, and serif fonts. Check that the rendering
// of our three test elements uses only fonts present in the
// whitelist.
let testFontWhitelist = function* (useMono, useSans, useSerif) {
let whitelist = [];
if (useMono) {
whitelist.push(fonts.mono);
}
if (useSans) {
whitelist.push(fonts.sans);
}
if (useSerif) {
whitelist.push(fonts.serif);
}
yield SpecialPowers.pushPrefEnv({"set": [["font.system.whitelist",
whitelist.join(", ")]]});
// If whitelist is empty, then whitelisting is considered disabled
// and all fonts are allowed.
info("font whitelist: " + JSON.stringify(whitelist));
let whitelistEmpty = whitelist.length === 0;
is(useMono || whitelistEmpty, fontUsed("mono") === fonts.mono,
"Correct mono whitelisting state; got " + fontUsed("mono") + ", requested " + fonts.mono);
is(useSans || whitelistEmpty, fontUsed("sans") === fonts.sans,
"Correct sans whitelisting state; got " + fontUsed("sans") + ", requested " + fonts.sans);
is(useSerif || whitelistEmpty, fontUsed("serif") === fonts.serif,
"Correct serif whitelisting state; got " + fontUsed("serif") + ", requested " + fonts.serif);
}
// Run tests to confirm that only whitelisting fonts are present in a
// rendered page. Try turning mono, sans, and serif off and on in
// every combination.
add_task(function* () {
for (let useMono of [false, true]) {
for (let useSans of [false, true]) {
for (let useSerif of [false, true]) {
yield testFontWhitelist(useMono, useSans, useSerif);
}
}
}
});
</script>
</body>
</html>

View File

@ -739,7 +739,7 @@ gfxDWriteFontList::gfxDWriteFontList()
// Arial to avoid this.
gfxFontFamily *
gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle)
gfxDWriteFontList::GetDefaultFontForPlatform(const gfxFontStyle *aStyle)
{
nsAutoString resolvedName;
@ -855,7 +855,7 @@ enum DWriteInitError {
};
nsresult
gfxDWriteFontList::InitFontList()
gfxDWriteFontList::InitFontListForPlatform()
{
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2, t3, t4, t5; // ticks
@ -876,8 +876,6 @@ gfxDWriteFontList::InitFontList()
Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading",
false);
gfxPlatformFontList::InitFontList();
mFontSubstitutes.Clear();
mNonExistingFonts.Clear();
@ -1409,7 +1407,8 @@ gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh,
uint32_t& aCmapCount,
gfxFontFamily** aMatchedFamily)
{
bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
bool useCmaps = IsFontFamilyWhitelistActive() ||
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
if (useCmaps) {
return gfxPlatformFontList::GlobalFontFallback(aCh,

View File

@ -357,9 +357,7 @@ public:
}
// initialize font lists
virtual nsresult InitFontList();
virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
virtual nsresult InitFontListForPlatform() override;
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
uint16_t aWeight,
@ -391,6 +389,10 @@ public:
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
protected:
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
private:
friend class gfxDWriteFontFamily;

View File

@ -1053,7 +1053,7 @@ gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
// build the font entry name and create an FT2FontEntry,
// but do -not- keep a reference to the FT_Face
FT2FontEntry* fe =
RefPtr<FT2FontEntry> fe =
CreateNamedFontEntry(aFace, aEntryName.get(), aIndex);
auto& fontFamilies =
@ -1063,7 +1063,7 @@ gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
if (fe) {
NS_ConvertUTF8toUTF16 name(aFace->family_name);
BuildKeyNameFromFontName(name);
gfxFontFamily *family = fontFamilies.GetWeak(name);
RefPtr<gfxFontFamily> family = fontFamilies.GetWeak(name);
if (!family) {
family = new FT2FontFamily(name);
fontFamilies.Put(name, family);
@ -1368,7 +1368,7 @@ gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
aFLE.isHidden() ? mHiddenFontFamilies : mFontFamilies;
fe->mStandardFace = (aStdFile == kStandard);
nsAutoString name(aFLE.familyName());
gfxFontFamily *family = fontFamilies.GetWeak(name);
RefPtr<gfxFontFamily> family = fontFamilies.GetWeak(name);
if (!family) {
family = new FT2FontFamily(name);
fontFamilies.Put(name, family);
@ -1470,10 +1470,9 @@ PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
}
nsresult
gfxFT2FontList::InitFontList()
gfxFT2FontList::InitFontListForPlatform()
{
// reset font lists
gfxPlatformFontList::InitFontList();
// reset hidden font list
mHiddenFontFamilies.Clear();
LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies);
@ -1562,7 +1561,7 @@ searchDone:
}
gfxFontFamily*
gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle)
gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
{
gfxFontFamily *ff = nullptr;
#ifdef MOZ_WIDGET_GONK

View File

@ -121,8 +121,6 @@ public:
gfxFT2FontList();
virtual ~gfxFT2FontList();
virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
uint16_t aWeight,
int16_t aStretch,
@ -151,7 +149,8 @@ protected:
kStandard
} StandardFile;
virtual nsresult InitFontList();
// initialize font lists
virtual nsresult InitFontListForPlatform() override;
void AppendFaceFromFontListEntry(const FontListEntry& aFLE,
StandardFile aStdFile);
@ -185,6 +184,9 @@ protected:
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC,
FT2FontFamily::Visibility aVisibility);
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
nsTHashtable<nsStringHashKey> mSkipSpaceLookupCheckFamilies;
private:

View File

@ -985,7 +985,7 @@ gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts)
}
FcChar8* lastFamilyName = (FcChar8*)"";
gfxFontconfigFontFamily* fontFamily = nullptr;
RefPtr<gfxFontconfigFontFamily> fontFamily;
nsAutoString familyName;
for (int f = 0; f < aFontSet->nfont; f++) {
FcPattern* font = aFontSet->fonts[f];
@ -1061,13 +1061,10 @@ gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts)
}
nsresult
gfxFcPlatformFontList::InitFontList()
gfxFcPlatformFontList::InitFontListForPlatform()
{
mLastConfig = FcConfigGetCurrent();
// reset font lists
gfxPlatformFontList::InitFontList();
mLocalNames.Clear();
mFcSubstituteCache.Clear();
@ -1182,7 +1179,7 @@ gfxFcPlatformFontList::GetFontList(nsIAtom *aLangGroup,
}
gfxFontFamily*
gfxFcPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
gfxFcPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
{
// Get the default font by using a fake name to retrieve the first
// scalable font that fontconfig suggests for the given language.

View File

@ -218,16 +218,13 @@ public:
}
// initialize font lists
nsresult InitFontList() override;
virtual nsresult InitFontListForPlatform() override;
void GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts) override;
gfxFontFamily*
GetDefaultFont(const gfxFontStyle* aStyle) override;
gfxFontEntry*
LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
int16_t aStretch, uint8_t aStyle) override;
@ -280,6 +277,9 @@ protected:
static void CheckFontUpdates(nsITimer *aTimer, void *aThis);
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
#ifdef MOZ_BUNDLED_FONTS
void ActivateBundledFonts();
nsCString mBundledFontsPath;

View File

@ -652,13 +652,10 @@ gfxGDIFontList::GetFontSubstitutes()
}
nsresult
gfxGDIFontList::InitFontList()
gfxGDIFontList::InitFontListForPlatform()
{
Telemetry::AutoTimer<Telemetry::GDI_INITFONTLIST_TOTAL> timer;
// reset font lists
gfxPlatformFontList::InitFontList();
mFontSubstitutes.Clear();
mNonExistingFonts.Clear();
@ -920,7 +917,7 @@ gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily,
}
gfxFontFamily*
gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle)
gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
{
gfxFontFamily *ff = nullptr;

View File

@ -301,9 +301,7 @@ public:
}
// initialize font lists
virtual nsresult InitFontList();
virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
virtual nsresult InitFontListForPlatform() override;
bool FindAndAddFamilies(const nsAString& aFamily,
nsTArray<gfxFontFamily*>* aOutput,
@ -327,6 +325,10 @@ public:
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
protected:
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
private:
friend class gfxWindowsPlatform;

View File

@ -82,8 +82,6 @@ public:
static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight);
gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle) override;
bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
@ -110,6 +108,10 @@ public:
gfxFontStyle &aFontStyle,
float aDevPixPerCSSPixel);
protected:
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override;
private:
friend class gfxPlatformMac;
@ -117,7 +119,7 @@ private:
virtual ~gfxMacPlatformFontList();
// initialize font lists
nsresult InitFontList() override;
virtual nsresult InitFontListForPlatform() override;
// special case font faces treated as font families (set via prefs)
void InitSingleFaceList();

View File

@ -703,7 +703,7 @@ gfxMacPlatformFontList::AddFamily(CFStringRef aFamily)
nsAutoString key;
ToLowerCase(familyName, key);
gfxFontFamily* familyEntry = new gfxMacFontFamily(familyName, sizeHint);
RefPtr<gfxFontFamily> familyEntry = new gfxMacFontFamily(familyName, sizeHint);
table.Put(key, familyEntry);
// check the bad underline blacklist
@ -713,14 +713,13 @@ gfxMacPlatformFontList::AddFamily(CFStringRef aFamily)
}
nsresult
gfxMacPlatformFontList::InitFontList()
gfxMacPlatformFontList::InitFontListForPlatform()
{
nsAutoreleasePool localPool;
Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
// reset font lists
gfxPlatformFontList::InitFontList();
// reset system font list
mSystemFontFamilies.Clear();
// iterate over available families
@ -780,7 +779,7 @@ gfxMacPlatformFontList::InitSingleFaceList()
// add only if doesn't exist already
if (!mFontFamilies.GetWeak(key)) {
gfxFontFamily *familyEntry =
RefPtr<gfxFontFamily> familyEntry =
new gfxSingleFaceMacFontFamily(familyName);
// LookupLocalFont sets this, need to clear
fontEntry->mIsLocalUserFont = false;
@ -927,7 +926,8 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
uint32_t& aCmapCount,
gfxFontFamily** aMatchedFamily)
{
bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
bool useCmaps = IsFontFamilyWhitelistActive() ||
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
if (useCmaps) {
return gfxPlatformFontList::GlobalFontFallback(aCh,
@ -1017,7 +1017,7 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
}
gfxFontFamily*
gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
{
nsAutoreleasePool localPool;

View File

@ -100,6 +100,8 @@ static const char* kObservedPrefs[] = {
nullptr
};
static const char kFontSystemWhitelistPref[] = "font.system.whitelist";
// xxx - this can probably be eliminated by reworking pref font handling code
static const char *gPrefLangNames[] = {
#define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
@ -173,7 +175,8 @@ gfxPlatformFontList::MemoryReporter::CollectReports(
gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
: mFontFamilies(64), mOtherFamilyNames(16),
mBadUnderlineFamilyNames(8), mSharedCmaps(8),
mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0)
mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0),
mFontFamilyWhitelistActive(false)
{
mOtherFamilyNamesInitialized = false;
@ -191,6 +194,9 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
NS_ADDREF(gFontListPrefObserver);
Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
Preferences::RegisterCallback(FontWhitelistPrefChanged,
kFontSystemWhitelistPref);
RegisterStrongMemoryReporter(new MemoryReporter());
}
@ -200,12 +206,43 @@ gfxPlatformFontList::~gfxPlatformFontList()
ClearLangGroupPrefFonts();
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
Preferences::UnregisterCallback(FontWhitelistPrefChanged,
kFontSystemWhitelistPref);
NS_RELEASE(gFontListPrefObserver);
}
// number of CSS generic font families
const uint32_t kNumGenerics = 5;
void
gfxPlatformFontList::ApplyWhitelist()
{
nsTArray<nsString> list;
gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref, list);
uint32_t numFonts = list.Length();
mFontFamilyWhitelistActive = (numFonts > 0);
if (!mFontFamilyWhitelistActive) {
return;
}
nsTHashtable<nsStringHashKey> familyNamesWhitelist;
for (uint32_t i = 0; i < numFonts; i++) {
nsString key;
ToLowerCase(list[i], key);
familyNamesWhitelist.PutEntry(key);
}
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
// Don't continue if we only have one font left.
if (mFontFamilies.Count() == 1) {
break;
}
nsString fontFamilyName(iter.Key());
ToLowerCase(fontFamilyName);
if (!familyNamesWhitelist.Contains(fontFamilyName)) {
iter.Remove();
}
}
}
nsresult
gfxPlatformFontList::InitFontList()
{
@ -243,6 +280,12 @@ gfxPlatformFontList::InitFontList()
sPlatformFontList = this;
nsresult rv = InitFontListForPlatform();
if (NS_FAILED(rv)) {
return rv;
}
ApplyWhitelist();
return NS_OK;
}
@ -1147,6 +1190,21 @@ gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang)
return eFamily_serif;
}
gfxFontFamily*
gfxPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
{
gfxFontFamily* family = GetDefaultFontForPlatform(aStyle);
if (family) {
return family;
}
// Something has gone wrong and we were unable to retrieve a default font
// from the platform. (Likely the whitelist has blocked all potential
// default fonts.) As a last resort, we return the first font listed in
// mFontFamilies.
return mFontFamilies.Iter().Data();
}
void
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
{
@ -1598,5 +1656,11 @@ gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
}
bool
gfxPlatformFontList::IsFontFamilyWhitelistActive()
{
return mFontFamilyWhitelistActive;
}
#undef LOG
#undef LOG_ENABLED

View File

@ -114,7 +114,7 @@ public:
virtual ~gfxPlatformFontList();
// initialize font lists
virtual nsresult InitFontList();
nsresult InitFontList();
virtual void GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
@ -155,7 +155,7 @@ public:
// pure virtual functions, to be provided by concrete subclasses
// get the system default font family
virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle) = 0;
gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
// look up a font by name on the host platform
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
@ -248,6 +248,13 @@ public:
void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr,
bool aCheckEnvironment = true);
// Returns true if the font family whitelist is not empty.
bool IsFontFamilyWhitelistActive();
static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) {
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
}
protected:
class MemoryReporter final : public nsIMemoryReporter
{
@ -361,6 +368,10 @@ protected:
eFontPrefLang aPrefLang,
nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies);
virtual nsresult InitFontListForPlatform() = 0;
void ApplyWhitelist();
typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontFamilyTable;
typedef nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> FontEntryTable;
@ -372,6 +383,10 @@ protected:
SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable,
mozilla::MallocSizeOf aMallocSizeOf);
// Platform-specific helper for GetDefaultFont(...).
virtual gfxFontFamily*
GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0;
// canonical family name ==> family entry (unique, one name per family entry)
FontFamilyTable mFontFamilies;
@ -437,6 +452,8 @@ protected:
nsCOMPtr<nsILanguageAtomService> mLangService;
nsTArray<uint32_t> mCJKPrefLangs;
nsTArray<mozilla::FontFamilyType> mDefaultGenericsLangGroup;
bool mFontFamilyWhitelistActive;
};
#endif /* GFXPLATFORMFONTLIST_H_ */

View File

@ -422,7 +422,10 @@ gfxUserFontEntry::LoadNextSrc()
// src local ==> lookup and load immediately
if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
gfxFontEntry* fe =
// Don't look up local fonts if the font whitelist is being used.
gfxFontEntry* fe = gfxPlatformFontList::PlatformFontList()->
IsFontFamilyWhitelistActive() ?
nullptr :
gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
mWeight,
mStretch,