High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionIncorrect boundary conditions in the Graphics: Text component
ComponentGraphics
Bug ClassLogic Error
Tracker2077162
Fix commitf3afc6070391 (firefox) +64/-41
CISA KEVNot listed
Creditedtsui
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
OTS_API
gfx/ots/include/opentype-sanitiser.h
modified
OTSContext
gfx/ots/include/opentype-sanitiser.h
modified
OTSContext
gfx/ots/include/opentype-sanitiser.h
modified
if
gfx/ots/src/glat.cc
modified
if
gfx/ots/src/glyf.cc
modified
if
gfx/ots/src/ots.cc
modified
if
gfx/ots/src/silf.cc
modified

Files Changed

  • gfx/ots/include/opentype-sanitiser.h
  • gfx/ots/moz.yaml
  • gfx/ots/src/glat.cc
  • gfx/ots/src/glyf.cc
  • gfx/ots/src/ots.cc
  • gfx/ots/src/silf.cc
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
index 27d4d5e815b..10c2042249c 100644
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -5,26 +5,6 @@
 #ifndef OPENTYPE_SANITISER_H_
 #define OPENTYPE_SANITISER_H_
 
-#if defined(_WIN32) || defined(__CYGWIN__)
-  #define OTS_DLL_IMPORT __declspec(dllimport)
-  #define OTS_DLL_EXPORT __declspec(dllexport)
-#else
-  #if __GNUC__ >= 4
-    #define OTS_DLL_IMPORT __attribute__((visibility ("default")))
-    #define OTS_DLL_EXPORT __attribute__((visibility ("default")))
-  #endif
-#endif
-
-#ifdef OTS_DLL
-  #ifdef OTS_DLL_EXPORTS
-    #define OTS_API OTS_DLL_EXPORT
-  #else
-    #define OTS_API OTS_DLL_IMPORT
-  #endif
-#else
-  #define OTS_API
-#endif
-
 #if defined(_WIN32)
 #include <stdlib.h>
 typedef signed char int8_t;
@@ -197,7 +177,7 @@ enum TableAction {
                               // sanitzation even if this table fails/is dropped
 };
 
-class OTS_API OTSContext {
+class OTSContext {
   public:
     OTSContext() {}
     virtual ~OTSContext() {}
diff --git a/gfx/ots/moz.yaml b/gfx/ots/moz.yaml
index 4abf77379c2..ca77d575d47 100644
--- a/gfx/ots/moz.yaml
+++ b/gfx/ots/moz.yaml
@@ -10,8 +10,8 @@ origin:
 
   url: https://github.com/khaledhosny/ots
 
-  release: 62634335137d86473c84b20a8de9b9d97645bbd6 (2026-09-11T14:03:29Z).
-  revision: 62634335137d86473c84b20a8de9b9d97645bbd6
+  release: 6540e90426c17de7ddcae650409a9af5a450ea7a (2026-10-13T11:40:17Z).
+  revision: 6540e90426c17de7ddcae650409a9af5a450ea7a
 
   license: BSD-3-Clause
   license-file: LICENSE
diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
index 296e208628c..6c9079c47c2 100644
--- a/gfx/ots/src/glat.cc
+++ b/gfx/ots/src/glat.cc
@@ -5,7 +5,7 @@
 #include "glat.h"
 
 #include "gloc.h"
-#include "mozilla/Compression.h"
+#include "lz4.h"
 #include <list>
 #include <memory>
 
@@ -217,15 +217,14 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
                             decompressed_size / (1024.0 * 1024.0));
       }
       std::unique_ptr<uint8_t> decompressed(new uint8_t[decompressed_size]());
-      size_t outputSize = 0;
-      bool ret = mozilla::Compression::LZ4::decompressPartial(
+      int ret = LZ4_decompress_safe_partial(
           reinterpret_cast<const char*>(data + table.offset()),
-          table.remaining(),  // input buffer size (input size + padding)
           reinterpret_cast<char*>(decompressed.get()),
+          table.remaining(),  // input buffer size (input size + padding)
           decompressed_size,  // target output size
-          &outputSize);  // output buffer size
-      if (!ret || outputSize != decompressed_size) {
-        return DropGraphite("Decompression failed");
+          decompressed_size);  // output buffer size
+      if (ret < 0 || unsigned(ret) != decompressed_size) {
+        return DropGraphite("Decompression failed with error code %d", ret);
       }
       return this->Parse(decompressed.get(), decompressed_size, true);
     }
diff --git a/gfx/ots/src/glyf.cc b/gfx/ots/src/glyf.cc
index 30e836062be..2ef046edd72 100644
--- a/gfx/ots/src/glyf.cc
+++ b/gfx/ots/src/glyf.cc
@@ -277,7 +277,17 @@ bool OpenTypeGLYF::ParseCompositeGlyph(
   std::vector<edit_rec> edits;
   unsigned prev_start = 0;
   bool we_have_instructions = false;
+  unsigned num_components = 0;
   do {
+    if (++num_components > 0x7fff) {
+      Warning("Too many components in composite: discarding glyph %u", glyph_id);
+      // Reset the buffer position such that all the glyph data will be dropped,
+      // making it an empty (non-composite) glyph.
+      glyph.set_offset(0);
+      component_point_count->gid_stack.clear();
+      return true;
+    }
+
     unsigned start = glyph.offset();
 
     if (!glyph.ReadU16(&flags) || !glyph.ReadU16(&gid)) {
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc
index df7366adef3..92fb89c7e56 100644
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -14,7 +14,7 @@
 #include <map>
 #include <vector>
 
-#include "../RLBoxWOFF2Host.h"
+#include <woff2/decode.h>
 
 // The OpenType Font File
 // http://www.microsoft.com/typography/otspec/otff.htm
@@ -525,9 +525,44 @@ bool ProcessWOFF(ots::FontFile *header,
   return ProcessGeneric(header, font, woff_tag, output, data, length, tables, file);
 }
 
-bool ProcessWOFF2(ots::FontFile* header, ots::OTSStream* output,
-                  const uint8_t* data, size_t length, uint32_t index) {
-  return RLBoxProcessWOFF2(header, output, data, length, index, ProcessTTC, ProcessTTF);
+bool ProcessWOFF2(ots::FontFile *header,
+                  ots::OTSStream *output,
+                  const uint8_t *data,
+                  size_t length,
+                  uint32_t index) {
+  size_t decompressed_size = woff2::ComputeWOFF2FinalSize(data, length);
+
+  if (decompressed_size < length) {
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is less than compressed size");
+  }
+
+  if (decompressed_size == 0) {
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
+  }
+  // decompressed font must be <= OTS_MAX_DECOMPRESSED_FILE_SIZE
+  if (decompressed_size > OTS_MAX_DECOMPRESSED_FILE_SIZE) {
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds %gMB",
+                               OTS_MAX_DECOMPRESSED_FILE_SIZE / (1024.0 * 1024.0));
+  }
+
+  if (decompressed_size > output->size()) {
+    return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds output size (%gMB)", output->size() / (1024.0 * 1024.0));
+  }
+
+  std::string buf(decompressed_size, 0);
+  woff2::WOFF2StringOut out(&buf);
+  out.SetMaxSize(decompressed_size);
+  if (!woff2::ConvertWOFF2ToTTF(data, length, &out)) {
+    return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
+  }
+  const uint8_t *decompressed = reinterpret_cast<const uint8_t*>(buf.data());
+
+  if (data[4] == 't' && data[5] == 't' && data[6] == 'c' && data[7] == 'f') {
+    return ProcessTTC(header, output, decompressed, out.Size(), index);
+  } else {
+    ots::Font font(header);
+    return ProcessTTF(header, &font, output, decompressed, out.Size());
+  }
 }
 
 ots::TableAction GetTableAction(const ots::FontFile *header, uint32_t tag) {
diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
index 5ac80b1864b..ea589981037 100644
--- a/gfx/ots/src/silf.cc
+++ b/gfx/ots/src/silf.cc
@@ -5,7 +5,7 @@
 #include "silf.h"
 
 #include "name.h"
-#include "mozilla/Compression.h"
+#include "lz4.h"
 #include <cmath>
 #include <memory>
 
@@ -50,15 +50,14 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
                               decompressed_size / (1024.0 * 1024.0));
         }
         std::unique_ptr<uint8_t[]> decompressed(new uint8_t[decompressed_size]());
-        size_t outputSize = 0;
-        bool ret = mozilla::Compression::LZ4::decompressPartial(
+        int ret = LZ4_decompress_safe_partial(
             reinterpret_cast<const char*>(data + table.offset()),
-            table.remaining(),  // input buffer size (input size + padding)
             reinterpret_cast<char*>(decompressed.get()),
+            table.remaining(),  // input buffer size (input size + padding)
             decompressed_size,  // target output size
-            &outputSize);  // output buffer size
-        if (!ret || outputSize != decompressed_size) {
-          return DropGraphite("Decompression failed");
+            decompressed_size);  // output buffer size
+        if (ret < 0 || unsigned(ret) != decompressed_size) {
+          return DropGraphite("Decompression failed with error code %d", ret);
         }
         return this->Parse(decompressed.get(), decompressed_size, true);
       }
Loading diff…