Last Comment Bug 311792 - Unrooted access in Array.prototype methods
: Unrooted access in Array.prototype methods
Status: VERIFIED FIXED
[sg:critical] arbitrary code executio...
: js1.6, verified1.7.13, verified1.8
Product: Core
Classification: Components
Component: JavaScript Engine (show other bugs)
: Trunk
: x86 Linux
: P1 critical (vote)
: mozilla1.8rc1
Assigned To: Igor Bukanov
:
Mentors:
Depends on:
Blocks: sbb?
  Show dependency treegraph
 
Reported: 2005-10-09 10:03 PDT by Igor Bukanov
Modified: 2006-06-14 16:51 PDT (History)
6 users (show)
brendan: blocking1.7.13+
brendan: blocking‑aviary1.0.8+
brendan: blocking1.8rc1+
bob: in‑testsuite+
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
Fix (2.16 KB, patch)
2005-10-09 10:36 PDT, Igor Bukanov
no flags Details | Diff | Splinter Review
Fix 2 (2.43 KB, patch)
2005-10-09 11:05 PDT, Igor Bukanov
no flags Details | Diff | Splinter Review
Fix 3 (2.92 KB, patch)
2005-10-09 13:53 PDT, Igor Bukanov
brendan: review+
mrbkap: review+
brendan: approval‑aviary1.0.8+
brendan: approval1.7.13+
brendan: approval1.8rc1+
Details | Diff | Splinter Review
js1_5/Array/regress-311792-01.js (2.15 KB, text/plain)
2005-10-13 12:27 PDT, Bob Clary [:bc:]
no flags Details
js1_5/Array/regress-311792-02.js (2.38 KB, text/plain)
2005-10-13 12:27 PDT, Bob Clary [:bc:]
no flags Details

Description Igor Bukanov 2005-10-09 10:03:55 PDT
Here is unrooted object access found in Array.prototype implementation in jsarray.c

1. array_slice does not root the array for slice results with trivial
demonstration of segmentation fault in jsshell:

function index_getter()
{
	gc();
	return 100;
}

var a = [0, 1];
a.__defineGetter__(0, index_getter);

uneval(a.slice(0, 1));


To make this to crash the browser just replace "gc();" by 
for (var i = 0; i != 1 << 15; ++i) new Object();

2. array_reverse does not root v and v2 indexes that it use to hold reversing
values. Here is an example for jsshell that demonstrates how to expose 64 bits
that holds JSString value into a script variable:

var subverted = 0;

function index_getter()
{
	delete a[0];
	gc();
	for (var i = 0; i != 1 << 14; ++i) {
		var tmp = new String("test");
		tmp = null;
	}
	return 1;
}

function index_setter(value)
{
	subverted = value;
}

var a = [ Math.sqrt(2), 0 ];
a.__defineGetter__(1, index_getter);
a.__defineSetter__(1, index_setter);

a.reverse();
print(subverted)

On my Linux box it prints 1.3303688272434068e-266 which is assembled from
JSString bits for 'new String("test");' interpreted as double value.

In a similar way one can make a GC thing that JS considers to be JSString from
arbitrary double value which could potentially allow to read arbitrary memory
context into scripts variables via this pseudo-string.

Due to this potential exposure I mark this bug as security-restricted.
Comment 1 Igor Bukanov 2005-10-09 10:36:35 PDT
Created attachment 199011 [details] [diff] [review]
Fix

I am not 100% sure that I can use argv[argc] as a space for the second local
root in array_reverse. Is it OK?
Comment 2 Igor Bukanov 2005-10-09 11:05:35 PDT
Created attachment 199013 [details] [diff] [review]
Fix 2

The previois fix should move, not copy the line with 
*rval = OBJECT_TO_JSVAL(nobj)
to the beginning of the function. So here is removal of the extra assignment.
Comment 3 Brendan Eich [:brendan] 2005-10-09 13:10:19 PDT
Thanks, Igor.  Another old bug that can be safely fixed for 1.8.  mrbkap, can
you drive this one in?

/be
Comment 4 Brendan Eich [:brendan] 2005-10-09 13:13:33 PDT
Comment on attachment 199013 [details] [diff] [review]
Fix 2

To use argv[argc] as a local root, you need to reserve one local root by
changing

    {"reverse", 	    array_reverse,	    0,JSFUN_GENERIC_NATIVE,0},

to have 1 instead of 0 in the last member initializer.

/be
Comment 5 Igor Bukanov 2005-10-09 13:53:33 PDT
Created attachment 199024 [details] [diff] [review]
Fix 3

I used 2 extra local roots to swap temporaries for less hackish code and added
that 2 into array_methods declaration. 

More hackish version would use argv[-2] for the second local root, right?
Comment 6 Brendan Eich [:brendan] 2005-10-09 14:39:14 PDT
Comment on attachment 199024 [details] [diff] [review]
Fix 3

Great, thanks.	I will rely on mrbkap to do a second review and help get this
checked in.

/be
Comment 7 Blake Kaplan (:mrbkap) 2005-10-09 17:59:39 PDT
Comment on attachment 199024 [details] [diff] [review]
Fix 3

r=mrbkap
Comment 8 Igor Bukanov 2005-10-10 02:03:29 PDT
> [sg:low] memory read at least, maybe more

Unfortunately it is the same type of problem as in bug 311497 and can be used
for arbitrary code execution, see comment 10 there for details.
Comment 9 Brendan Eich [:brendan] 2005-10-10 09:21:24 PDT
Blake, would you shepherd this to fixed resolution?  Thanks,

/be
Comment 10 Blake Kaplan (:mrbkap) 2005-10-10 16:33:30 PDT
Fix checked into trunk.
Comment 11 Brendan Eich [:brendan] 2005-10-10 22:18:41 PDT
(In reply to comment #5)
> Created an attachment (id=199024) [edit]
> Fix 3
> 
> I used 2 extra local roots to swap temporaries for less hackish code and added
> that 2 into array_methods declaration. 
> 
> More hackish version would use argv[-2] for the second local root, right?

That would be the callee function object, but it might be bad to overwrite it,
if you use an in-runtime debugger that might be confused.

/be

Comment 12 Blake Kaplan (:mrbkap) 2005-10-11 15:10:20 PDT
Fix checked into MOZILLA_1_8_BRANCH.

Reopening to give to Igor.
Comment 13 Bob Clary [:bc:] 2005-10-13 12:27:09 PDT
Created attachment 199448 [details]
js1_5/Array/regress-311792-01.js
Comment 14 Bob Clary [:bc:] 2005-10-13 12:27:51 PDT
Created attachment 199450 [details]
js1_5/Array/regress-311792-02.js
Comment 15 Bob Clary [:bc:] 2005-11-07 22:33:28 PST
verified firefox 1.5 rc2 linux/win32 2005-11-07
Comment 16 Bob Clary [:bc:] 2005-12-27 10:33:51 PST
testcase+ to get this off my radar. when this is made public, i will check in the test.
Comment 17 Blake Kaplan (:mrbkap) 2006-02-10 18:17:27 PST
Fix checked into the 1.7 branches.
Comment 18 Bob Clary [:bc:] 2006-02-17 01:45:26 PST
js1_5/Array/regress-311792-01.js, js1_5/Array/regress-311792-02.js verified no crash in automatic tests of firefox nightlies 1.7.13, 1.8.0.1, 1.8, 1.9a1 on windows/linux/mac. Note that 1.7.5 and 1.7.12 did crash.

For mozilla 1.7.13 on winxp running the tests in the browser_however_ I was able to get a nightly Mozilla 1.7.13 from 20060213 to crash by clicking and attempting to edit the url in the urlbar back and forth from -01 to -02 however it did not crash immediately. I could not reproduce with a debug firefox trunk build from 20060214. I was able to hit an assert in Firefox 1.0.8 debug build from 20060214 though.

<http://test.mozilla.com/tests/mozilla.org/js/js-test-driver-standards.html?test=js1_5/Array/regress-311792-01.js;language=language;javascript>

Assertion failure: flags != GCF_FINAL, at c:/work/mozilla/builds/ff/1.0.x/mozilla/js/src/jsgc.c:835

+	cx	0x03bb08c0
	thing	0x03baf368
	arg	0x00000000
+	vp	0x03c734e8
+	flagp	0x03bae225 ""
+	obj	0x03baeba8
	nslots	0x00000005
	v	0x80000001
+	end	0x03c734e8
+	rt	0x00ec9e78
+	str	0x03bae9b0
	flags	0x10 ''

js_MarkGCThing(JSContext * 0x03bb08c0, void * 0x03baf368, void * 0x00000000) line 835 + 35 bytes
js_MarkGCThing(JSContext * 0x03bb08c0, void * 0x03bae520, void * 0x00000000) line 919 + 18 bytes
js_MarkGCThing(JSContext * 0x03bb08c0, void * 0x03b2a360, void * 0x00000000) line 919 + 18 bytes
js_MarkGCThing(JSContext * 0x03bb08c0, void * 0x03b2ad50, void * 0x00000000) line 919 + 18 bytes
gc_root_marker(JSDHashTable * 0x00ec9e98, JSDHashEntryHdr * 0x03b8786c, unsigned long 0x000001e6, void * 0x03bb08c0) line 975 + 18 bytes
JS_DHashTableEnumerate(JSDHashTable * 0x00ec9e98, int (JSDHashTable *, JSDHashEntryHdr *, unsigned long, void *)* 0x10042cb0 gc_root_marker(JSDHashTable *, JSDHashEntryHdr *, unsigned long, void *), void * 0x03bb08c0) line 618 + 34 bytes
js_GC(JSContext * 0x03bb08c0, unsigned int 0x00000000) line 1189 + 21 bytes
js_ForceGC(JSContext * 0x03bb08c0, unsigned int 0x00000000) line 1000 + 13 bytes
JS_GC(JSContext * 0x03bb08c0) line 1698 + 11 bytes
nsJSContext::Notify(nsJSContext * const 0x03bb0720, nsITimer * 0x0344b058) line 1859 + 13 bytes
nsTimerImpl::Fire() line 386
nsTimerManager::FireNextIdleTimer(nsTimerManager * const 0x0316f7f0) line 616
nsAppShell::Run(nsAppShell * const 0x02dcd6f8) line 142
nsAppShellService::Run(nsAppShellService * const 0x02dcd638) line 495
xre_main(int 0x00000004, char * * 0x003e6e08, const nsXREAppData * 0x0041e01c kAppData) line 1907 + 35 bytes
main(int 0x00000004, char * * 0x003e6e08) line 58 + 18 bytes
mainCRTStartup() line 338 + 17 bytes
KERNEL32! 7c816d4f()

I think this is fixed, but leaving unverified on the 1.7 branch for now until someone looks at the stack.
Comment 19 Bob Clary [:bc:] 2006-02-18 00:52:49 PST
v ff 1.0.8, 1.5.0.1, 1.5, 1.6a1 20060217 win/linux/mac, mozilla 1.7.13 winxp.
Comment 20 Bob Clary [:bc:] 2006-06-14 16:51:30 PDT
RCS file: /cvsroot/mozilla/js/tests/js1_5/GC/regress-311792-01.js,v
done
Checking in regress-311792-01.js;
/cvsroot/mozilla/js/tests/js1_5/GC/regress-311792-01.js,v  <--  regress-311792-01.js
initial revision: 1.1
done
RCS file: /cvsroot/mozilla/js/tests/js1_5/GC/regress-311792-02.js,v
done
Checking in regress-311792-02.js;
/cvsroot/mozilla/js/tests/js1_5/GC/regress-311792-02.js,v  <--  regress-311792-02.js
initial revision: 1.1
done

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