Closed Bug 775793 Opened 12 years ago Closed 12 years ago

nsBMPDecoder alpha channel processing memory corruption

Categories

(Core :: Graphics: ImageLib, defect)

x86
All
defect
Not set
critical

Tracking

()

VERIFIED FIXED
mozilla17
Tracking Status
firefox14 + wontfix
firefox15 + verified
firefox16 + verified
firefox17 + verified
firefox-esr10 15+ verified

People

(Reporter: hoguin, Assigned: jgilbert)

References

Details

(4 keywords, Whiteboard: [advisory-tracking+])

Attachments

(3 files, 1 obsolete file)

This bug is present in the nsBMPDecoder class, in the code responsible for processing alpha channel data. It allows a remote attacker to write random memory, hence the critical severity. User action is needed in the following form: the user needs to open a web page containing a specially crafted image. The vulnerable code lies in nsBMPDecoder.cpp, at line 519: 510 if (mUseAlphaData) { 511 if (!mHaveAlphaData && p[3]) { 512 // Non-zero alpha byte detected! Clear previous 513 // pixels that we have already processed. 514 // This works because we know that if we 515 // are reaching here then the alpha data in byte 516 // 4 has been right all along. And we know it 517 // has been set to 0 the whole time, so that 518 // means that everything is transparent so far. 519 memset(mImageData + (mCurLine - 1) * GetWidth(), 0, 520 (GetHeight() - mCurLine + 1) * 521 GetWidth() * sizeof(PRUint32)); 522 mHaveAlphaData = true; 523 } This code is responsible for clearing pixels in the mImageData array, when it is processing a BMP image with an alpha channel, and encounters for the first time a non-zero alpha byte. The third parameter of memset is calculated using GetHeight(), which returns the raw "height" header value, even when it is negative (which is allowed for BMP images, it means pixels are stored top-to-bottom instead of bottom-to-top). The result of this calculation is then used as an unsigned 32 bits integer by memset. If GetHeight() returns a negative value, the calculation will result in a very large unsigned number, and memset() will run past the mImageData array, resulting in a memory corruption, which could in turn lead to arbitrary code execution. The code snippet above will be executed only if mUseAlphaData is true. The only way for this to happen is to have a BMP image embedded in an icon file (.ico). The nsICODecoder will instantiate a nsBMPDecoder, and call its method SetUseAlphaData with the parameter "true", which will set mUseAlphaData to true: nsICODecoder.cpp: 434 nsBMPDecoder *bmpDecoder = new nsBMPDecoder(mImage, mObserver); 435 mContainedDecoder = bmpDecoder; 436 bmpDecoder->SetUseAlphaData(true); Another condition is that the BMP pixel array must be in 32 bits per pixel format (Red, Green, Blue, Alpha). This is done simply by setting the "bpp" field to 32 in the image header. The last condition is that at least one alpha byte must be non-zero. The attached file "bmp_with_alpha.ico" triggers the vulnerability. Here is a WinDbg log when exploiting the vulnerability in Firefox on Windows XP: (53c.734): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=062f0380 ebx=05c3a0d0 ecx=01ffffd8 edx=00000000 esi=05d1fdd8 edi=062f1000 eip=781472d7 esp=0012cbe8 ebp=0012cbec iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 MSVCR80!strnicmp+0x7c: 781472d7 660f7f07 movdqa xmmword ptr [edi],xmm0 ds:0023:062f1000=???????????????????????????????? 0:000> k ChildEBP RetAddr WARNING: Stack unwind information not available. Following frames may be wrong. 0012cbec 78147344 MSVCR80!strnicmp+0x7c 0012cc0c 012ecf98 MSVCR80!strnicmp+0xe9 0012cc44 0119f049 xul!mozilla::imagelib::nsBMPDecoder::WriteInternal+0x1a9368 0012cca8 010de143 xul!mozilla::imagelib::nsICODecoder::FixBitmapWidth+0x13 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\decoders\nsicodecoder.cpp @ 208] 0012ccc8 0113410e xul!mozilla::imagelib::RasterImage::WriteToDecoder+0x3e [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\rasterimage.cpp @ 2370] 0012cce4 010b9526 xul!mozilla::imagelib::RasterImage::DecodeSomeData+0x35 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\rasterimage.cpp @ 2702] 0012cd3c 010f6ba2 xul!mozilla::imagelib::imgDecodeWorker::Run+0xfe [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\rasterimage.cpp @ 2819] 0012cd50 010f6be3 xul!mozilla::imagelib::RasterImage::AddSourceData+0xcf [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\rasterimage.cpp @ 1496] 0012cda4 0104cfb6 xul!mozilla::imagelib::RasterImage::WriteToRasterImage+0x15 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\rasterimage.cpp @ 2917] 0012cda4 0104cfb6 xul!imgRequest::OnDataAvailable+0x466 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\imgrequest.cpp @ 1166] 0012d004 010f1121 xul!imgRequest::OnDataAvailable+0x466 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\imgrequest.cpp @ 1166] 0012d024 010a7f3a xul!ProxyListener::OnDataAvailable+0x26 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\image\src\imgloader.cpp @ 2091] 0012d050 010981c3 xul!nsBaseChannel::OnDataAvailable+0x49 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\netwerk\base\src\nsbasechannel.cpp @ 774] 0012d094 0109807a xul!nsInputStreamPump::OnStateTransfer+0xd3 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\netwerk\base\src\nsinputstreampump.cpp @ 512] 0012d0a8 01097df3 xul!nsInputStreamPump::OnInputStreamReady+0x6d [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\netwerk\base\src\nsinputstreampump.cpp @ 409] 0012d0b8 00fbee5f xul!nsInputStreamReadyEvent::Run+0x1d [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\xpcom\io\nsstreamutils.cpp @ 115] 0012d104 100026f5 xul!nsThread::ProcessNextEvent+0x19f [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\xpcom\threads\nsthread.cpp @ 666] 0012d144 011bc8e2 nspr4!PR_Unlock+0x25 00000000 00000000 xul!MessageLoop::RunHandler+0x21 [e:\builds\moz2_slave\rel-m-rel-w32-bld\build\ipc\chromium\src\base\message_loop.cc @ 202]
Status: UNCONFIRMED → NEW
Ever confirmed: true
In addition there's an invalidation that's incorrect, but clearly this part is more serious.
Nice find! Thanks for the detailed and clear bug report.
Assignee: nobody → netzen
(In reply to David Baron [:dbaron] from comment #1) > In addition there's an invalidation that's incorrect, but clearly this part > is more serious. Could you post a new bug for that and CC me? Or if you provide more info then I can post.
This should do it. I'll check for repro presently.
Assignee: netzen → jgilbert
Attachment #644132 - Flags: review?(netzen)
Comment on attachment 644132 [details] [diff] [review] Clarify usage of height and GetHeight in the BMP decoder Review of attachment 644132 [details] [diff] [review]: ----------------------------------------------------------------- Oops. ::: image/decoders/nsBMPDecoder.h @@ +40,3 @@ > PRInt32 GetHeight() const; > + // Is the height inverted in the BIH header > + bool IsHeightInverted() const; Ack, thought I deleted this.
By the way I already had a patch for this, could you be sure to take a bug before you work on it or else don't work on a bug when someone else takes it? That way we don't waste time duplicating efforts.
(In reply to Brian R. Bondy [:bbondy] from comment #7) > By the way I already had a patch for this, could you be sure to take a bug > before you work on it or else don't work on a bug when someone else takes > it? That way we don't waste time duplicating efforts. Oops, sorry. Will do in the future.
Comment on attachment 644132 [details] [diff] [review] Clarify usage of height and GetHeight in the BMP decoder Review of attachment 644132 [details] [diff] [review]: ----------------------------------------------------------------- Looks good, please push to try first but it should all pass. Also we should request this for aurora, beta and esr10 once it lands on m-c.
Attachment #644132 - Flags: review?(netzen) → review+
Just remove your self found nit btw. Also for dbaron please ignore my Comment 4, I realized what you meant after I posted that.
I'm afraid I don't have the imagination to see how to parlay writing a large number of zeros into the kind of control you need for an exploit. Maybe I should suspend judgement until we see the "Exploiting jemalloc" talk at this year's BlackHat.
Keywords: crash
Crash does not occur after patch. Try is clean.
Attached patch fixed patchSplinter Review
Carrying forward r+.
Attachment #644132 - Attachment is obsolete: true
Attachment #645036 - Flags: review+
Status: NEW → ASSIGNED
Target Milestone: --- → mozilla17
Can we get a sg rating for this? It's pretty trivial to trigger, and I believe you can basically choose how many zeros you want.
Whiteboard: [sg:high?]
Comment on attachment 645036 [details] [diff] [review] fixed patch [Approval Request Comment] Bug caused by (feature/regressing bug #): Bug 682688 User impact if declined: Crashy browser for an uncommon set of valid images, and security concerns. Testing completed (on m-c, etc.): m-c, tested/fixed locally Risk to taking this patch (and alternatives if risky): Low. String or UUID changes made by this patch: None.
Attachment #645036 - Flags: approval-mozilla-beta?
Attachment #645036 - Flags: approval-mozilla-aurora?
I'm less worried about a consecutive string of nulls than the slightly different case in bug 775794. But we should fix both anyway.
Keywords: sec-moderate
Whiteboard: [sg:high?]
Status: ASSIGNED → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Comment on attachment 645036 [details] [diff] [review] fixed patch [Triage Comment] Please also prepare a patch for the ESR branch.
Attachment #645036 - Flags: approval-mozilla-beta?
Attachment #645036 - Flags: approval-mozilla-beta+
Attachment #645036 - Flags: approval-mozilla-aurora?
Attachment #645036 - Flags: approval-mozilla-aurora+
Comment on attachment 645036 [details] [diff] [review] fixed patch [Approval Request Comment] If this is not a sec:{high,crit} bug, please state case for ESR consideration: Request from akeybl. User impact if declined: Crashes for valid (if uncommon) images, DOS through crashing. Sec-moderate vulnerability. Fix Landed on Version: m-c, aurora, beta Risk to taking this patch (and alternatives if risky): Low. String or UUID changes made by this patch: None See https://wiki.mozilla.org/Release_Management/ESR_Landing_Process for more info.
Attachment #645036 - Flags: approval-mozilla-esr10?
Should I prepare a FF 14 patch, or is that a WONTFIX?
Attachment #645036 - Flags: approval-mozilla-esr10? → approval-mozilla-esr10+
(In reply to Jeff Gilbert [:jgilbert] from comment #24) > Should I prepare a FF 14 patch, or is that a WONTFIX? Thanks for checking in - this is wontfix for 14 at this point.
Attached patch esr10 backportSplinter Review
This is the patch backported to esr10.
Attachment #645593 - Flags: review+
Whiteboard: [advisory-tracking+]
Does this need a testcase in-testsuite?
Whiteboard: [advisory-tracking+] → [advisory-tracking+][qa?]
I don't think so
(In reply to Brian R. Bondy [:bbondy] from comment #29) > I don't think so Okay, thanks, we will verify this manually with the attached testcase.
Whiteboard: [advisory-tracking+][qa?] → [advisory-tracking+][qa+]
Keywords: verifyme
Confirmed reproducible with 2012-07-19 Firefox 17.0a1 Debug. Verified fixed with: * 2012-08-24 Firefox 17.0a1 Debug * 2012-08-24 Firefox 16.0a2 Debug * 2012-08-24 Firefox 15.0 Debug * 2012-08-24 Firefox 10.0.7esr Debug
Status: RESOLVED → VERIFIED
Keywords: verifyme
QA Contact: anthony.s.hughes
Whiteboard: [advisory-tracking+][qa+] → [advisory-tracking+]
Group: core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: