Last Comment Bug 762280 - (CVE-2012-3963) use after free in js::gc::MapAllocToTraceKind
: use after free in js::gc::MapAllocToTraceKind
[asan][advisory-tracking+] new in Fx14
: regression, sec-critical
Product: Core
Classification: Components
Component: DOM (show other bugs)
: Trunk
: x86_64 Linux
-- normal (vote)
: mozilla17
Assigned To: Peter Van der Beken [:peterv]
: Matt Wobensmith [:mwobensmith][:matt:]
: Andrew Overholt [:overholt]
Depends on:
Blocks: 821360 740069
  Show dependency treegraph
Reported: 2012-06-06 15:37 PDT by Abhishek Arya
Modified: 2014-07-02 12:54 PDT (History)
13 users (show)
rforbes: sec‑bounty+
See Also:
Crash Signature:
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---

Testcase, from mutation of existing long test. (64.56 KB, application/x-zip-compressed)
2012-06-06 15:37 PDT, Abhishek Arya
no flags Details
v1 (1.37 KB, patch)
2012-07-11 02:32 PDT, Peter Van der Beken [:peterv]
bzbarsky: review+
lukasblakk+bugs: approval‑mozilla‑aurora+
lukasblakk+bugs: approval‑mozilla‑beta+
Details | Diff | Splinter Review

Description User image Abhishek Arya 2012-06-06 15:37:21 PDT
Created attachment 630740 [details]
Testcase, from mutation of existing long test.

Reproduces on trunk.

==16916== ERROR: AddressSanitizer global-buffer-overflow on address 0x7fab8bdc5bb0 at pc 0x7fab8ab5e87d bp 0x7fab789bbdd0 sp 0x7fab789bbdc8
READ of size 4 at 0x7fab8bdc5bb0 thread T2
    #0 0x7fab8ab5e87d in js::gc::MapAllocToTraceKind(js::gc::AllocKind) /usr/local/google/home/aarya/firefox/src/js/src/jsfriendapi.cpp:0
    #1 0x7fab88c80099 in nsXMLHttpRequest::cycleCollection::Trace(void*, void (*)(void*, char const*, void*), void*) /usr/local/google/home/aarya/firefox/src/content/base/src/nsXMLHttpRequest.cpp:663
    #2 0x7fab88c7c9ca in nsXHREventTarget::cycleCollection::Traverse(void*, nsCycleCollectionTraversalCallback&) /usr/local/google/home/aarya/firefox/src/content/base/src/nsXMLHttpRequest.cpp:287
    #3 0x7fab8a2cf99e in nsCycleCollector::MarkRoots(GCGraphBuilder&) /usr/local/google/home/aarya/firefox/src/xpcom/base/nsCycleCollector.cpp:2054
    #4 0x7fab8a2d1db7 in nsCycleCollector::BeginCollection(nsICycleCollectorListener*) /usr/local/google/home/aarya/firefox/src/xpcom/base/nsCycleCollector.cpp:2760
    #5 0x7fab8a2d667e in nsCycleCollectorRunner::Run() /usr/local/google/home/aarya/firefox/src/xpcom/base/nsCycleCollector.cpp:3049
    #6 0x7fab8a2b0824 in nsThread::ProcessNextEvent(bool, bool*) /usr/local/google/home/aarya/firefox/src/xpcom/threads/nsThread.cpp:624
    #7 0x7fab8a21e16d in NS_ProcessNextEvent_P(nsIThread*, bool) /usr/local/google/home/aarya/firefox/src/objdir-ff-asan/xpcom/build/nsThreadUtils.cpp:213
    #8 0x7fab8a2aebbd in nsThread::ThreadFunc(void*) /usr/local/google/home/aarya/firefox/src/xpcom/threads/nsThread.cpp:256
    #9 0x7fab8edcf706 in _pt_root /usr/local/google/home/aarya/firefox/src/nsprpub/pr/src/pthreads/ptthread.c:158
0x7fab8bdc5bb0 is located 0 bytes to the right of global variable 'js::gc::MapAllocToTraceKind(js::gc::AllocKind)::map (/usr/local/google/home/aarya/firefox/src/js/src/jsfriendapi.cpp)' (0x7fab8bdc5b60) of size 80
  'js::gc::MapAllocToTraceKind(js::gc::AllocKind)::map (/usr/local/google/home/aarya/firefox/src/js/src/jsfriendapi.cpp)' is ascii string ''
==16916== ABORTING
Stats: 186M malloced (195M for red zones) by 404853 calls
Stats: 46M realloced by 21407 calls
Stats: 156M freed by 274895 calls
Stats: 24M really freed by 46335 calls
Stats: 412M (105532 full pages) mmaped in 103 calls
  mmaps   by size class: 8:311277; 9:57337; 10:24570; 11:22517; 12:4096; 13:2560; 14:1792; 15:512; 16:640; 17:160; 18:208; 19:56; 20:20;
  mallocs by size class: 8:298456; 9:55207; 10:22104; 11:19974; 12:4008; 13:2088; 14:1570; 15:393; 16:638; 17:146; 18:196; 19:55; 20:18;
  frees   by size class: 8:188758; 9:43497; 10:18577; 11:16765; 12:2858; 13:1836; 14:1370; 15:330; 16:533; 17:126; 18:181; 19:50; 20:14;
  rfrees  by size class: 8:37269; 9:2590; 10:2242; 11:3443; 12:169; 13:216; 14:139; 15:48; 16:159; 17:29; 18:21; 19:9; 20:1;
Stats: malloc large: 415 small slow: 2219
Shadow byte and word:
  0x1ff5717b8b76: f9
  0x1ff5717b8b70: 00 00 00 00 00 00 f9 f9
More shadow bytes:
  0x1ff5717b8b50: 00 00 00 00 06 f9 f9 f9
  0x1ff5717b8b58: f9 f9 f9 f9 05 f9 f9 f9
  0x1ff5717b8b60: f9 f9 f9 f9 00 06 f9 f9
  0x1ff5717b8b68: f9 f9 f9 f9 00 00 00 00
=>0x1ff5717b8b70: 00 00 00 00 00 00 f9 f9
  0x1ff5717b8b78: f9 f9 f9 f9 00 00 00 00
  0x1ff5717b8b80: 00 00 00 00 00 00 00 00
  0x1ff5717b8b88: 00 00 00 00 00 00 00 00
  0x1ff5717b8b90: 00 00 00 00 00 00 00 00
Comment 1 User image Bill McCloskey (:billm) 2012-06-11 14:19:04 PDT
Here's what's happening here. nsXMLHttpRequest has a JSObject* field called mResultArrayBuffer. It's supposed to get traced via NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN. However, in this case we're not calling HoldJSObjects on the nsXMLHttpRequest, so the JS GC is freeing the JSObject while the XHR thinks it still owns it.

We're supposed to be calling HoldJSObjects from RootResultArrayBuffer, which calls nsContentUtils::PreserveWrapper, which calls HoldJSObjects. However, that function returns early if the wrapper is already preserved; that's what's happening here.

It's getting preserved from generated code, inside of mozilla::dom::XMLHttpRequestBinding::_addProperty, which looks like this:

  nsXMLHttpRequest* self = UnwrapDOMObject<nsXMLHttpRequest>(obj);

  JSCompartment* compartment = js::GetObjectCompartment(obj);
  xpc::CompartmentPrivate* priv =
  if (!priv->RegisterDOMExpandoObject(obj)) {
    return false;
  return true;

I'm not sure what the right solution is here. Should we stop relying on PreserveWrapper to hold the JS objects? Or should we fix the new DOM bindings so that they call HoldJSObjects? Or something else?

Anyway, this seems like a pretty serious bug to me. I'm not sure when the new XHR bindings landed, but I'm guessing that's when this regressed.
Comment 2 User image Boris Zbarsky [:bz] (still a bit busy) 2012-06-11 14:24:46 PDT
Those landed for Firefox 14.  See bug 740069.

Sounds like _addProperty should perhaps make the relevant HoldJSObjects call...
Comment 3 User image Bill McCloskey (:billm) 2012-06-11 14:25:45 PDT
Oh, one more thing. If you run this test case in a debug build, it asserts in some layout code. I had to comment out the assertion to see the more serious problem. I think the assertion is unrelated, but someone in layout should probably look at it.
Comment 4 User image Bill McCloskey (:billm) 2012-06-11 14:30:29 PDT
(In reply to Boris Zbarsky (:bz) from comment #2)
> Sounds like _addProperty should perhaps make the relevant HoldJSObjects
> call...

If so, we should probably add a comment to nsWrapperCache::SetPreservingWrapper saying something like "Never call this directly; use nsContentUtils instead." I hate having to do stuff like that, though, so it would be nice if there were a better way.
Comment 5 User image Andrew McCreight [:mccr8] 2012-06-11 14:36:13 PDT
I also see a call to SetPreservingWrapper(true) in ListBase<LC>::ensureExpandoObject.  It looks to me like that object is rooted by RegisterDOMExpandoObject.
Comment 6 User image Andrew McCreight [:mccr8] 2012-06-11 15:29:12 PDT
Oh, right.  I misunderstood the problem.  To spell it out a bit more, the JSObject wrapper itself is held alive by the ensureExpandoObject, which serves the same role as NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER.

nsXMLHttpRequest's Trace function visits two other JS fields, mResultArrayBuffer and mResultJSON, which it expects to be kept alive, but the XHR isn't added as a JS holder, so the GC don't call the trace function, so the GC doesn't know to keep those two fields alive.

It is okay to set SetPreservingWrapper(true) on your wrapper if you aren't a JS holder, but only if you don't have a Trace method.  That seems to be the case for ListBase, or at least a quick search couldn't find a Trace method for that function.
Comment 7 User image Boris Zbarsky [:bz] (still a bit busy) 2012-06-11 15:32:54 PDT
When you say "Trace" method, are you talking about a JSAPI class hook, or CC stuff, or something else?
Comment 8 User image Andrew McCreight [:mccr8] 2012-06-11 15:43:48 PDT
Sorry, I meant the CC stuff.  NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN and NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED.  When a C++ thing is added as a JS holder, its CC trace function gets invoked to find what JS objects it keeps alive, is what I mean.
Comment 9 User image Boris Zbarsky [:bz] (still a bit busy) 2012-06-11 17:59:58 PDT
> Sorry, I meant the CC stuff. 

Ah.  The ListBase itself doesn't have that, of course: it's a singleton proxy handler.  The actual objects are various things like nsContentList, which have a wrapper cache and should definitely have Trace stuff attached to their CC.
Comment 10 User image Peter Van der Beken [:peterv] 2012-06-12 05:53:04 PDT
We could go two ways with this, either start using HoldJSObjects to root/trace non-wrapper members or add a trace hook that calls the CC participant's Trace. I personally am more in favor of the second, but ideally we'd then need to have a way to only add the trace hook if we want to trace more than just the wrapper, and that seems a bit hard to know without hardcoding it in the config file.
Comment 11 User image Kyle Huey [:khuey] (Exited; not receiving bugmail, email if necessary) 2012-06-12 09:12:20 PDT
+1 to everything in comment 10.  I think sticking this in the config file is fine.
Comment 12 User image Jonas Sicking (:sicking) No longer reading bugmail consistently 2012-06-16 18:34:45 PDT
I don't understand most of the discussion here, but I'd like to point out that getting tracing correct is really hard as it is. Especially since testing reliably is hard. So relying on people to additionally remember to put something in the config file in order to avoid exploitable crashes scares me.
Comment 13 User image Andrew McCreight [:mccr8] 2012-07-10 12:49:06 PDT
Has anybody had a change to look at this?  Probably too late to fix for 14, but it looks bad.  (XHR isn't properly rooting a JS object it holds onto.)
Comment 14 User image Andrew McCreight [:mccr8] 2012-07-10 12:49:15 PDT
Comment 15 User image Kyle Huey [:khuey] (Exited; not receiving bugmail, email if necessary) 2012-07-10 13:28:33 PDT
Uh, it really sucks that we dropped the ball on this.
Comment 16 User image Peter Van der Beken [:peterv] 2012-07-11 02:32:12 PDT
Created attachment 640985 [details] [diff] [review]

Let's fix this the slow but safe way for now. I'll file a followup bug to figure out a better approach with a real trace hook.
Comment 17 User image Boris Zbarsky [:bz] (still a bit busy) 2012-07-12 20:46:28 PDT
Comment on attachment 640985 [details] [diff] [review]

r=me if you add a check on our class having the nsISupports bool set.  Or do we not even codegen this hook for non-nsISupports things?  If so, we could just have a comment about that here, and one at the place where that check is done...  Seems like we generate this for all concrete non-worker wrappercached things.  Does that imply nsISupports?
Comment 18 User image Peter Van der Beken [:peterv] 2012-07-16 09:22:01 PDT
Comment 19 User image Peter Van der Beken [:peterv] 2012-07-16 10:32:20 PDT
Comment on attachment 640985 [details] [diff] [review]

[Approval Request Comment]
Bug caused by (feature/regressing bug #): bug 740069
User impact if declined: crashes
Testing completed (on m-c, etc.): landed on mozilla-inbound
Risk to taking this patch (and alternatives if risky): low risk, this reuses existing wrapper preservation code which we already use for all other XPConnect bindings
String or UUID changes made by this patch: none
Comment 20 User image Lukas Blakk [:lsblakk] use ?needinfo 2012-07-16 15:10:23 PDT
Comment on attachment 640985 [details] [diff] [review]

approving for aurora now, we'll need more testing before approving for beta.
Comment 21 User image Ed Morley [:emorley] 2012-07-17 02:29:49 PDT
Comment 22 User image Lukas Blakk [:lsblakk] use ?needinfo 2012-07-20 15:10:34 PDT
Comment on attachment 640985 [details] [diff] [review]

Can we land this on branches now?  Let's get this into beta 2 for testing.
Comment 23 User image Andrew McCreight [:mccr8] 2012-07-23 08:19:14 PDT
This was actually landed on Aurora on 7/18.
Comment 24 User image Andrew McCreight [:mccr8] 2012-07-23 08:23:29 PDT
Peter's Aurora patch applied cleanly to Beta, so I went ahead and landed it.
Comment 26 User image Ioana (away) 2012-11-13 05:48:45 PST
I tried to verify this issue on Ubuntu 12.04 64 bit with the latest Firefox 17 debug build (

Unfortunately, when I try to see the bug on Firefox 14 by uploading Arya's testcase, I get this crash:

When I try to upload the same testcase in the Firefox 17 build mentioned above, I get the following crash:
Fx 17:

Are there any workarounds that could allow QA to verify this bug?
Comment 27 User image Anthony Hughes (:ashughes) [GFX][QA][Mentor] 2012-11-13 12:37:06 PST
This can't be tested with a normal debug build, afaik. It requires an ASAN build. I'm reassigning this to Matt to see if he can help verify.
Comment 28 User image Matt Wobensmith [:mwobensmith][:matt:] 2012-11-14 15:27:35 PST
I'm getting the same crash as Ioana is, above, using latest ASAN builds for Aurora and Nightly, on Ubuntu 11.10 from 2012-11-14.

AFAIC, it is specific to the testcase in this bug.
Comment 29 User image Jesse Ruderman 2012-11-26 13:50:44 PST
Matt, can you file a new bug for the crash you're hitting?

Peter, what would a reduced testcase for this bug look like?  I want to know if my fuzzer is missing something, and I'd like this bug to be regression-tested.
Comment 30 User image Matt Wobensmith [:mwobensmith][:matt:] 2012-12-13 09:58:11 PST
Filed new bug 821360 for the current crash.
Comment 31 User image Bill McCloskey (:billm) 2012-12-13 11:33:38 PST
Please see comment 3 about the crash in CSS code. It's unrelated to this problem.
Comment 32 User image Raymond Forbes[:rforbes] 2013-07-19 18:42:03 PDT
Comment 33 User image Tracy Walker [:tracy] 2014-01-10 10:40:27 PST
mass remove verifyme requests greater than 4 months old

Note You need to log in before you can comment on or make changes to this bug.