Closed
Bug 730415
Opened 13 years ago
Closed 13 years ago
JS OOM Testing: Invalid free in JSObject::makeDenseArraySlow
Categories
(Core :: JavaScript Engine, defect)
Tracking
()
VERIFIED
FIXED
mozilla13
People
(Reporter: decoder, Assigned: decoder)
Details
(Keywords: crash, testcase, Whiteboard: [qa!] js-triage-needed)
Attachments
(1 file, 1 obsolete file)
1.02 KB,
patch
|
decoder
:
review+
|
Details | Diff | Splinter Review |
The following command crashes on mozilla-central revision 13b571bde26a:
js -A 380 -f js/src/jit-test/shell.js -f js/src/jit-test/tests/jaeger/bug709067.js
I'm getting a glibc abort here:
*** glibc detected *** debug64/js: free(): invalid pointer: 0x0000000000b361a0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x78a8f)[0x7f3434a03a8f]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x73)[0x7f3434a078e3]
In Valgrind:
==6766== Invalid free() / delete / delete[]
==6766== at 0x4C282ED: free (vg_replace_malloc.c:366)
==6766== by 0x403933: js_free (Utility.h:152)
==6766== by 0x4118DD: js::Foreground::free_(void*) (Utility.h:566)
==6766== by 0x41B7C5: JSRuntime::free_(void*) (jscntxt.h:640)
==6766== by 0x41B84B: JSContext::free_(void*) (jscntxt.h:1126)
==6766== by 0x451C07: JSObject::makeDenseArraySlow(JSContext*) (jsarray.cpp:1392)
==6766== by 0x450CD6: array_setGeneric(JSContext*, JSObject*, jsid, JS::Value*, int) (jsarray.cpp:914)
==6766== by 0x533C7D: JSObject::nonNativeSetProperty(JSContext*, jsid, JS::Value*, int) (jsobj.cpp:3124)
==6766== by 0x44649F: JSObject::setGeneric(JSContext*, jsid, JS::Value*, int) (jsobjinlines.h:162)
==6766== by 0x4F9C67: js::SetObjectElementOperation(JSContext*, JSObject*, jsid, JS::Value const&) (jsinterpinlines.h:829)
==6766== by 0x506942: js::Interpret(JSContext*, js::StackFrame*, js::InterpMode) (jsinterp.cpp:2640)
==6766== by 0x4FAFDE: js::RunScript(JSContext*, JSScript*, js::StackFrame*) (jsinterp.cpp:454)
==6766== Address 0xb361a0 is 0 bytes inside data symbol "_ZL17emptyObjectHeader"
At first glance it looks like some pointer arithmetic magic going wrong in jsobj.h (NULL pointer, likely from OOM is added to elements size to form a new pointer that is freed).
If the size is controllable (and I assume it will be somehow), then this is exploitable if the attacker can force OOM for the script in the right moment.
Assignee | ||
Comment 1•13 years ago
|
||
Forgot that the shell.js is a file I created. Just omit the shell.js file and use -A 355, will also reproduce the bug.
Assignee | ||
Comment 2•13 years ago
|
||
I wrote a patch for the JS shell that will output the trace when -A steps in (as in, when js_malloc and friends return NULL due to -A, then a backtrace will be emitted immediately). I hope this helps to track down the faulty code location that does not properly handle the OOM.
Here's the first trace for this test:
Forcing artificial memory allocation function failure:
#0 debug64-bt/js(+0x429f50) (js_malloc at /home/decoder/LangFuzz/mozilla-central/js/src/debug64-bt/shell/../dist/include/js/Utility.h:162)
#1 debug64-bt/js(+0x42bc8d) (JSRuntime::malloc_(unsigned long, JSContext*) at /home/decoder/LangFuzz/mozilla-central/js/src/debug64-bt/shell/../../jscntxt.h:606)
#2 debug64-bt/js(+0x42bd88) (JSContext::malloc_(unsigned long) at /home/decoder/LangFuzz/mozilla-central/js/src/debug64-bt/shell/../../jscntxt.h:1099)
#3 debug64-bt/js(+0x474cb4) (js::ObjectElements* JSContext::new_<js::ObjectElements, int, int>(int, int) at /home/decoder/LangFuzz/mozilla-central/js/src/jscntxt.h:1129)
#4 debug64-bt/js(+0x462611) (JSObject::allocateSlowArrayElements(JSContext*) at /home/decoder/LangFuzz/mozilla-central/js/src/jsarray.cpp:1311)
#5 debug64-bt/js(+0x4626af) (AddLengthProperty at /home/decoder/LangFuzz/mozilla-central/js/src/jsarray.cpp:1332)
#6 debug64-bt/js(+0x46290d) (JSObject::makeDenseArraySlow(JSContext*) at /home/decoder/LangFuzz/mozilla-central/js/src/jsarray.cpp:1390)
#7 debug64-bt/js(+0x461a1d) (array_setGeneric at /home/decoder/LangFuzz/mozilla-central/js/src/jsarray.cpp:914)
#8 debug64-bt/js(+0x547af0) (JSObject::nonNativeSetProperty(JSContext*, jsid, JS::Value*, int) at /home/decoder/LangFuzz/mozilla-central/js/src/jsobj.cpp:3125)
#9 debug64-bt/js(+0x456ed4) (JSObject::setGeneric(JSContext*, jsid, JS::Value*, int) at /home/decoder/LangFuzz/mozilla-central/js/src/debug64-bt/../jsobjinlines.h:162)
#10 debug64-bt/js(+0x50d1a0) (js::SetObjectElementOperation(JSContext*, JSObject*, jsid, JS::Value const&) at /home/decoder/LangFuzz/mozilla-central/js/src/jsinterpinlines.h:829)
#11 debug64-bt/js(+0x519e7b) (js::Interpret(JSContext*, js::StackFrame*, js::InterpMode) at /home/decoder/LangFuzz/mozilla-central/js/src/jsinterp.cpp:2640)
#12 debug64-bt/js(+0x50e517) (js::RunScript(JSContext*, JSScript*, js::StackFrame*) at /home/decoder/LangFuzz/mozilla-central/js/src/jsinterp.cpp:455)
#13 debug64-bt/js(+0x50f058) (js::ExecuteKernel(JSContext*, JSScript*, JSObject&, JS::Value const&, js::ExecuteType, js::StackFrame*, JS::Value*) at /home/decoder/LangFuzz/mozilla-central/js/src/jsinterp.cpp:657)
Not yet really beautiful I know, but I hope it's helpful :)
Comment 3•13 years ago
|
||
The crashing line of JSObject::makeDenseArraySlow is part of OOM recovery code that bhackett rewrote in bug 693221:
https://hg.mozilla.org/mozilla-central/rev/838464854ec6#l2.182
Assignee | ||
Comment 4•13 years ago
|
||
I do have a fix for this that I'll post later when I'm home. not sure if it's correct of course.
Assignee | ||
Comment 5•13 years ago
|
||
I'm feeling lucky, so I created a patch that I think fixes the problem :D
Only call free when | elements | was actually set in | allocateSlowArrayElements |. If the ObjectElement allocation there fails and we return false, then elements remains unchanged and must not be freed.
Attachment #600734 -
Flags: review?(bhackett1024)
Comment 6•13 years ago
|
||
Comment on attachment 600734 [details] [diff] [review]
Patch
Review of attachment 600734 [details] [diff] [review]:
-----------------------------------------------------------------
Oops, good catch.
Attachment #600734 -
Flags: review?(bhackett1024) → review+
Assignee | ||
Comment 7•13 years ago
|
||
Updated the patch to have proper commit message, carrying r+ from last review. Needs check-in.
Assignee: general → choller
Attachment #600734 -
Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #601009 -
Flags: review+
Comment 8•13 years ago
|
||
Comment 9•13 years ago
|
||
Status: ASSIGNED → RESOLVED
Closed: 13 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla13
Updated•13 years ago
|
status-firefox13:
--- → fixed
Comment 10•13 years ago
|
||
From the patch it looks like this is always going to try freeing emptyObjectHeader. Can an attacker influence what's there in a useful way? This should affect the ESR branch so we need to decide if this is a vulnerability that needs to be fixed there.
status-firefox-esr10:
--- → affected
status-firefox12:
--- → affected
Updated•13 years ago
|
tracking-firefox-esr10:
--- → 13+
Whiteboard: js-triage-needed → [sg:critical]js-triage-needed
Whiteboard: [sg:critical]js-triage-needed → [sg:critical][qa+] js-triage-needed
Assignee | ||
Comment 11•13 years ago
|
||
(In reply to Daniel Veditz [:dveditz] from comment #10)
> From the patch it looks like this is always going to try freeing
> emptyObjectHeader.
Agreed. I'm opening this and I guess we won't need this for ESR.
Comment 12•13 years ago
|
||
Is this still correctly marked as an SG:Critical since we've opened it up?
Assignee | ||
Comment 13•13 years ago
|
||
Nope :) Removed sg rating.
Whiteboard: [sg:critical][qa+] js-triage-needed → [qa+] js-triage-needed
Comment 14•13 years ago
|
||
Ubuntu 11.10 64bit
I built Spidermonkey for the latest firefox beta revision (5f412ea09aba) and ran the command from comment #1 (./js -A 355 -f ../jit-test/tests/jaeger/bug709067.js) and no crash occured.
Marking verified for Firefox 13.
Status: RESOLVED → VERIFIED
Whiteboard: [qa+] js-triage-needed → [qa!] js-triage-needed
Assignee | ||
Comment 15•13 years ago
|
||
Thanks for verifying this. However, for tests that use -A, simply running the command for verification on the new revision is not sufficient. The reason is that the -A parameter is the number of internal memory allocations done by the code before an out-of-memory condition is simulated. Thus, this value can easily change on a newer revision and the only way to verify the fix is to retest with a whole range (best, all), possible -A values.
You need to log in
before you can comment on or make changes to this bug.
Description
•