diff --git a/third_party/skia/tests/TypefaceMacOOBTest.cpp b/third_party/skia/tests/TypefaceMacOOBTest.cpp new file mode 100644 index 0000000000..1111111111 --- /dev/null +++ b/third_party/skia/tests/TypefaceMacOOBTest.cpp @@ -0,0 +1,62 @@ +// POC unit test for heap-buffer-overflow in +// populate_glyph_to_unicode_slow (SkTypeface_mac_ct.cpp:386-387). +// +// Build (macOS, ASAN-enabled Skia/Chromium tree) e.g.: +// autoninja -C out/asan dm +// out/asan/dm --match TypefaceMac_GlyphToUnicode_OOB \ +// --resourcePath /path/to/dir/containing/oob.ttf +// +// Place oob.ttf (generated by make_font.py) at +// /fonts/oob.ttf +// +// Expected ASAN result on macOS: +// heap-buffer-overflow WRITE of size 4 +// #0 populate_glyph_to_unicode_slow ... SkTypeface_mac_ct.cpp:387 +// allocated by std::vector in this test (mirrors +// SkPDFFont::GetUnicodeMap, SkPDFFont.cpp:316-317). + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkData.h" +#include "include/core/SkFontMgr.h" +#include "include/core/SkStream.h" +#include "include/core/SkTypeface.h" +#include "include/ports/SkFontMgr_mac_ct.h" +#include "tests/Test.h" +#include "tools/Resources.h" + +#include + +DEF_TEST(TypefaceMac_GlyphToUnicode_OOB, reporter) { + // Load the malicious font: maxp.numGlyphs == 4 but cmap maps + // U+0041..U+0044 to glyph IDs {100, 1000, 30000, 65000}. + sk_sp data = GetResourceAsData("fonts/oob.ttf"); + if (!data) { + ERRORF(reporter, "could not load fonts/oob.ttf — copy it into the " + "Skia resources/fonts/ directory"); + return; + } + + // Same path the PrintCompositor takes on macOS: factoryId 'ctxt' + // -> SkTypeface_Mac::MakeFromStream -> ctfont_from_skdata -> + // CTFontManagerCreateFontDescriptorFromData (no OTS sanitisation). + sk_sp mgr = SkFontMgr_New_CoreText(nullptr); + sk_sp tf = mgr->makeFromData(std::move(data), 0); + if (!tf) { + ERRORF(reporter, "CoreText rejected the font"); + return; + } + + // Mirror SkPDFFont::GetUnicodeMap (SkPDFFont.cpp:316-317): + // allocate exactly countGlyphs() entries and ask the typeface to + // fill them. countGlyphs() == CTFontGetGlyphCount == maxp.numGlyphs + // == 4, so this is a 16-byte heap buffer. + const int n = tf->countGlyphs(); + REPORTER_ASSERT(reporter, n == 4, "unexpected glyph count %d", n); + std::vector buf(n); + // OOB write happens inside here when the slow path runs. + tf->getGlyphToUnicodeMap(buf); +} + +#endif // SK_BUILD_FOR_MAC || SK_BUILD_FOR_IOS diff --git a/third_party/skia/gn/tests.gni b/third_party/skia/gn/tests.gni index aaaaaaaaaa..bbbbbbbbbb 100644 --- a/third_party/skia/gn/tests.gni +++ b/third_party/skia/gn/tests.gni @@ -272,6 +272,7 @@ tests_sources = [ "$_tests/TopoSortTest.cpp", "$_tests/TraceMemoryDumpTest.cpp", "$_tests/TracingTest.cpp", + "$_tests/TypefaceMacOOBTest.cpp", "$_tests/TypefaceTest.cpp", "$_tests/UnicodeTest.cpp", "$_tests/UtilsTest.cpp",