CVE: CVE-2021-1790
Tested Versions:
- macOS Catalina 10.15.4 (19E287)
Product URL(s):
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.
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.
Proof of Concept
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)
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)
Suggested 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