Closed Bug 157652 Opened 22 years ago Closed 22 years ago

Crash, possible heap corruption in JS Array.prototype.sort

Categories

(Core :: JavaScript Engine, defect)

x86
Windows 2000
defect
Not set
normal

Tracking

()

VERIFIED FIXED

People

(Reporter: security-bugs, Assigned: khanson)

References

Details

(Keywords: crash, js1.5)

Attachments

(1 file, 2 obsolete files)

Submitter name:                zen-parse
   Submitter email address:       zen-parse@gmx.net
   Acknowledgement checkbox:      on
   Product:                       Netscape 6.x
   Operating system:              Unix: x86 Linux
   OS version:                    Redhat 7.0
   Issue summary:                 Javascript Array object heap corruption

Issue details:
Heap corruption with Javascript: the sort 
method of the Array object.


Should be a check that "(size_t) len * 
sizeof(jsval)" won't overflow the int
at 
http://lxr.mozilla.org/mozilla/source/js/src/jsarray.c#824

824     vec = (jsval *) JS_malloc(cx, 
(size_t) len * sizeof(jsval));


These lines of javascript will cause a crash.

...
 a=Array(1073741824); // 0x40000000 (or 
0x100000000/4)
 a.sort();
...

This example will just die trying to access 
unallocated memory, and is
intended merely to show there is a problem.

However, it is possible to control, to a 
degree, the contents of memory
being accessed by this code in such a way as 
to execute arbitrary
instructions.


Tested on:
 Netscape 4.77
 Netscape 6.2.3
(Also Internet Explorer (Version 
6.0.2600.0000.xpclnt_qfe.010827-1803
 with Update Versions: q319182,Q321232) dies 
with an access violation,
 so it seems to be a common construct in the 
handling.)



This form was submitted from
http://help.netscape.com/forms/bug-security.html?cp=bbpctr
with Mozilla/4.76 (Linux 2.2.19-7.0.16 i686; U) Opera 6.0  [en].
I'm not entirely sure this is exploitable, but I have reproduced the crash in a
recent trunk debug build. Please let me know ASAP if you think this can be
exploited to run arbitrary code, for example by overwriting a return address.
Reassigning to Kenton -
Assignee: rogerl → khanson
Keywords: crash
Testcase added to JS testsuite:

      mozilla/js/tests/js1_5/Array/regress-157652.js

Note: if I load this interactively in the debug JS shell, 
I get an assertion failure:

js> load('../../tests/js1_5/shell.js')
js> load('../../tests/js1_5/Array/regress-157652.js')
    BUGNUMBER: 157652
    STATUS: Testing that we don't crash on Array.sort()
    Assertion failure: nbytes != 0, at jsapi.c:1417
Attached patch proposed patch (obsolete) — Splinter Review
Checks for integer overflow.
Blocks: 149801
Keywords: js1.5, mozilla1.1
Comment on attachment 91586 [details] [diff] [review]
proposed patch

The (size_t) cast before len and the parens around the products len *
sizeof(jsval) and (double) len * sizeof(jsval) are unnecessary.

What's more, you do not want to return JS_FALSE without first reporting an
error when failing.  Note that if (!vec), then JS_malloc already reported an
OOM error.

/be
Attachment #91586 - Flags: needs-work+
Rather than reporting a new error and extending js.msg, I suggest leaving the if
(!vec) return false clause alone, and adding the overflow test in an if
condition governing a then block that calls JS_ReportOutOfMemory(cx) and then
returns false.  Who needs "Array too long" as opposed to "Out of memory", for
this silly hard case?

/be
Brendan, the reporter claims this is exploitable and can be used to execute
arbitrary instructions. Do you think that's possible, or is this just a crash?
mstoltz: I don't know how to control the contents of memory beyond the piece
returned by malloc called by JS_malloc, the piece that has length
(size_t)(((double)len * sizeof(jsval)) % 4294967296) bytes.  If the reporter
knows, can you draw him or her out on the technique?

khanson, I suggest adding the overflow case in comment #6 *before* the JS_malloc
call, not after.

/be
Keywords: mozilla1.0.1
Attached patch revised patch (obsolete) — Splinter Review
Fixed nits.
Attachment #91586 - Attachment is obsolete: true
Summary: Crash, possible memory corruption in JS Array Sort → Crash, possible heap corruption in JS Array Sort
Comment on attachment 91626 [details] [diff] [review]
revised patch

>Index: mozilla/js/src/jsarray.c
>===================================================================
>RCS file: /cvsroot/mozilla/js/src/jsarray.c,v
>retrieving revision 3.36
>diff -w -u -2 -r3.36 jsarray.c
>--- mozilla/js/src/jsarray.c	27 May 2002 05:53:57 -0000	3.36
>+++ mozilla/js/src/jsarray.c	17 Jul 2002 11:05:43 -0000
>@@ -822,4 +822,9 @@
>     if (len == 0)
>         return JS_TRUE;
>+                                /* test for integer overflow */

This seems way overindented.  How about making it start in column 5, maybe with
a empty line before it, and capitalized with full stop at end?	Prevailing
style, etc.

>+    if ((size_t) len * sizeof(jsval) != (double) len * sizeof(jsval)) {
>+        JS_ReportOutOfMemory(cx);
>+	      return JS_FALSE;
>+	  }

The last two lines have tabs (one each per line, at the front), horrors!

>     vec = (jsval *) JS_malloc(cx, (size_t) len * sizeof(jsval));

Hmm, maybe a local variable for explicit common subexpression elim:

    size_t nbytes;
    ...
    nbytes = len * sizeof(jsval);
    if (nbytes != (double) len * sizeof(jsval)) {
	...
    }
    vec = (jsval *) JS_malloc(cx, nbytes);

Fix these true nits and sr=brendan@mozilla.org.

/be
>     if (!vec)
Whiteboard: QA note: per nboyd@atg.com, added testcase to rhino-n.tests
Summary: Crash, possible heap corruption in JS Array Sort → Crash, possible heap corruption in JS Array.prototype.sort
True nits fixed.
Attachment #91626 - Attachment is obsolete: true
Comment on attachment 93215 [details] [diff] [review]
revised revised patch

sr=brendan@mozilla.org -- thanks, sorry I lost track of this.  It would be good
to get into 1.1 and 1.0.1.

Roger, can you r=?

/be
Attachment #93215 - Flags: superreview+
Attachment #93215 - Flags: review+
Comment on attachment 93215 [details] [diff] [review]
revised revised patch

r=rogerl
Keywords: nsbeta1+
Comment on attachment 93215 [details] [diff] [review]
revised revised patch

Approved for 1.1 and 1.0.1.  Please add a fixed1.0.1 when fixed on branch.
Attachment #93215 - Flags: approval+
I took the liberty of checking this in (with an extended comment, to justify the
major-comment-style and to make the problem completely clear) to the trunk and
the 1.0 branch.  Thanks to all,

/be
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Patch verified on the trunk and the MOZILLA_1_0_BRANCH in CVS.

The above testcase, mozilla/js/tests/js1_5/Array/regress-157652.js,
no longer crashes on Linux, WinNT, Mac9.1, or Mac OSX.

Marking Verified FIXED.
Status: RESOLVED → VERIFIED
Adding fixed1.0.1, verified1.0.1 keywords -
Whiteboard: QA note: per nboyd@atg.com, added testcase to rhino-n.tests
Group: security?
Flags: testcase+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: