High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the Layout: Text and Fonts component
ComponentGraphics
Bug ClassLogic Error
Tracker2070264
Fix commit3d87e25210a8 (firefox) +53/-27
CISA KEVNot listed
Credited5up3rh3i
Disclosed2026-09-29

Changed Functions

FunctionChangeNotes
if
gfx/thebes/gfxDWriteFontList.cpp
modified

Files Changed

  • gfx/thebes/gfxDWriteFontList.cpp
  • gfx/thebes/gfxDWriteFontList.h
  • gfx/thebes/gfxFontEntry.h
diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp
index ed6761af2d8..e0ebe5b998e 100644
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -500,10 +500,15 @@ static void DestroyBlobFunc(void* aUserData) {
 }
 
 hb_blob_t* gfxDWriteFontEntry::GetFontTableInternal(uint32_t aTag) {
-  // try to avoid potentially expensive DWrite call if we haven't actually
+  // Try to avoid potentially expensive DWrite call if we haven't actually
   // created the font face yet, by using the gfxFontEntry method that will
-  // use CopyFontTable and then cache the data
-  if (!mFontFace) {
+  // use CopyFontTable and then cache the data.
+  RefPtr<IDWriteFontFace> fontFace;
+  {
+    AutoReadLock lock(mLock);
+    fontFace = mFontFace;
+  }
+  if (!fontFace) {
     return gfxFontEntry::GetFontTableInternal(aTag);
   }
 
@@ -511,10 +516,10 @@ hb_blob_t* gfxDWriteFontEntry::GetFontTableInternal(uint32_t aTag) {
   UINT32 size;
   void* context;
   BOOL exists;
-  HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
-                                          &data, &size, &context, &exists);
+  HRESULT hr = fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
+                                         &data, &size, &context, &exists);
   if (SUCCEEDED(hr) && exists) {
-    FontTableRec* ftr = new FontTableRec(mFontFace, context);
+    FontTableRec* ftr = new FontTableRec(fontFace, context);
     return hb_blob_create(static_cast<const char*>(data), size,
                           HB_MEMORY_MODE_READONLY, ftr, DestroyBlobFunc);
   }
@@ -621,17 +626,26 @@ bool gfxDWriteFontEntry::HasVariationsInternal() {
     return mHasVariations;
   }
 
-  if (!mFontFace) {
-    // CreateFontFace will initialize the mFontFace field, and also
-    // mFontFace5 if available on the current DWrite version.
-    RefPtr<IDWriteFontFace> fontFace;
-    if (NS_FAILED(CreateFontFace(getter_AddRefs(fontFace)))) {
+  {
+    AutoReadLock lock(mLock);
+    if (mFontFace) {
+      if (mFontFace5) {
+        mHasVariations = mFontFace5->HasVariations();
+      }
       return mHasVariations;
     }
   }
-  if (mFontFace5) {
-    mHasVariations = mFontFace5->HasVariations();
+
+  // CreateFontFace will initialize the mFontFace field, and also
+  // mFontFace5 if available on the current DWrite version.
+  RefPtr<IDWriteFontFace> fontFace;
+  if (NS_SUCCEEDED(CreateFontFace(getter_AddRefs(fontFace)))) {
+    AutoReadLock lock(mLock);
+    if (mFontFace5) {
+      mHasVariations = mFontFace5->HasVariations();
+    }
   }
+
   return mHasVariations;
 }
 
@@ -643,9 +657,12 @@ void gfxDWriteFontEntry::GetVariationAxesInternal(
   // HasVariations() will have ensured the mFontFace5 interface is available;
   // so we can get an IDWriteFontResource and ask it for the axis info.
   RefPtr<IDWriteFontResource> resource;
-  HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
-  if (FAILED(hr) || !resource) {
-    return;
+  {
+    AutoReadLock lock(mLock);
+    HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
+    if (FAILED(hr) || !resource) {
+      return;
+    }
   }
 
   uint32_t count = resource->GetFontAxisCount();
@@ -690,7 +707,11 @@ void gfxDWriteFontEntry::GetVariationInstancesInternal(
 
 #if MOZ_FONTATIONS
 void gfxDWriteFontEntry::InitSkrifaFontFace() {
-  RefPtr<IDWriteFontFace> face = mFontFace;
+  RefPtr<IDWriteFontFace> face;
+  {
+    AutoReadLock lock(mLock);
+    face = mFontFace;
+  }
   if (!face) {
     if (!mFont || FAILED(mFont->CreateFontFace(getter_AddRefs(face)))) {
       return;
@@ -846,6 +867,11 @@ nsresult gfxDWriteFontEntry::CreateFontFace(
                                      (aTag >> 8) & 0xff, aTag & 0xff);
   };
 
+  // Must read this *before* taking the write lock.
+  bool hasVariations = HasVariations();
+
+  AutoWriteLock lock(mLock);
+
   MOZ_SEH_TRY {
     // initialize mFontFace if this hasn't been done before
     if (!mFontFace) {
@@ -896,7 +922,7 @@ nsresult gfxDWriteFontEntry::CreateFontFace(
 
     // If the IDWriteFontFace5 interface is available, we can try using
     // IDWriteFontResource to create a new modified face.
-    if (mFontFace5 && (HasVariations() || needSimulations)) {
+    if (mFontFace5 && (hasVariations || needSimulations)) {
       RefPtr<IDWriteFontResource> resource;
       HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
       if (SUCCEEDED(hr) && resource) {
diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h
index 9d50c2a3227..5f36003dadb 100644
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -235,9 +235,9 @@ class gfxDWriteFontEntry final : public gfxFontEntry {
 
   // font face corresponding to the mFont/mFontFile *without* any DWrite
   // style simulations applied
-  RefPtr<IDWriteFontFace> mFontFace;
+  RefPtr<IDWriteFontFace> mFontFace MOZ_GUARDED_BY(mLock);
   // Extended fontface interface if supported, else null
-  RefPtr<IDWriteFontFace5> mFontFace5;
+  RefPtr<IDWriteFontFace5> mFontFace5 MOZ_GUARDED_BY(mLock);
 
   DWRITE_FONT_FACE_TYPE mFaceType;
 
diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h
index 05f74f34b92..74c9556c87b 100644
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -522,16 +522,16 @@ class gfxFontEntry {
    * Font-variation query methods. These will call through to ...Internal()
    * implementation methods if we don't have a Skrifa font to query.
    */
-  bool HasVariations();
+  bool HasVariations() MOZ_EXCLUDES(mLock);
   void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes);
   void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances);
 
-  bool HasBoldVariableWeight();
-  bool HasItalicVariation();
-  bool HasSlantVariation();
-  bool HasOpticalSize();
+  bool HasBoldVariableWeight() MOZ_EXCLUDES(mLock);
+  bool HasItalicVariation() MOZ_EXCLUDES(mLock);
+  bool HasSlantVariation() MOZ_EXCLUDES(mLock);
+  bool HasOpticalSize() MOZ_EXCLUDES(mLock);
 
-  void CheckForVariationAxes();
+  void CheckForVariationAxes() MOZ_EXCLUDES(mLock);
 
   // Set up the entry's weight/width/style ranges according to axes found
   // by GetVariationAxes (for installed fonts; do NOT call this for user
@@ -797,7 +797,7 @@ class gfxFontEntry {
   // Caller is responsible to call hb_blob_destroy() on the returned blob
   // (if non-nullptr) when no longer required. For transient access to a
   // table, use of AutoTable (below) is generally preferred.
-  virtual hb_blob_t* GetFontTableInternal(uint32_t aTag);
+  virtual hb_blob_t* GetFontTableInternal(uint32_t aTag) MOZ_EXCLUDES(mLock);
 
   // Check for presence of a given table.
   virtual bool HasFontTableInternal(uint32_t aTableTag);
Loading diff…