Closed Bug 440230 (CVE-2008-2785) Opened 16 years ago Closed 16 years ago

Firefox CSSValue Array Memory Corruption Vulnerability

Categories

(Core :: CSS Parsing and Computation, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: dveditz, Assigned: jst)

References

Details

(4 keywords, Whiteboard: [sg:critical])

Attachments

(6 files)

ZDI submitted the following advisory to us via mail to security@mozilla.org

-- ABSTRACT ------------------------------------------------------------

TippingPoint has identified a vulnerability affecting the following 
products:

    Mozilla Firefox 2.0.x
    Mozilla Firefox 3.0.x

-- VULNERABILITY DETAILS -----------------------------------------------

This vulnerability allows remote attackers to execute arbitrary code on
vulnerable installations of Mozilla Firefox. User interaction is
required to exploit this vulnerability in that the target must visit a
malicious page.

The specific flaw exists in the browser's handling reference counters to
the nsCSSValue:Array class. Creating more then 65,535 references will
overflow a 16-bit reference counter and therefore result in an erroneous
free() while the object still exists. Properly manipulated this can
result in arbitrary code execution under the context of the current
user.

Most reference counters are implemented as unsigned longs and can not be
feasible overflowed with too many reference. However, the
nsCSSValue::Array class uses a 16-bit wide value,
layout/style/nsCSSValue.h (lines 321-335):

void AddRef() {
  ++mRefCnt;
  NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Array", sizeof(*this));
}
void Release() {
  --mRefCnt;
  NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Array");
  if (mRefCnt == 0)
    delete this;
}

private:
  PRUint16 mRefCnt;
  PRUint16 mCount;

An attacker can create an arbitrary number of references to this object
by creating a style definition with counter-increment, counter-reset,
cursor or text-shadow attribute. Setting one of those attributes to an
arbitrary HTML object creates a reference to this object.

Creating more than 65535 HTML objects with reference to this style
definition will overflow the reference counter, which will lead to a
freeing of the object whilst references to it still exist.


-- CREDIT --------------------------------------------------------------

This vulnerability was discovered by:
    * Anonymous
Flags: wanted1.8.1.x+
Flags: blocking1.9.1?
Flags: blocking1.9.0.1?
Flags: blocking1.8.1.16+
Whiteboard: [sg:critical]
Component: Layout → Style System (CSS)
OS: Windows NT → All
QA Contact: layout → style-system
Hardware: PC → All
Attached patch possible patchSplinter Review
I think we should do this here, and elsewhere in the tree.

The nsStyleStruct.{h,cpp} change shouldn't be needed on 1.9 or 1.8.  I haven't yet looked to see if additional changes should be needed there.
Attachment #325690 - Flags: superreview?(roc)
Attachment #325690 - Flags: review?(roc)
(Note that I haven't tested this against the attached ZIP and don't plan to.  I don't have Java installed.  If somebody else wants to try it, you're welcome to.)
Attachment #325690 - Flags: superreview?(roc)
Attachment #325690 - Flags: superreview+
Attachment #325690 - Flags: review?(roc)
Attachment #325690 - Flags: review+
I'd be interested in other people's opinions on whether they agree with this approach (including those already cc:ed).


Also, should I hold off on checking this in to trunk?  (If so, somebody else may need to land it for me.)
Note that for me on mac the testcase hung the browser for ~5minutes until I force-quit it.  Is that how long it takes on windows as well?
Are the PR_UINT32_MAX checks necessary? Possibly on 64-bit systems, but should we use a uint64 mRefCnt there to avoid having to worry?

It's not possible on 32-bit systems to add 2^32-1 refs from JS, of course.

/be
(In reply to comment #5)
> It's not possible on 32-bit systems to add 2^32-1 refs from JS, of course.

...assuming that we have no reference leak bugs.
(In reply to comment #4)
> Note that for me on mac the testcase hung the browser for ~5minutes until I
> force-quit it.  Is that how long it takes on windows as well?

Yes, it took ages while it filled up memory and played games trying to force GC -- very brute-force. A motivated attacker might be able to make this more efficient and workable.

I haven't yet reproduced the claimed "launch calc.exe" PoC, but I did get shut down by Windows DEP which indicates a serious problem.

(In reply to comment #2)
> (Note that I haven't tested this against the attached ZIP and don't plan to.
> I don't have Java installed.

There are actually two testcases, one uses Flash and the other Java.
Attached file testcase
This is a simple html testcase that triggers the crash, without all the memory filling stuff.
This crashes after a gc, which happens after 20 seconds or so.
(In reply to comment #7)
> (In reply to comment #4)
> > Note that for me on mac the testcase hung the browser for ~5minutes until I
> > force-quit it.  Is that how long it takes on windows as well?
> 
> Yes, it took ages while it filled up memory and played games trying to force GC
> -- very brute-force. A motivated attacker might be able to make this more
> efficient and workable.
> 
> I haven't yet reproduced the claimed "launch calc.exe" PoC, but I did get shut
> down by Windows DEP which indicates a serious problem.
> 

If we are shut down by DEP doesn't that mean we are safe from the exploit?
Only on systems with DEP available, so probably not Linux and OS X, and almost certainly not people with pre-x86-64 machines.  I guess you can turn DEP off, too, for some or all applications -- not sure what the defaults are.
(In reply to comment #8)
> This is a simple html testcase that triggers the crash, without all the memory
> filling stuff.
> This crashes after a gc, which happens after 20 seconds or so.

This didn't crash for me on Linux.  It definitely causes a hang, but I left the page open for ~5min before killing the browser.

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0
I got a crash on Mac only after leaving the tab open for quite a while and browsing to other sites in other tabs.  Just letting it sit didn't do it for me.
And david we good to land this on trunk?
I started an email discussion about how we should proceed.

I'd also note that we probably ought to wrap these if-conditions in NS_UNLIKELY.
If you miss the AddRef, like the patch intentionally does, it's not a leak, but you still possibly access a wild pointer, no?
Ah, no, nevermind. If we hit that case, no releases will work anymore for that object, it will indeed never be freed and leaked.
I got this stack trace out of using the test case on winXP

http://crash-stats.mozilla.com/report/index/74cff7fa-3f32-11dd-a7e4-001cc45a2ce4

0  	mozcrt19.dll  	arena_dalloc_small  	 jemalloc.c:4094
1 	mozcrt19.dll 	arena_dalloc 	jemalloc.c:4196
2 	mozcrt19.dll 	free 	jemalloc.c:6009
3 	xul.dll 	nsThebesRegion::FreeRects 	mozilla/gfx/src/thebes/nsThebesRegion.cpp:183
4 	xul.dll 	ConvertNativeRegionToAppRegion 	mozilla/view/src/nsViewManager.cpp:402
5 	xul.dll 	nsViewManager::Refresh 	mozilla/view/src/nsViewManager.cpp:436
6 	xul.dll 	xul.dll@0x2fc068 	
7 	xul.dll 	HandleEvent 	mozilla/view/src/nsView.cpp:168
8 	xul.dll 	nsWindow::DispatchEvent 	mozilla/widget/src/windows/nsWindow.cpp:985
9 	xul.dll 	nsWindow::DispatchWindowEvent 	mozilla/widget/src/windows/nsWindow.cpp:1010
10 	xul.dll 	xul.dll@0x2ec341 	
11 	xul.dll 	nsWindow::ProcessMessage 	mozilla/widget/src/windows/nsWindow.cpp:4288
12 	xul.dll 	nsWindow::WindowProc 	mozilla/widget/src/windows/nsWindow.cpp:1200
13 	user32.dll 	InternalCallWinProc 	
14 	user32.dll 	UserCallWinProcCheckWow 	
15 	user32.dll 	DispatchClientMessage 	
16 	user32.dll 	__fnDWORD 	
17 	ntdll.dll 	KiUserCallbackDispatcher 	
18 	xul.dll 	nsScriptSecurityManager::GetObjectPrincipal 	
19 	user32.dll 	DispatchMessageW 	
20 	xul.dll 	nsAppShell::ProcessNextNativeEvent 	mozilla/widget/src/windows/nsAppShell.cpp:148
21 	xul.dll 	nsBaseAppShell::OnProcessNextEvent 	mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:278
22 	xul.dll 	nsThread::ProcessNextEvent 	mozilla/xpcom/threads/nsThread.cpp:497
23 	xul.dll 	nsBaseAppShell::Run 	mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:170
24 	nspr4.dll 	PR_GetEnv 	
25 	firefox.exe 	wmain 	mozilla/toolkit/xre/nsWindowsWMain.cpp:87
26 	firefox.exe 	firefox.exe@0x217f 	
27 	kernel32.dll 	BaseProcessStart 	

It turns out that Firefox 3.0 Crash Reports [@ arena_dalloc_small ] has been bouncing around the #1-3 top crash reports for the last few days since release, but this stack trace looks fairly unique among all the reports with that stack signature.  

Is there a chance that we will fix other crashes with this fix?  

Could there be other ways to get to exploitable crashes around area_dalloc_small that we need to think about?

search down for "0x5f  	153  	chofmann looking at bugs" to see my crash report among the other arena_dalloc_small reports in 

http://crash-stats.mozilla.com/report/list?product=Firefox&query_search=signature&query_type=contains&range_unit=days&version=Firefox%3A3.0&signature=arena_dalloc_small&range_value=3
W/o looking at this in extreme detail I would *not* expect this to fix any crashes that people are seeing unless they're being directly exploited by someone aware of this problem.
I also got a stack trace out of a Mac crash.

0  	XUL  	nsCSSValue::DoReset  	 mozilla/layout/style/nsCSSStyleRule.cpp:326
1 	XUL 	nsCSSValue::DoReset 	mozilla/layout/style/nsCSSStyleRule.cpp:261
2 	XUL 	nsCSSCompressedDataBlock::Destroy 	mozilla/layout/style/nsCSSDataBlock.cpp:532
3 	XUL 	nsCSSDeclaration::~nsCSSDeclaration 	mozilla/layout/style/nsCSSDataBlock.cpp:109
4 	XUL 	CSSStyleRuleImpl::~CSSStyleRuleImpl 	mozilla/layout/style/nsCSSStyleRule.cpp:240
5 	XUL 	nsCSSRule::Release 	mozilla/layout/style/nsCSSPseudoElements.cpp:64
6 	XUL 	nsAttrValue::EnsureEmptyMiscContainer 	mozilla/content/base/src/nsAtomListUtils.cpp:982
7 	XUL 	nsAttrValue::Reset 	mozilla/content/base/src/nsAtomListUtils.cpp:149
8 	XUL 	nsAttrAndChildArray::Clear 	mozilla/content/base/src/nsAtomListUtils.cpp:177
9 	XUL 	nsAttrAndChildArray::~nsAttrAndChildArray 	mozilla/content/base/src/nsAtomListUtils.cpp:133
10 	XUL 	nsGenericElement::~nsGenericElement 	mozilla/content/base/src/nsGenericElement.cpp:1191
11 	XUL 	nsHTMLBodyElement::~nsHTMLBodyElement 	mozilla/content/html/content/src/nsHTMLBRElement.cpp:57
12 	XUL 	nsNodeUtils::LastRelease 	mozilla/content/base/src/nsNodeUtils.cpp:245
13 	XUL 	nsGenericElement::Release 	mozilla/content/base/src/nsGenericElement.cpp:3571
14 	XUL 	nsXPCOMCycleCollectionParticipant::Unroot 	nsCycleCollectionParticipant.cpp:74
15 	XUL 	nsCycleCollector::CollectWhite 	mozilla/xpcom/base/nsCycleCollector.cpp:1676
16 	XUL 	nsCycleCollector::FinishCollection 	mozilla/xpcom/base/nsCycleCollector.cpp:2434
17 	XUL 	nsCycleCollector_finishCollection 	mozilla/xpcom/base/nsCycleCollector.cpp:2916
18 	XUL 	XPCCycleCollectGCCallback 	mozilla/js/src/xpconnect/src/nsXPConnect.cpp:453
19 	libmozjs.dylib 	js_GC 	mozilla/js/src/jsgc.c:3526
20 	libmozjs.dylib 	JS_GC 	mozilla/js/src/jslong.c:2469
21 	XUL 	nsXPConnect::Collect 	mozilla/js/src/xpconnect/src/nsXPConnect.cpp:529
22 	XUL 	nsCycleCollector::Collect 	mozilla/xpcom/base/nsCycleCollector.cpp:2250
23 	XUL 	nsCycleCollector_collect 	mozilla/xpcom/base/nsCycleCollector.cpp:2898
24 	XUL 	nsJSContext::CC 	mozilla/dom/src/base/nsJSEnvironment.cpp:3346
25 	XUL 	nsUserActivityObserver::Observe 	mozilla/dom/src/base/nsJSEnvironment.cpp:270
26 	XUL 	nsObserverList::NotifyObservers 	mozilla/xpcom/ds/nsObserverList.cpp:128
27 	XUL 	nsObserverService::NotifyObservers 	mozilla/xpcom/ds/nsObserverService.cpp:181
28 	XUL 	nsUITimerCallback::Notify 	mozilla/content/events/src/nsEventStateManager.cpp:208
29 	XUL 	nsTimerImpl::Fire 	mozilla/xpcom/threads/nsTimerImpl.cpp:403
30 	XUL 	nsTimerEvent::Run 	mozilla/xpcom/threads/nsTimerImpl.cpp:490
31 	XUL 	nsThread::ProcessNextEvent 	mozilla/xpcom/threads/nsThread.cpp:510
32 	XUL 	NS_ProcessPendingEvents_P 	nsThreadUtils.cpp:180
33 	XUL 	nsBaseAppShell::NativeEventCallback 	mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:121
34 	XUL 	nsAppShell::ProcessGeckoEvents 	mozilla/widget/src/cocoa/nsAppShell.mm:299
35 	CoreFoundation 	CoreFoundation@0x7260d 	
36 	CoreFoundation 	CoreFoundation@0x72cf7 	
37 	HIToolbox 	HIToolbox@0x2fda3 	
38 	HIToolbox 	HIToolbox@0x2fbbc 	
39 	HIToolbox 	HIToolbox@0x2fa30 	
40 	AppKit 	AppKit@0x40504 	
41 	AppKit 	AppKit@0x3fdb7 	
42 	AppKit 	AppKit@0x38df2 	
43 	XUL 	nsAppShell::Run 	mozilla/widget/src/cocoa/nsAppShell.mm:588
44 	XUL 	nsAppStartup::Run 	mozilla/toolkit/components/startup/src/nsAppStartup.cpp:181
45 	XUL 	XRE_main 	mozilla/toolkit/xre/nsAppRunner.cpp:3170
46 	firefox-bin 	main 	mozilla/browser/app/nsBrowserApp.cpp:158
47 	firefox-bin 	start 	crt.c:272
48 	firefox-bin 	start 	
49 		@0x0 	
roc/jst: dbaron's afk until the 29th, and I'm not involved in this email discussion that was started; where are we on landing this patch? has it been able to bake on mozilla-central?
This hasn't landed yet and we're waiting for more work in this area (by dmandelin) to attempt to identify other areas with the same problem before publishing this change. I'll be doing further work on this issue as well.
Flags: blocking1.9.0.1? → blocking1.9.0.1+
This is a list of member variables named mRefCnt and mRefCount prepared using Dehydra on a Linux trunk build. The name and source location of each member is given. They are grouped by type: showing bits and S/U for signed/unsigned. In parens are given any typedefs or wrapper classes around the mValue member.

The notable stuff is near the top. The nsCSSValue::Array::mRefCnt being 16-bit unsigned is shown. There is also an Assertion::mRefCnt, which is 16-bit signed. Then there is a group of 14 variables that are 32-bit signed or unsigned that are not defined using nsrefcnt, but through PRInt32 or PRUInt32 directly, and 3 more that are nsrefcnt, but not using any wrapper. So those 17 might merit additional attention.

I'm going to search for more stuff by looking for increments inside functions with likely names and maybe broadening the name search a bit.
This is a list of class fields assigned in "refcounting methods" and the expressions used to assign them. A "refcounting method" was defined as any method with a name in:

  AddRef,Release,AddReference,ReleaseReference,Hold,Drop,incr,decr

I didn't spot any bitmasking operations other than the known one in the cycle counting decr. This check did turn up a few other ref count members. I checked them out and none are 16-bit. Let me know if you want the source listing of where they are defined.
This is a minimal patch to make us safe against this problem on 32-bit systems. It's dbaron's 16-bit refcount fix, and the same fix applied to the other 16-bit refcount that dmandelin found. Once this is in we can worry about making our reference counting safe on 64-bit systems IMO, in a separate bug.
Attachment #327032 - Flags: superreview?(roc)
Attachment #327032 - Flags: review?(roc)
Comment on attachment 327032 [details] [diff] [review]
Minimal fix to make us safe on 32-bit systems.

A good start.

However, I agree with dbaron that we really should do this for all refcounts, because a bug is still triggerable if someone finds a refcount leak. We don't find too many of those these days, but still...
Attachment #327032 - Flags: superreview?(roc)
Attachment #327032 - Flags: superreview+
Attachment #327032 - Flags: review?(roc)
Attachment #327032 - Flags: review+
Agreed, but I don't think we need to solve that before landing the fix for this issue, and possibly opening this bug up. And I think when we fix that kind of problem *anywhere* we need to fix them across the board (as best as we can).
Attachment #327032 - Flags: approval1.9.0.1?
nice work folks (go static analysis for the coverage win!).  We should land this on trunk, then on both branches in quick succession.  Before doing so I'd like to understand our 2.0.0.x and 3.0.1 schedules to make sure we can push all updates fast.  
 Martijn's testcase doesn't do anything on branch for me or Sam. Running the PoC case on a server, I simply get the "Warning: Unresponsive script" dialog every 20 seconds or so and nothing else happens. If I tell the script to continue, the process just repeats for another 20 seconds or so. If I stop the script, nothing happens either. 

This was with Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.16pre) Gecko/2008062703 BonEcho/2.0.0.16pre.

I'm going to double-check this on Windows XP.
Behavior is the same on XP (Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16pre) Gecko/2008062703 BonEcho/2.0.0.16pre). Martijn's testcase does not visibly do anything. Running the PoC, I get a unresponsive script prompt (and Firefox is hung until I get it) but can stop the script at that point (or continue it until the next time).
Flags: blocking1.8.1.16+
Comment on attachment 327032 [details] [diff] [review]
Minimal fix to make us safe on 32-bit systems.

a=beltzner, are we landing this under a cover bug? Either way, we should hold off until we're ready to roll builds.
Attachment #327032 - Flags: approval1.9.0.1? → approval1.9.0.1+
Assignee: nobody → jst
Comment on attachment 327032 [details] [diff] [review]
Minimal fix to make us safe on 32-bit systems.

This looks like it applies to the 1.8 branch, and a quick MXR shows only these two int16 mRefCnt variables. Requesting approval unless Johnny says we need a different patch.
Attachment #327032 - Flags: approval1.8.1.17?
Attachment #327032 - Flags: approval1.8.1.16?
I set dom.max_script_run_time to 10,000 in about:config and tried the PoC again
on Firefox 2.0.0.14. While the script happily uses my resources, nothing else
ever happens. All it does is hang my browser. If I leave the default values for
dom.max_script_run_time in place, I get a prompt to stop the script.
Comment on attachment 327032 [details] [diff] [review]
Minimal fix to make us safe on 32-bit systems.

Approved for 1.8.1.16. a=ss for release-drivers.

Please land on the MOZILLA_1_8_BRANCH when you land on 1.9.
Attachment #327032 - Flags: approval1.8.1.17?
Attachment #327032 - Flags: approval1.8.1.16?
Attachment #327032 - Flags: approval1.8.1.16+
Do we have a cover bug under which we're going to land this? jst, are you planning on landing this tonight or tomorrow morning?
I can land whenever, but there's no cover bug. If others think we need one let me know, otherwise I can either just check in referring to this closed bug, or I can check in w/o a bug reference in the commit message.
Fixed on trunk and branches. Bug 443059 filed as a followup.
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
As I mention in comment 33, I see the same behavior in 2.0.0.14 and 2.0.0.16 with this.
This is also CVE-2008-2785
Alias: ZDI-CAN-349 → CVE-2008-2785
Summary: Firefox CSSValue Array Memory Corruption Vulnerability → Firefox CSSValue Array Memory Corruption Vulnerability (zdi-can-349)
Flags: blocking1.8.0.15+
(In reply to comment #33)
> I set dom.max_script_run_time to 10,000 in about:config and tried the PoC
> again on Firefox 2.0.0.14. While the script happily uses my resources,
> nothing else ever happens. All it does is hang my browser.

When it works it alerts a url-escaped string, then after a pause alerts "Done", and when you click "OK" firefox disappears and calc.exe runs. It does this within the bounds of the current max script time. If it's going to work you shouldn't hit the unresponsive script dialog, or maybe once if you've got a slow or loaded machine.

I never got the PoC to work on 2.0.0.x but by code inspection it has the same problem. That probably means the PoC is sensitive to memory layout which unfortunately also means the PoC not working is not necessarily proof that we fixed it.
Summary: Firefox CSSValue Array Memory Corruption Vulnerability (zdi-can-349) → Firefox CSSValue Array Memory Corruption Vulnerability
Flags: blocking1.8.1.17+
Depends on: 337421
Group: core-security
Flags: blocking1.9.1? → blocking1.9.1+
I landed the remainder of my original patch as http://hg.mozilla.org/mozilla-central/rev/447d12ffe764 since it seemed better in than out.
Comment on attachment 327032 [details] [diff] [review]
Minimal fix to make us safe on 32-bit systems.

a=asac for 1.8.0
Attachment #327032 - Flags: approval1.8.0.next+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: