Advisories

macOS/iOS CoreText libhvf Out-Of-Bounds Read

CVE ID

CVE-2021-1790

Tested Versions

  • macOS Catalina 10.15.4 (19E287)

Product URL(s)

  • https://apple.com

Description of the vulnerability

This vulnerability exists in libhvf.dylib, a part of CoreText library is widely used in macOS, iOS, iPadOS to parse font. An attacker can craft an evil PDF contains the malicious font that could lead to remote code execution.

Technical Details

libhvf.dylib is used to parse HierVariation table in Truetype Font. libhvf.dylib is a feature of libFontParser.dylib. To enable this feature user must create a plist file in /User/<user>/Library/Preferences/com.apple.FontParser.plist with following content.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>HVFEnabled</key>
  <true/>
</dict>
</plist>

This vulnerability only triggers in Font Book.app when com.apple.FontParser.plist was set.

The vulnerability occurs in hvf::LoaderCBF::loadPartAtIndex following the decompiler code below.

  if (idx < count_part) {
    start_offset = *(uint *)(this[5] + (ulong)idx * 4);
    end_offset = *(uint *)(this[5] + 4 + (ulong)idx * 4);
    start_offset = start_offset >> 0x18 | (start_offset & 0xff0000) >> 8 | (start_offset & 0xff00) << 8 |
                 start_offset << 0x18;
    end_offset = end_offset >> 0x18 | (end_offset & 0xff0000) >> 8 | (end_offset & 0xff00) << 8 | end_offset << 0x18;
    if (end_offset <= start_offset) {
      start_offset = end_offset;
    }
    start_ptr = (char *)(this[1] + (ulong)start_offset);
    end_ptr = start_ptr + (end_offset - start_offset);
  }

An attacker can control the start_offset and end_offset. Because there are not bound check of these variables, this could lead to an Out-Of-Bounds read.

PoC

  1. Trigger the crash in harness binary.
clang++ harness.cpp -o harness -framework ApplicationServices -framework CoreFoundation -framework CoreText -framework CoreGraphics --std=c++14
lldb ./harness
r ./poc.ttf

The program will crash because the offset will point outside of start_ptr buffer.

Process 35904 resuming
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000001  RBX: 0x00000001022C9FC0  RBP: 0x00007FFEEFBFC320  RSP: 0x00007FFEEFBFA980  o d I t s z a P c
  RDI: 0x00000001022C9FC0  RSI: 0x0000000050500000  RDX: 0x0000000152774C04  RCX: 0x000000007D3D30A6
  RIP: 0x00007FFF4E1649CB  R8 : 0x0000000000000000  R9 : 0x0000000000000000  R10: 0x0000000007000001
  R11: 0x0000000000000202  R12: 0x00007FFEEFBFDCB0  R13: 0x0000000104152FE0  R14: 0x00007FFEEFBFDCF0
  R15: 0x0000000000000001
  CS : 002B  GS : 0000  FS : 0000
-----------------------------------------------------------------------------------------------------------------------[code]
hvf::LoaderCBF::loadPartAtIndex(hvf::PartCache&, unsigned int) @ /System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib:
->  0x7fff4e1649cb (0x19cb): 80 3a 00                       cmp      byte ptr [rdx], 0x0
    0x7fff4e1649ce (0x19ce): 48 b8 ff ff ff ff ff ff ff 7f  movabs   rax, 0x7fffffffffffffff
    0x7fff4e1649d8 (0x19d8): 48 89 85 a0 e6 ff ff           mov      qword ptr [rbp - 0x1960], rax
    0x7fff4e1649df (0x19df): 0f 88 0d 02 00 00              js       0x7fff4e164bf2 ; <+690>
    0x7fff4e1649e5 (0x19e5): 4c 89 a5 c0 e6 ff ff           mov      qword ptr [rbp - 0x1940], r12
    0x7fff4e1649ec (0x19ec): 48 8d 85 70 e6 ff ff           lea      rax, [rbp - 0x1990]
    0x7fff4e1649f3 (0x19f3): 48 89 85 f0 e6 ff ff           mov      qword ptr [rbp - 0x1910], rax
    0x7fff4e1649fa (0x19fa): 48 8d bd 00 e7 ff ff           lea      rdi, [rbp - 0x1900]
-----------------------------------------------------------------------------------------------------------------------------

Process 35904 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x152774c04)
    frame #0: 0x00007fff4e1649cb libhvf.dylib`hvf::LoaderCBF::loadPartAtIndex(hvf::PartCache&, unsigned int) + 139
Target 0: (dfont_harness) stopped.
(lldbinit)
  1. Trigger the crash in FontBook.app
  • Set environment to DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib
  • Open FontBook Application and attached in lldb.
  • On the left hand side select menu “User”.
  • Click add new font, select poc.ttf.
(lldbinit) 
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000001  RBX: 0x00000003AFC56FC0  RBP: 0x00007FFEEFBF6AC0  RSP: 0x00007FFEEFBF5120  o d I t s z a P c 
  RDI: 0x00000003AFC56FC0  RSI: 0x0000000050500000  RDX: 0x000000040014EC04  RCX: 0x000000007D3D30A6
  RIP: 0x00007FFF530539CB  R8 : 0x0000000000000000  R9 : 0x0000000000000000  R10: 0x0000000007000001
  R11: 0x0000000000000206  R12: 0x00007FFEEFBF8450  R13: 0x00000003B3F11FE0  R14: 0x00007FFEEFBF8490
  R15: 0x0000000000000001
  CS : 002B  GS : 0000  FS : 0000                                              
-----------------------------------------------------------------------------------------------------------------------[code]
hvf::LoaderCBF::loadPartAtIndex(hvf::PartCache&, unsigned int) @ /System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib:
->  0x7fff530539cb (0x19cb): 80 3a 00                       cmp      byte ptr [rdx], 0x0
    0x7fff530539ce (0x19ce): 48 b8 ff ff ff ff ff ff ff 7f  movabs   rax, 0x7fffffffffffffff
    0x7fff530539d8 (0x19d8): 48 89 85 a0 e6 ff ff           mov      qword ptr [rbp - 0x1960], rax
    0x7fff530539df (0x19df): 0f 88 0d 02 00 00              js       0x7fff53053bf2 ; <+690>
    0x7fff530539e5 (0x19e5): 4c 89 a5 c0 e6 ff ff           mov      qword ptr [rbp - 0x1940], r12
    0x7fff530539ec (0x19ec): 48 8d 85 70 e6 ff ff           lea      rax, [rbp - 0x1990]
    0x7fff530539f3 (0x19f3): 48 89 85 f0 e6 ff ff           mov      qword ptr [rbp - 0x1910], rax
    0x7fff530539fa (0x19fa): 48 8d bd 00 e7 ff ff           lea      rdi, [rbp - 0x1900]
-----------------------------------------------------------------------------------------------------------------------------

Process 22443 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x40014ec04)
    frame #0: 0x00007fff530539cb libhvf.dylib`hvf::LoaderCBF::loadPartAtIndex(hvf::PartCache&, unsigned int) + 139
Target 0: (Font Book) stopped.
(lldbinit) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x40014ec04)
  * frame #0: 0x00007fff530539cb libhvf.dylib`hvf::LoaderCBF::loadPartAtIndex(hvf::PartCache&, unsigned int) + 139
    frame #1: 0x00007fff530597a0 libhvf.dylib`(anonymous namespace)::RendererImpl::renderPartAtIndex(unsigned int, hvf::PartTransform const&, HVFPartRenderState (HVFPartRenderInstruction, HVFPartRenderParams const*) block_pointer) + 496
    frame #2: 0x00007fff52ef2971 libFontParser.dylib`THierVariationsFontHandler::GetOutlinePath(unsigned short, TGlyphOutlineBatch const&, bool*) const + 129
    frame #3: 0x00007fff52e89716 libFontParser.dylib`FPFontCopyGlyphPath + 595
    frame #4: 0x00007fff36be3448 CoreGraphics`CGFontCreateGlyphPath + 42
    frame #5: 0x00007fff3859b122 CoreText`TBaseFont::GetSpaceGlyph(TcmapTable const*) const + 236
    frame #6: 0x00007fff385a4649 CoreText`AddSynthesizableCharacters(__CFCharacterSet const*, TBaseFont const*, TInlineVector<unsigned short, 30ul>&) + 256
    frame #7: 0x00007fff385a4484 CoreText`CharacterSetByAddingSynthesizedCharacters(__CFCharacterSet const*, TBaseFont const*) + 101
    frame #8: 0x00007fff385a4304 CoreText`TBaseFont::CopyLanguageProperties() const + 214
    frame #9: 0x00007fff385c6df8 CoreText`TBaseFont::CopyDesignLanguages() const + 144
    frame #10: 0x00007fff38576467 CoreText`TBaseFont::CopyAttribute(unsigned long) const + 357
    frame #11: 0x00007fff385875ef CoreText`TDescriptor::CopyAttribute(unsigned long, __CFString const*) const + 99
    frame #12: 0x00007fff385872ff CoreText`TFont::CopyAttribute(unsigned long, __CFString const*) const + 405
    frame #13: 0x00007fff385a3c48 CoreText`TFont::CopyAttribute(__CFString const*) const + 44
    frame #14: 0x00007fff385d3127 CoreText`CTFontCopyAttribute + 43
    frame #15: 0x000000010004293d Font Book`___lldb_unnamed_symbol1007$$Font Book + 97
    frame #16: 0x000000010008d2fc Font Book`___lldb_unnamed_symbol2993$$Font Book + 139
    frame #17: 0x000000010008c79e Font Book`___lldb_unnamed_symbol2983$$Font Book + 356
    frame #18: 0x000000010008771c Font Book`___lldb_unnamed_symbol2872$$Font Book + 186
    frame #19: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #20: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #21: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #22: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #23: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #24: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #25: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #26: 0x000000010004fb0a Font Book`___lldb_unnamed_symbol1357$$Font Book + 302
    frame #27: 0x000000010000e6b9 Font Book`___lldb_unnamed_symbol264$$Font Book + 353
    frame #28: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #29: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #30: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #31: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #32: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #33: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #34: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #35: 0x000000010001449c Font Book`___lldb_unnamed_symbol356$$Font Book + 988
    frame #36: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #37: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #38: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #39: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #40: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #41: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #42: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #43: 0x00007fff33b553ab AppKit`-[NSTableView _sendSelectionChangedNotificationForRows:columns:] + 221
    frame #44: 0x00007fff33b54a61 AppKit`-[NSTableView _doSelectIndexes:byExtendingSelection:indexType:funnelThroughSingleIndexVersion:] + 3140
    frame #45: 0x00007fff33b53e09 AppKit`-[NSTableView selectRowIndexes:byExtendingSelection:] + 127
    frame #46: 0x000000010000e4f7 Font Book`___lldb_unnamed_symbol263$$Font Book + 857
    frame #47: 0x0000000100012efd Font Book`___lldb_unnamed_symbol336$$Font Book + 1271
    frame #48: 0x000000010000d50c Font Book`___lldb_unnamed_symbol249$$Font Book + 1540
    frame #49: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #50: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #51: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #52: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #53: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #54: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #55: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #56: 0x000000010004c8db Font Book`___lldb_unnamed_symbol1254$$Font Book + 501
    frame #57: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #58: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #59: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #60: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #61: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #62: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #63: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #64: 0x00007fff33b553ab AppKit`-[NSTableView _sendSelectionChangedNotificationForRows:columns:] + 221
    frame #65: 0x00007fff33b54a61 AppKit`-[NSTableView _doSelectIndexes:byExtendingSelection:indexType:funnelThroughSingleIndexVersion:] + 3140
    frame #66: 0x00007fff33b53e09 AppKit`-[NSTableView selectRowIndexes:byExtendingSelection:] + 127
    frame #67: 0x000000010000503f Font Book`___lldb_unnamed_symbol47$$Font Book + 1308
    frame #68: 0x000000010000c705 Font Book`___lldb_unnamed_symbol226$$Font Book + 1335
    frame #69: 0x00007fff3678d80f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    frame #70: 0x00007fff3678d7a3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
    frame #71: 0x00007fff3678d718 CoreFoundation`_CFXRegistrationPost1 + 372
    frame #72: 0x00007fff3678d384 CoreFoundation`___CFXNotificationPost_block_invoke + 80
    frame #73: 0x00007fff3675d4fd CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1554
    frame #74: 0x00007fff3675c9a9 CoreFoundation`_CFXNotificationPost + 1351
    frame #75: 0x00007fff38dda786 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
    frame #76: 0x00007fff38e6c0dd Foundation`__NSThreadPerformPerform + 204
    frame #77: 0x00007fff36797d52 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #78: 0x00007fff36797cf1 CoreFoundation`__CFRunLoopDoSource0 + 103
    frame #79: 0x00007fff36797b0b CoreFoundation`__CFRunLoopDoSources0 + 209
    frame #80: 0x00007fff3679683a CoreFoundation`__CFRunLoopRun + 927
    frame #81: 0x00007fff36795e3e CoreFoundation`CFRunLoopRunSpecific + 462
    frame #82: 0x00007fff353c2abd HIToolbox`RunCurrentEventLoopInMode + 292
    frame #83: 0x00007fff353c27d5 HIToolbox`ReceiveNextEventCommon + 584
    frame #84: 0x00007fff353c2579 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 64
    frame #85: 0x00007fff33a08039 AppKit`_DPSNextEvent + 883
    frame #86: 0x00007fff33a06880 AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
    frame #87: 0x00007fff339f858e AppKit`-[NSApplication run] + 658
    frame #88: 0x00007fff339ca396 AppKit`NSApplicationMain + 777
    frame #89: 0x0000000100001e6b Font Book`___lldb_unnamed_symbol1$$Font Book + 11
    frame #90: 0x00007fff70802cc9 libdyld.dylib`start + 1
    frame #91: 0x00007fff70802cc9 libdyld.dylib`start + 1
(lldbinit) 

Mitigations

  • Validation application which used API CTFontManagerCreateFontDescriptorsFromURL.

  • Make sure to disable HVFEnable in application.

  • Do not install any un-trusted font in FontBook and to disable HVF, follow these steps:

    rm ~/Library/Preferences/com.apple.FontParser.plist
    

Timeline

  • 2020-09-17 Reported to Vendor, Vendor acknowledged on same day
  • 2021-02-01 Vendor patched the vulnerability

Credit

Discovered by Peter Nguyễn Vũ Hoàng