Bug 622015 (CVE-2011-0056)

JavaScript Atom Invalid Index Vulnerability -- iDefense [V-ikgwbx1hqs]

RESOLVED FIXED

Status

()

defect
--
critical
RESOLVED FIXED
9 years ago
8 years ago

People

(Reporter: reed, Assigned: igor)

Tracking

({verified1.9.1, verified1.9.2})

unspecified
Points:
---

Firefox Tracking Flags

(blocking2.0 betaN+, blocking1.9.2 .14+, status1.9.2 .14-fixed, blocking1.9.1 .17+, status1.9.1 .17-fixed)

Details

(Whiteboard: [sg:critical]hardblocker fixed-in-tracemonkey)

Attachments

(3 attachments, 2 obsolete attachments)

Posted file PoC
iDefense VCP Submission V-ikgwbx1hqs

12/29/2010

Mozilla Firefox JavaScript Atom Invalid Index Vulnerability



Description: 

Remote exploitation of a memory corruption vulnerability in Mozilla Organization's FireFox could allow an attacker to execute arbitrary code with the privileges of the current user.



The vulnerability occurs in the JavaScript engine (SpiderMonkey) of Mozilla FireFox. When compiling javascript, the Mozilla engine produces bytecode that is later interpreted in a virtual machine. Strings and other literals (so called atoms) are stored in an atom map. Opcodes that use values from the atom map take a 16 bit immediate constant operand that is used as an index in the atom map array. When more than 64k atoms are used, special handling is required because a 16 bit value would not suffice to address the desired atom. Therefore, the engine frames the opcode with an "indexbaseX" and a "resetbase0" opcode that move the atoms pointer forward and backward respectively. When an exception is thrown in between the indexbase and resetbase opcodes, the atoms pointer does not get reset and the exception object of the catch block is read from an invalid memory address. This results in an exploitable memory corruption vulnerability. 



Analysis: 

Exploitation of this vulnerability results in the execution of arbitrary code with the privileges of the user viewing the web page. To exploit this vulnerability, a targeted user must load a malicious webpage created by an attacker. An attacker typically accomplishes this via social engineering or injecting content into compromised, trusted sites. After the user visits the malicious web page, no further user interaction is needed.



In order to exploit this vulnerability, it is necessary control various structures at the location of the invalid reference. By performing a heap spray it is possible to populate memory with the needed structures and obtain reliable arbitrary code execution. 



Credit: 

Christian Holler
blocking2.0: --- → betaN+
Word has it that Igor is the one to handle this. Let us know if this turns out to be wrong.
Assignee: general → igor
Summary: JavaScript Atom Invalid Index Vulnerability (iDefense VCP V-ikgwbx1hqs) → JavaScript Atom Invalid Index Vulnerability -- iDefense [V-ikgwbx1hqs]
Not blocking this bug, but it seems like we should reevaluate the space/time benefits of all this indexbase complexity.
blocking1.9.1: --- → ?
blocking1.9.2: --- → ?
status1.9.1: --- → ?
status1.9.2: --- → ?
(In reply to comment #2)
> Not blocking this bug, but it seems like we should reevaluate the space/time
> benefits of all this indexbase complexity.

I am going to try 3-byte indexes and see how this affects interpreter-only benchmarks.
Posted patch v1 (obsolete) — Splinter Review
Here is an untested work-in-progress.
Posted patch v2 (obsolete) — Splinter Review
Here is another WIP - it still fails few tests during make check.
Attachment #500368 - Attachment is obsolete: true
The resulting patch for expanding the literal index to 3 bytes is too big to port it to branches. Apparently the macros to work with the bytecode do not abstract the literal index sufficiently to allow for a small and easy to test patch. So I will delegate that to the bug 622557 while focusing here on hopefully one-liner fix.
A simpler test case that builds a function source with over 64K literals:

var src = "var a=[";
for(var i  = 0; i != 1e5; ++i)
    src += "'a"+i+"',";
src += "]; i = 'xyz';";
src += "try { x.y; return a; } catch(e) { return this[i]; }";

var x = { get y() { throw 0; }};
var xyz = 42;

assertEq(Function(src)(), 42);


It asserts/crashes in debug/optimized builds.
blocking1.9.1: ? → .17+
blocking1.9.2: ? → .14+
Posted patch two-liner fixSplinter Review
The fix adds missing re-initialization of atoms.
Attachment #500411 - Attachment is obsolete: true
Attachment #500865 - Flags: review?(brendan)
Comment on attachment 500865 [details] [diff] [review]
two-liner fix

Need back-porting, should be easy.

/be
Attachment #500865 - Flags: review?(brendan) → review+
Whiteboard: hardblocker
http://hg.mozilla.org/tracemonkey/rev/61e3418e4223
Whiteboard: hardblocker → hardblocker fixed-in-tracemonkey
Whiteboard: hardblocker fixed-in-tracemonkey → [sg:critical?]hardblocker fixed-in-tracemonkey
The bug is definitely critical
Whiteboard: [sg:critical?]hardblocker fixed-in-tracemonkey → [sg:critical]hardblocker fixed-in-tracemonkey
http://hg.mozilla.org/mozilla-central/rev/61e3418e4223
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Guys, can we get this on the branches?
Please note that the particular PoC attached here is a shell PoC only and won't run in browser (it might even fail in the shell, it was tested with Ubuntu and the shell from Firefox 3.6.11 release). Exploitation in the browser works the same as in shell but requires more complicated heap spraying to work reliable.

I won't ever publish the working exploit for the browser.
Fyi, successful exploitation in the shell looks like this:

 Program received signal SIGSEGV, Segmentation fault.
 0x08177853 in js_Interpret (cx=0x81ba9e0) at jsops.cpp:2208
 2208                        ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
 (gdb) print fun->u.n.native
 $1 = (JSNative) 0xdeadbeef
 (gdb)
The patch is a trivial backport to 1.9.2, here is a plain diff between the trunk and it:

4,7c4,7
< @@ -6805,7 +6805,6 @@ END_CASE(JSOP_ARRAYPUSH)
<          // Handle exceptions as if they came from the imacro-calling pc.
<          regs.pc = regs.fp->imacropc();
<          regs.fp->clearImacropc();
---
> @@ -3069,7 +3069,6 @@ js_Interpret(JSContext *cx)
>          // Handle other exceptions as if they came from the imacro-calling pc.
>          regs.pc = fp->imacpc;
>          fp->imacpc = NULL;
10d9
<  #endif
12c11,12
< @@ -6834,6 +6833,9 @@ END_CASE(JSOP_ARRAYPUSH)
---
>      JS_ASSERT((size_t)((fp->imacpc ? fp->imacpc : regs.pc) - script->code) < script->length);
> @@ -3092,6 +3091,9 @@ js_Interpret(JSContext *cx)
Attachment #504464 - Flags: approval1.9.2.14?
Comment on attachment 504464 [details] [diff] [review]
fix for 19[12]

The 192 patch applies as-is to 191.
Attachment #504464 - Attachment description: fix for 192 → fix for 19[12]
Attachment #504464 - Flags: approval1.9.1.17?
Comment on attachment 504464 [details] [diff] [review]
fix for 19[12]

a=LegNeato for 1.9.2.14 and 1.9.1.17
Attachment #504464 - Flags: approval1.9.2.14?
Attachment #504464 - Flags: approval1.9.2.14+
Attachment #504464 - Flags: approval1.9.1.17?
Attachment #504464 - Flags: approval1.9.1.17+
Verified crash in 1.9.1.16 with PoC and fix in Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.17pre) Gecko/20110121 Shiretoko/3.5.17pre ( .NET CLR 3.5.30729).

Same with 1.9.2.13 and Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.14pre) Gecko/20110121 Namoroka/3.6.14pre ( .NET CLR 3.5.30729).
Alias: V-ikgwbx1hqs → CVE-2011-0056
Posted patch Fix for 1.9.0Splinter Review
Would that be enough for 1.9.0 ? (It looks like so ; at least the testcase doesn't crash anymore)
Attachment #512152 - Flags: review?(igor)
Comment on attachment 512152 [details] [diff] [review]
Fix for 1.9.0

Please use diff -U8 the next time you attach the patch for a review to get more context.
Attachment #512152 - Flags: review?(igor) → review+
Group: core-security
You need to log in before you can comment on or make changes to this bug.