Multiple unchecked Top DICT offsets in cairo CFF subsetter
Categories
(Core :: Graphics: Text, defect)
Tracking
()
People
(Reporter: zzjas98, Assigned: jfkthame)
References
Details
(Keywords: csectype-bounds, reporter-external, sec-moderate, Whiteboard: [adv-main152+][adv-esr140.12+])
Attachments
(4 files, 3 external files)
Steps to reproduce:
With an ASan build of Firefox:
cp cairo-poc-fdselect-offset.otf cairo-poc-private.otf ~/.fontsandfc-cache -f. This installs the malicious font.- To uninstall,
rm ~/.fonts/cairo-poc-*.otf && fc-cache -f
- To uninstall,
- Load
file:///path/to/private.htmlorfile:///path/to/fdselect-offset.html - Print -> (Save as PDF) Save -> Save
Actual results:
For private.html:
==915016==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7376a7489a73 at pc 0x71468d252761 bp 0x7ffe1dffb5d0 sp 0x7ffe1dffb5c8
READ of size 1 at 0x7376a7489a73 thread T0
#0 0x71468d252760 in operand_length .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:362:9
#1 0x71468d252760 in cff_dict_read .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:665:16
#2 0x71468d2583af in cairo_cff_font_read_private_dict .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:925:14
#3 0x71468d257503 in cairo_cff_font_read_top_dict .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:1243:11
#4 0x71468d24e95a in cairo_cff_font_read_font .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:1359:18
#5 0x71468d24e95a in cairo_cff_font_generate .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:2603:14
#6 0x71468d24e95a in _cairo_cff_subset_init .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:2995:14
#7 0x71468d2b42ef in _cairo_pdf_surface_emit_cff_font_subset .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:6249:14
#8 0x71468d2b42ef in _cairo_pdf_surface_emit_unscaled_font_subset .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:7141:14
#9 0x71468d3c580b in _cairo_sub_font_collect .../firefox/obj-ff-asan/gfx/cairo/cairo/src/./../../../../../gfx/cairo/cairo/src/cairo-scaled-font-subsets.c:733:30
#10 0x71468d3c580b in _cairo_scaled_font_subsets_foreach_internal .../firefox/obj-ff-asan/gfx/cairo/cairo/src/./../../../../../gfx/cairo/cairo/src/cairo-scaled-font-subsets.c:1068:2
For fdselect-offset.html:
==1180712==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x718917162494 at pc 0x70d8fd057b95 bp 0x7ffdfd6b95f0 sp 0x7ffdfd6b95e8
READ of size 1 at 0x718917162494 thread T0
#0 0x70d8fd057b94 in cairo_cff_font_read_fdselect .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:984:12
#1 0x70d8fd057b94 in cairo_cff_font_read_top_dict .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:1230:18
#2 0x70d8fd04e95a in cairo_cff_font_read_font .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:1359:18
#3 0x70d8fd04e95a in cairo_cff_font_generate .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:2603:14
#4 0x70d8fd04e95a in _cairo_cff_subset_init .../firefox/gfx/cairo/cairo/src/cairo-cff-subset.c:2995:14
#5 0x70d8fd0b42ef in _cairo_pdf_surface_emit_cff_font_subset .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:6249:14
#6 0x70d8fd0b42ef in _cairo_pdf_surface_emit_unscaled_font_subset .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:7141:14
#7 0x70d8fd1c580b in _cairo_sub_font_collect .../firefox/obj-ff-asan/gfx/cairo/cairo/src/./../../../../../gfx/cairo/cairo/src/cairo-scaled-font-subsets.c:733:30
#8 0x70d8fd1c580b in _cairo_scaled_font_subsets_foreach_internal .../firefox/obj-ff-asan/gfx/cairo/cairo/src/./../../../../../gfx/cairo/cairo/src/cairo-scaled-font-subsets.c:1068:2
#9 0x70d8fd09b760 in _cairo_pdf_surface_emit_font_subsets .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:7185:14
#10 0x70d8fd09b760 in _cairo_pdf_surface_finish .../firefox/gfx/cairo/cairo/src/cairo-pdf-surface.c:2711:14
Expected results:
No OOB reads.
Analysis
decode_integer returns a signed int (operators 28/29 decode as int16_t / int32_t):
cairo_cff_font_read_top_dict (and the per-fontdict loop in cairo_cff_font_read_cid_fontdict) takes that signed value and adds it to font->data at four sites without checking the result against [font->data, font->data_end].
The commit ee57158fb5e4 added the two-sided p < font->data || p > font->data_end check at only one sibling site — the LOCAL_SUB offset inside the private dict: https://searchfox.org/firefox-main/rev/8352bcb6d75d53f3e2190221b71190e47afa0bfc/gfx/cairo/cairo/src/cairo-cff-subset.c#929-935
The unchecked sites:
CHARSTRINGS_OP: https://searchfox.org/firefox-main/rev/8352bcb6d75d53f3e2190221b71190e47afa0bfc/gfx/cairo/cairo/src/cairo-cff-subset.c#1205-1210
PRIVATE_OP (top dict): https://searchfox.org/firefox-main/rev/8352bcb6d75d53f3e2190221b71190e47afa0bfc/gfx/cairo/cairo/src/cairo-cff-subset.c#1240-1253
PRIVATE_OP (per-fontdict): https://searchfox.org/firefox-main/rev/8352bcb6d75d53f3e2190221b71190e47afa0bfc/gfx/cairo/cairo/src/cairo-cff-subset.c#1082-1102
FDSELECT_OP / FDARRAY_OP: https://searchfox.org/firefox-main/rev/8352bcb6d75d53f3e2190221b71190e47afa0bfc/gfx/cairo/cairo/src/cairo-cff-subset.c#1227-1238
I couldn't manage to trigger ASan in Firefox end-to-end for CHARSTRINGS_OP and CHARSET_OP but they might be worth fixing.
- CHARSTRINGS_OP: A statically-malformed CHARSTRINGS offset is rejected by FreeType's CFF parser before cairo's subsetter ever runs, so Firefox never embeds the font into a PDF.
- CHARSET_OP: Firefox's font-fallback policy substitutes a different family for the specific OTF used, so cairo never sees the malicious bytes.
Please let me know if I can provide any more information, thanks!
| Reporter | ||
Comment 1•6 months ago
|
||
| Reporter | ||
Comment 2•6 months ago
|
||
| Reporter | ||
Comment 3•6 months ago
|
||
Updated•6 months ago
|
Updated•6 months ago
|
| Assignee | ||
Comment 4•6 months ago
|
||
Both of the example fonts here are rejected by OTS if we attempt to load them as webfonts. Therefore, they could only reach the cairo subsetting code if installed locally by the user.
That's not to say we shouldn't harden the subsetting code, too, but given the requirement for both local font installation and executing a print operation, neither of which can be done directly by a website without user confirmation, the risk here seems relatively low.
Updated•5 months ago
|
| Assignee | ||
Comment 5•5 months ago
|
||
Updated•5 months ago
|
Comment 6•5 months ago
|
||
There is an r+ patch which didn't land and no activity in this bug for 1 week.
:jfkthame, could you have a look please?
If you still have some work to do, you can add an action "Plan Changes" in Phabricator.
For more information, please visit BugBot documentation.
| Assignee | ||
Comment 7•5 months ago
|
||
Hmm, not sure what the sec-rating should be for this; to me it seems relatively low (moderate?), per comment 4. But I'll request sec-approval so the appropriate people can make the call.
| Assignee | ||
Comment 8•5 months ago
|
||
(I'm assuming all branches are similarly affected, though have not attempted to test them all.)
| Assignee | ||
Comment 9•5 months ago
|
||
Comment on attachment 9587614 [details]
(secure)
Security Approval Request
- How easily could an exploit be constructed based on the patch?: Not easily -- the patch hints at possible overflow (out-of-bounds read) locations, but it's unclear how that would be exploited.
(In theory I think this might be part of a sandbox escape chain during printing operations, but would require significant additional steps.)
- Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: No
- Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?: all
- If not all supported branches, which bug introduced the flaw?: None
- Do you have backports for the affected branches?: No
- If not, how different, hard to create, and risky will they be?: should be simple transplant/backport
- How likely is this patch to cause regressions; how much testing does it need?: minimal risk, just adding bounds checks
- Is the patch ready to land after security approval is given?: Yes
- Is Android affected?: Yes
Updated•5 months ago
|
Updated•5 months ago
|
Comment 10•5 months ago
|
||
Comment 11•5 months ago
|
||
https://hg-edge.mozilla.org/mozilla-central/rev/358ce92cf0ba
Please add Beta and ESR140 uplift requests to this when you get a chance and give it a severity rating.
| Assignee | ||
Comment 12•5 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D301269
Updated•5 months ago
|
Comment 13•5 months ago
|
||
firefox-beta Uplift Approval Request
- User impact if declined/Reason for urgency: potential (parent-process) out-of-bounds access during printing operations
- Code covered by automated testing?: no
- Fix verified in Nightly?: no
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: simple addition of bounds checks
- String changes made/needed?: none
- Is Android affected?: yes
Comment 14•5 months ago
|
||
firefox-esr140 Uplift Approval Request
- User impact if declined/Reason for urgency: potential (parent-process) out-of-bounds access during printing operations
- Code covered by automated testing?: no
- Fix verified in Nightly?: no
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing:
- Risk associated with taking this patch: low
- Explanation of risk level: simple addition of bounds checks
- String changes made/needed?: none
- Is Android affected?: yes
| Assignee | ||
Comment 15•5 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D301269
| Assignee | ||
Comment 16•5 months ago
|
||
Calling this sec-moderate, given it's unclear how exploitable the OOB access would be, and I don't think it's reachable without user interaction (triggering a print job, local font installation).
Updated•5 months ago
|
Updated•5 months ago
|
Comment 17•5 months ago
|
||
| uplift | ||
Updated•5 months ago
|
Updated•5 months ago
|
Comment 18•5 months ago
|
||
| uplift | ||
Updated•5 months ago
|
Updated•5 months ago
|
Updated•5 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Updated•1 month ago
|
Description
•