Chrome · Fonts
CVE-2026-106252
Logic Error in Fonts
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fthird_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc |
modified | |
forthird_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc |
modified | |
ifthird_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc |
modified |
Files Changed
third_party/blink/renderer/platform/fonts/opentype/format_check.rsthird_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
Patch
From f62b9df71852f924534c3a0492ee76edf897bb0f Mon Sep 17 00:00:00 2001 From: Dominik Röttsches <[email protected]> Date: Fri, 18 Sep 2026 05:50:58 -0700 Subject: [PATCH] Send avar >= 2 fonts through Fontations For safety we want to pass unknown avar2 versions through Fontations, too, preventing unsanitized variation data from reaching native OS parsers. Not that avar3 exists, but if we receive such a font, we can just send it to fontations to partially use the font and avoiding sending invalid data to system rasterizers. Fixed: 513446410 Change-Id: Iddc86b392c08f2fe5cd4fce01ea9920acd4ac98d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8430122 Auto-Submit: Dominik Röttsches <[email protected]> Reviewed-by: Rune Lillesveen <[email protected]> Commit-Queue: Dominik Röttsches <[email protected]> Cr-Commit-Position: refs/heads/main@{#1700680} --- diff --git a/third_party/blink/renderer/platform/fonts/opentype/format_check.rs b/third_party/blink/renderer/platform/fonts/opentype/format_check.rs index b99f0ec8..d01b67dd 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/format_check.rs +++ b/third_party/blink/renderer/platform/fonts/opentype/format_check.rs @@ -56,8 +56,16 @@ Some((version.major, version.minor)) } +// https://crbug.com/513446410: For safety we want to pass unknown avar2 +// versions through fontations, too. pub fn is_avar2(format_info: &FontFormatInfo) -> bool { - matches!(&format_info.format_flags, Some(FontFormatFlags { avar_version: Some((2, _)), .. }),) + matches!( + &format_info.format_flags, + Some(FontFormatFlags { + avar_version: Some((major, _)), + .. + }) if *major >= 2, + ) } fn has_tags(format_info: &FontFormatInfo, query: &[Tag]) -> bool { diff --git a/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc b/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc index f8be3debf..6644ace 100644 --- a/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc +++ b/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc @@ -4,8 +4,11 @@ #include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h" +#include "base/containers/heap_array.h" +#include "skia/ext/skia_utils_base.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" +#include "ui/gfx/skia_span_util.h" namespace blink { @@ -62,4 +65,56 @@ ASSERT_FALSE(format_check.IsEbdtEblcMonochromeFont()); } +TEST_F(FontFormatCheckTest, Avar1) { + EnsureFontDataFromPath(test::BlinkWebTestsDir() + + "/external/wpt/css/css-fonts/resources/avar/" + "DesignSpaceWarpTestAvar1[opsz,wdth,wght].ttf"); + FontFormatCheck format_check(font_data_); + ASSERT_FALSE(format_check.IsAvar2Font()); +} + +TEST_F(FontFormatCheckTest, Avar2) { + EnsureFontDataFromPath(test::BlinkWebTestsDir() + + "/external/wpt/css/css-fonts/resources/avar/" + "DesignSpaceWarpTestAvar2[opsz,wdth,wght].ttf"); + FontFormatCheck format_check(font_data_); + ASSERT_TRUE(format_check.IsAvar2Font()); +} + +TEST_F(FontFormatCheckTest, AvarVersion3) { + EnsureFontDataFromPath(test::BlinkWebTestsDir() + + "/external/wpt/css/css-fonts/resources/avar/" + "DesignSpaceWarpTestAvar2[opsz,wdth,wght].ttf"); + auto modified_font_bytes = + base::HeapArray<uint8_t>::CopiedFrom(skia::as_byte_span(*font_data_)); + + // Locate the 'avar' table directory entry and modify its major version to 3. + constexpr uint32_t kAvarTag = SkSetFourByteTag('a', 'v', 'a', 'r'); + size_t avar_offset = 0; + uint16_t num_tables = (modified_font_bytes[4] << 8) | modified_font_bytes[5]; + for (uint16_t i = 0; i < num_tables; ++i) { + size_t record_offset = 12 + i * 16; + uint32_t tag = SkSetFourByteTag(modified_font_bytes[record_offset], + modified_font_bytes[record_offset + 1], + modified_font_bytes[record_offset + 2], + modified_font_bytes[record_offset + 3]); + if (tag == kAvarTag) { + avar_offset = (modified_font_bytes[record_offset + 8] << 24) | + (modified_font_bytes[record_offset + 9] << 16) | + (modified_font_bytes[record_offset + 10] << 8) | + modified_font_bytes[record_offset + 11]; + break; + } + } + ASSERT_NE(avar_offset, 0u); + ASSERT_EQ(modified_font_bytes[avar_offset], 0); + ASSERT_EQ(modified_font_bytes[avar_offset + 1], 2); + modified_font_bytes[avar_offset + 1] = 3; + + sk_sp<SkData> modified_data = + gfx::MakeSkDataFromSpanWithCopy(modified_font_bytes); + FontFormatCheck format_check(modified_data); + ASSERT_TRUE(format_check.IsAvar2Font()); +} + } // namespace blink
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc b/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
index f8be3debf..6644ace 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/font_format_check_test.cc
@@ -4,8 +4,11 @@
#include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"
+#include "base/containers/heap_array.h"
+#include "skia/ext/skia_utils_base.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "ui/gfx/skia_span_util.h"
namespace blink {
@@ -62,4 +65,56 @@
ASSERT_FALSE(format_check.IsEbdtEblcMonochromeFont());
}
+TEST_F(FontFormatCheckTest, Avar1) {
+ EnsureFontDataFromPath(test::BlinkWebTestsDir() +
+ "/external/wpt/css/css-fonts/resources/avar/"
+ "DesignSpaceWarpTestAvar1[opsz,wdth,wght].ttf");
+ FontFormatCheck format_check(font_data_);
+ ASSERT_FALSE(format_check.IsAvar2Font());
+}
+
+TEST_F(FontFormatCheckTest, Avar2) {
+ EnsureFontDataFromPath(test::BlinkWebTestsDir() +
+ "/external/wpt/css/css-fonts/resources/avar/"
+ "DesignSpaceWarpTestAvar2[opsz,wdth,wght].ttf");
+ FontFormatCheck format_check(font_data_);
+ ASSERT_TRUE(format_check.IsAvar2Font());
+}
+
+TEST_F(FontFormatCheckTest, AvarVersion3) {
+ EnsureFontDataFromPath(test::BlinkWebTestsDir() +
+ "/external/wpt/css/css-fonts/resources/avar/"
+ "DesignSpaceWarpTestAvar2[opsz,wdth,wght].ttf");
+ auto modified_font_bytes =
+ base::HeapArray<uint8_t>::CopiedFrom(skia::as_byte_span(*font_data_));
+
+ // Locate the 'avar' table directory entry and modify its major version to 3.
+ constexpr uint32_t kAvarTag = SkSetFourByteTag('a', 'v', 'a', 'r');
+ size_t avar_offset = 0;
+ uint16_t num_tables = (modified_font_bytes[4] << 8) | modified_font_bytes[5];
+ for (uint16_t i = 0; i < num_tables; ++i) {
+ size_t record_offset = 12 + i * 16;
+ uint32_t tag = SkSetFourByteTag(modified_font_bytes[record_offset],
+ modified_font_bytes[record_offset + 1],
+ modified_font_bytes[record_offset + 2],
+ modified_font_bytes[record_offset + 3]);
+ if (tag == kAvarTag) {
+ avar_offset = (modified_font_bytes[record_offset + 8] << 24) |
+ (modified_font_bytes[record_offset + 9] << 16) |
+ (modified_font_bytes[record_offset + 10] << 8) |
+ modified_font_bytes[record_offset + 11];
+ break;
+ }
+ }
+ ASSERT_NE(avar_offset, 0u);
+ ASSERT_EQ(modified_font_bytes[avar_offset], 0);
+ ASSERT_EQ(modified_font_bytes[avar_offset + 1], 2);
+ modified_font_bytes[avar_offset + 1] = 3;
+
+ sk_sp<SkData> modified_data =
+ gfx::MakeSkDataFromSpanWithCopy(modified_font_bytes);
+ FontFormatCheck format_check(modified_data);
+ ASSERT_TRUE(format_check.IsAvar2Font());
+}
+
} // namespace blink
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page