Closed Bug 744480 (CVE-2012-0472) Opened 12 years ago Closed 12 years ago

cairo_dwrite_font_face Memory Corruption Vulnerability [V-49y00m3lf2]

Categories

(Core :: Graphics, defect)

defect
Not set
normal

Tracking

()

VERIFIED FIXED
mozilla14
Tracking Status
firefox11 --- affected
firefox12 + verified
firefox13 + verified
firefox14 + verified
firefox-esr10 12+ verified

People

(Reporter: curtisk, Assigned: jfkthame)

Details

(Keywords: sec-critical, Whiteboard: [sg:critical][qa+])

Attachments

(3 files)

iDefense VCP Submission V-49y00m3lf2
04/11/2012
Mozilla Firefox cairo_dwrite_font_face Memory Corruption Vulnerability (iDefense Exclusive)

Description: 


Analysis: 


Credit: 
wushi of team509
Could we get any details on the specific Firefox version involved, and what signs of corruption should be expected from the PoC here? I've tried loading this in a few different versions (release, aurora, nightly debug build) and left it auto-refreshing for several minutes without seeing any problems.
Here are some notes from the researcher that discovered the vulnerability:


This vulnerability affects the following software :

    * firefox 7&8 (tested on windows )

Overview
fireofx  contains a vulnerability. This vulnerability may allow attackers to remotely 
execute arbitrary code on the affected system. Exploitation may occur as the result of using the 
affected webkit application to visit a website. The privileges gained by a remote attacker depend on the software 
component being attacked. 


I. Description:
	unpack the firefox11-2.rar and got the test-1.html,open the file using firefox 8.0.1 , firefox  will crash. 


And on windows, the crash will like this:
eax=092c2898 ebx=597860d0 ecx=00200077 edx=00317124 esi=066bf800 edi=092c2850
eip=00000000 esp=003170fc ebp=00317164 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
00000000 ??              ???
0:000> kv
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
003170f8 58f0bbe8 092c2898 00317124 00000000 0x0
00317164 58ade452 092c2850 597860d0 59786138 xul!_cairo_dwrite_font_face_scaled_font_create+0x4e (CONV: cdecl) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\cairo\cairo\src\cairo-dwrite-font.cpp @ 464]
00317338 58ade040 09277700 597860d0 59786138 xul!_moz_cairo_scaled_font_create+0x302 (FPO: [Uses EBP] [4,107,4]) (CONV: cdecl) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\cairo\cairo\src\cairo-scaled-font.c @ 1054]
0031737c 590c02ad 003173a4 07a6d8b0 092897f0 xul!DCFromContext::DCFromContext+0x150 (FPO: [Uses EBP] [1,8,4]) (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxwindowsplatform.h @ 79]
00317998 58cc346a 07a6d8b0 092c0240 00317e78 xul!gfxUniscribeShaper::InitTextRun+0x20 (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxuniscribeshaper.cpp @ 474]
003179c4 58ad2312 07a6d8b0 092c0240 00317e78 xul!gfxGDIFont::InitTextRun+0x1f132a (CONV: thiscall)
00317b08 589d2ec7 07a6d8b0 092c0240 00317e78 xul!gfxFont::SplitAndInitTextRun+0x102 (FPO: [Uses EBP] [6,69,0]) (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxfont.cpp @ 1517]
00317ba4 589cf482 07a6d8b0 092c0240 00317e78 xul!gfxFontGroup::InitScriptRun+0xb7 (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxfont.cpp @ 2524]
00317e28 589d730a 07a6d8b0 092c0240 00317e78 xul!gfxFontGroup::InitTextRun+0x162 (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxfont.cpp @ 2485]
00317ef8 58d05012 5960ae80 00000001 00317f30 xul!gfxFontGroup::MakeTextRun+0xea (FPO: [Uses EBP] [4,43,0]) (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxfont.cpp @ 2420]
00317f44 58a16004 00000000 07a6d8b0 00000001 xul!gfxTextRun::SetSpaceGlyph+0x279692 (CONV: thiscall)
00317fd8 58ac16e5 00000000 00000000 00000000 xul!TextRunWordCache::MakeTextRun+0x3d4 (CONV: thiscall) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\thebes\gfxtextrunwordcache.cpp @ 828]
003187f8 0031882c 00318848 00318864 00318880 xul!_moz_cairo_region_create_rectangles+0x85 (FPO: [Uses EBP] [2,515,4]) (CONV: cdecl) [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\gfx\cairo\cairo\src\cairo-region.c @ 252]
00000000 00000000 00000000 00000000 00000000 0x31882c


Check the 8.0 source code, you will get:

static cairo_status_t
_cairo_dwrite_font_face_scaled_font_create (void			*abstract_face,
					    const cairo_matrix_t	*font_matrix,
					    const cairo_matrix_t	*ctm,
					    const cairo_font_options_t  *options,
					    cairo_scaled_font_t **font)
{
    cairo_dwrite_font_face_t *font_face = static_cast<cairo_dwrite_font_face_t*>(abstract_face);

    // Must do malloc and not C++ new, since Cairo frees this.
    cairo_dwrite_scaled_font_t *dwriteFont = (cairo_dwrite_scaled_font_t*)malloc(sizeof(cairo_dwrite_scaled_font_t));
    *font = reinterpret_cast<cairo_scaled_font_t*>(dwriteFont);
    _cairo_scaled_font_init(&dwriteFont->base, &font_face->base, font_matrix, ctm, options, &_cairo_dwrite_scaled_font_backend);

    cairo_font_extents_t extents;

    DWRITE_FONT_METRICS metrics;
    font_face->dwriteface->GetMetrics(&metrics); // this line error.


the var abstract_face seems corrupted, And find it in caller:
	/* Return existing scaled_font if it exists in the hash table. */
	if (scaled_font != NULL) {
	    /* If the original reference count is 0, then this font must have
	     * been found in font_map->holdovers, (which means this caching is
	     * actually working). So now we remove it from the holdovers
	     * array, unless we caught the font in the middle of destruction.
	     */

 ....................

    status = font_face->backend->scaled_font_create (font_face, font_matrix,
						     ctm, options, &scaled_font);

The Hash table corrupt.


OK, this one should be exploitable.
OK, I think this occurs only if hardware acceleration is *disabled* (either due to incompatible hardware/drivers, or by explicitly disabling it in Options). It looks like the cairo-dwrite code path is getting used when it shouldn't be. (Reminds me of bug 544617.) Adding Bas, who originally did the cairo-dwrite stuff, I believe.

I've been able to reproduce a crash with FF11 (release), but with Beta (12), Aurora (13) or later, I'm not seeing a crash, only a failure to render the text - though that still isn't right, so maybe it's just getting (un)lucky, not really fixed.
The problem here occurs when the page tries to use the stroke-based (i.e. not truetype/opentype) font "Roman" at a size larger than 256px. Initially, creation of the cairo scaled_font succeeds, and we successfully shape the text. However, when cairo attempts to actually *draw* with this font, it goes into an error state (and we draw nothing, because gfxFont::Draw detects the error).

Then when the page is refreshed, we try to repeat; but this time we find the existing cached scaled_font, detect that it is in an error state, and so we don't set it in the context for shaping. But this means that cairo provides a fallback font internally, and unfortunately it creates a dwrite one, which doesn't work because we're in the GDI code path. Bug 544617 tried to address this, by ensuring we call SetupCairoFont before shaping, but it didn't account for the fact that this may fail if the cairo font is already in an error state from last time we used it.

The testcase here doesn't crash recent versions (FF12 or later) because the shaped word caching changes from bug 703100 mean that we don't re-shape the text when reloading the page, we just use the font's cache. However, it's easy to construct an example that will crash any build up to and including current Nightly, by varying the text string being rendered.
This example will crash all builds up through current Nightly, when running on Win7 with hardware acceleration *disabled*.
Assignee: nobody → jfkthame
Nominating for tracking-*, given how easily crashable this is. I don't have a good sense of how exploitable this might be; in my testing, it seems to typically crash with a read access violation, but there might be scenarios where something worse happens.
This prevents the crash by bailing out of the text-shaping process if SetupCairoFont detects an error.

The result is that we simply fail to render the text at all (and debug builds log a warning about shaping failure). This is the same behavior as we'd see on a system (WinXP) without dwrite present at all (and hence not vulnerable to the crashing issue here). We might want to handle that situation better (e.g. clamp the font size for such fonts, or fall back to a different font?), but I think that belongs in a separate (non-sg) followup.
Attachment #614752 - Flags: review?(jdaggett)
Attachment #614752 - Flags: review?(jdaggett) → review+
Merged to m-c (thanks, Marco):
https://hg.mozilla.org/mozilla-central/rev/2f77fddb6f7a
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Comment on attachment 614752 [details] [diff] [review]
patch, check for SetupCairoFont failure and return safely

[Approval Request Comment]
Regression caused by (bug #): fix for a crash that has probably existed in some form since FF4 or so

User impact if declined: exposed to potential crash (maybe exploitable if we're unlucky, depending on heap state?) on Vista/Win7 (systems where directwrite is present) when HWAcc is disabled, either manually or due to incompatible graphics config

Testing completed (on m-c, etc.): landed on m-i and m-c; builds containing this patch no longer crash with the testcase here

Risk to taking this patch (and alternatives if risky): minimal risk, just adds a missing error check

String changes made by this patch: none
Attachment #614752 - Flags: approval-mozilla-esr10?
Attachment #614752 - Flags: approval-mozilla-beta?
Attachment #614752 - Flags: approval-mozilla-aurora?
Comment on attachment 614752 [details] [diff] [review]
patch, check for SetupCairoFont failure and return safely

[Triage comment]
Approved for landing - please land on beta and ESR today, earlier the better.
Attachment #614752 - Flags: approval-mozilla-esr10?
Attachment #614752 - Flags: approval-mozilla-esr10+
Attachment #614752 - Flags: approval-mozilla-beta?
Attachment #614752 - Flags: approval-mozilla-beta+
Attachment #614752 - Flags: approval-mozilla-aurora?
Attachment #614752 - Flags: approval-mozilla-aurora+
Summary: cairo_dwrite_font_face Memory Corruption Vulnerability → cairo_dwrite_font_face Memory Corruption Vulnerability [V-49y00m3lf2]
Whiteboard: [sg:critical?]
Alias: CVE-2012-0472
Whiteboard: [sg:critical?] → [sg:critical?][qa+]
Keywords: sec-critical
Whiteboard: [sg:critical?][qa+] → [sg:critical][qa+]
(In reply to Jonathan Kew (:jfkthame) from comment #6)
> Created attachment 614725 [details]
> modified testcase, crashes on current trunk (as well as release channels)
> 
> This example will crash all builds up through current Nightly, when running
> on Win7 with hardware acceleration *disabled*.

Verified crash in Firefox 11 in _cairo_dwrite_font_face_scaled_font_create and a lack of crash in Firefox 12. Calling this verified.
Status: RESOLVED → VERIFIED
verified on Windows 7 x64 w/ ESR 10.0.5 (Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.5) Gecko/20100101 Firefox/10.0.5)

Disabled hardware acceleration and loaded the test case in ESR text counter did not load as expected.
Verified fixed in Firefox 13.0RC and 14.0a2 2012-06-04.
Is there a targeted date for the official disclosure of this vulnerability? From what I gather from the above, the fix is already in publicly released versions.
Group: core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: