Closed Bug 374260 Opened 18 years ago Closed 17 years ago

enumerating over the java, netscape or Packages objects results in crash

Categories

(Core :: Widget: Cocoa, defect)

PowerPC
macOS
defect
Not set
critical

Tracking

()

RESOLVED FIXED

People

(Reporter: msg, Assigned: smichaud)

References

Details

(Keywords: crash, Whiteboard: [sg:critical?][post 1.8-branch])

Attachments

(4 files)

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2 Build Identifier: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.9a3pre) Gecko/20070316 Minefield/3.0a3pre The following causes a crash in the Java Embedding Plugin: <script> alert("prepare for crash"); for(x in Packages) { document.write(x); } </script> No clue if this belongs to the DOM folks, jscript proper, or plugins...since it seems to be in the plugin itself, plugins win. Of possible concern is the presence of ascii text as the crash location -- address is the string 'try' backwards -- suggesting the source of the value is an unitialized variable, heap value, or something that may be alterable by an attacker. Reproducible: Always Steps to Reproduce: 1.run attached html file Actual Results: crash Expected Results: contents of referenced objects
Attached file repro html —
This is worksforme with current trunk and 1.8.1 branch build on windows.
Sorry -- browser crashed when I was filling this out originally. ;) I can confirm this does *not* happen under Win32 -- I only see it on OSX.
The testcase is similar to that of bug 344804 and bug 349964. Steven, can you reproduce the crash?
Flags: blocking1.9?
Whiteboard: [sg:critical?]
I can reproduce this crash (and another very different one) with Minefield, but not with any of the non-trunk Mozilla.org browsers that I tried (Firefox 2.0.0.3, Camino 1.0.4, Seamonkey 1.1.1). I'm convinced that this is a Mozilla.org bug/design-flaw, and that it's related to bug 347598. I'm currently trying to track the bug down ... which may take a few days. I'll comment again when I have something more definite to say.
Status: UNCONFIRMED → NEW
Ever confirmed: true
After some digging around, I've found that (at least) three bugs are involved here -- one of them is a JEP bug, and the other two are browser bugs (I'll talk about the browser bugs in later messages). The JEP bug is a crash that happens when the JEP iterates over all the browser's windows (in [JEPController hookExistingObjects] or [JEPController allSubviews] (called from hookExistingObjects)), and the last NSWindow's contentView turns out to be invalid (which triggers the crash). I'm not sure why the contentView is invalid (it may be an Apple bug, or conceivably a browser bug). But it's pretty clear that the NSWindow in question is the alert box (the one that says "prepare for crash"), which has just been dismissed (by clicking on its "OK" button). The crash doesn't happen when I comment out 'alert("prepare for crash");' Though the partially invalid alert window is still in NSApp's window list, it's no longer visible. So I'll work around this problem by ignoring NSWindows in the window list that aren't visible. The stack trace that lsg-mtso posted in comment #1 is slightly corrupt (there can't have been any call to ShowClassInfo) -- possibly because bundled copies of the JEP have their debug symbols stripped. The trace I'm posting here is more accurate (it was made using an unstripped copy of JEP 0.9.6). Most of my crashes don't seem to have any security implications. But one of them (from a stripped JEP) did also have "ascii text as the crash location": Exception: EXC_BAD_ACCESS (0x0001) Codes: KERN_INVALID_ADDRESS (0x0001) at 0x6e3d314e
I mentioned in comment #6 that I also saw a second, very different crash. Here's a stack trace (one of two nearly identical ones). This is just for the record -- I have no idea if it's relevant.
Even if you comment out 'alert("prepare for crash");' (to avoid the crash), you still see wierdness: No list of packages is displayed. In the Error Console you see "Error: too much recursion". And in the Java Console you see several hundred lines starting as follows (which shows that this is indeed a recursion bug): java.lang.NoClassDefFoundError: __iterator__ at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoSuchMethodError: createClassLoader at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoClassDefFoundError: __iterator__/toSource at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoSuchMethodError: createClassLoader at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoClassDefFoundError: __iterator__/toSource/toSource at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoSuchMethodError: createClassLoader at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) java.lang.NoClassDefFoundError: __iterator__/toSource/toSource/toSource at netscape.oji.JNIRunnable.run(Native Method) at netscape.oji.LiveConnectProxy.run(LiveConnectProxy.java:48) ... The "java.lang.NoSuchMethodError: createClassLoader" lines are irrelevant, benign, and the symptom of yet another browser problem (one I won't discuss here). The ones I'm interested in are those that include "__iterator__". This "__iterator__" operator is used internally to implement iteration (a new feature of JavaScript 1.7) -- needed to interpret the lines for(x in Packages) { document.write(Packages[x]); } But the __iterator__ operator _isn't_ supported in Java. So trying to use it in Java is a bug. (This is the first browser bug.) The second browser bug is what causes the recursion. It's in the js_ReportIsNotFunction() function in js/src/jsfun.c. When the JavaScript interpreter tries to use the __iterator__ operator in Java it gets a NoClassDefFoundError and calls js_ReportIsNotFunction(). Since this is a case of a bad iterator, js_ValueToPrintableSource() gets called (under "if (flags & J2VF_ITERATOR)") -- which tries to call the bad iterator's "toSource" method. But Java doesn't have an __iterator__/toSource class or method -- so js_ReportIsNotFunction() gets called again (recursively), and the same thing happens again, and keeps happening until some kind of internal recursion limit is reached. I plan to open bugs on each of these problems. I'll use a variant of lsg-msto's test case, without the call to alert() (which should avoid spilling any security-sensitive beans). By the way, the code in lsg-msto's test case is partially invalid. If Mozilla.org's JavaScript interpreter could iterate over an array of Java objects, and lsg-msto's code worked properly, it would just display the values of 'x' -- not the names of the Java objects in the array. To display the names of the Java objects you'd need something like this: for(x in Packages) { document.write(Packages[x]); }
> I'm convinced that this is a Mozilla.org bug/design-flaw, and that it's > related to bug 347598. I was wrong -- this bug is completely unrelated to bug 347598. But that's also a browser bug, and I've managed to find a fix for it. I'll report my fix at bug 347598.
I've just released a new version (0.9.6.1) of the Java Embedding Plugin that fixes the JEP crash that I described in comment #7. For more information see bug 376395.
Depends on: 376395
Assignee: nobody → smichaud
This looks like a nullpointer deref per comment 7, so not blocking. However it would be great if we can get this fixed. Steven: any chance you could come up with a fix for 1.9?
Flags: blocking1.9? → blocking1.9-
Whiteboard: [sg:critical?] → [sg:critical?][wanted-1.9]
> This looks like a nullpointer deref Actually the crash bug is something more serious -- it's caused by the last window in the window list (what's returned by [NSApp windows]) having an invalid contentView -- one that's already been deleted. As I say in comment #7, this might be a browser bug (though it could also be an Apple bug). In any case (as I say in comment #11), this crash bug has already been worked around in the current version (now 0.9.6.2) of the Java Embedding Plugin, which has been landed on the trunk and both branches (and is set to appear in Firefox 2.0.0.4 and 1.5.0.12). > Steven: any chance you could come up with a fix for 1.9? The other problems (what I talk about in comment #9) haven't yet been fixed. Yes, I'll probably be able to fix those by 1.9, but I'm not going to be able to work on them right away.
So from the sounds of it this isn't exploitable any more? Is that right? If not, please renominate the bug for 1.9 blocking. It would be great to get separate bugs filed for the problems that remain (which you mentioned in comment 9). As it stands this bug seems to cover many problems which is always confusing.
> So from the sounds of it this isn't exploitable any more? I doubt that the crash bug was ever exploitable (we only have very slight evidence of exploitability, and that comes from stacks created using stripped binaries). But yes, now that the new JEP has worked around it, it's not even potentially exploitable (at least via the JEP). It's still possible that the invalid/deleted contentView problem is a browser bug (and not an Apple bug). But (as far as I know) crashes that result from continuing to use a deleted object usually aren't exploitable. So this problem isn't an urgent one. > It would be great to get separate bugs filed for the problems that > remain I agree. But I don't have a whole lot of time to work on this, so it won't happen right away. I'd say that the two problems mentioned in comment #9 belong in their own bugs. And if it can be shown that the deleted contentView problem is a browser bug, that should also get its own, separate, bug report. Likewise if the deleted contentView problem is an Apple bug, but it's possible that the browser might stumble across it (e.g. if it ever iterates through the [NSApp windows] window list).
Calling virtual methods on a deleted object is actually exploitable most of the time (though i'd rather have the discussion on how elsewhere). Simply using members might not be depending on what the members are used for.
OK. I'd guess the crucial difference is that virtual methods use a vtable and others don't. Though there are different "flavors" of Objective C (C and C++), I don't know whether the Objective C runtime (which is what crashes in this case) ever uses virtual methods. I suspect not (Objective C is quite old, and is part of the Next legacy). I will try to find time in the next week to find out whether the contentView problem is a browser bug, or whether there's any code in the browser that iterates through the window list and touches those windows' contentViews. But if the crash bug is _really_ urgent, it's probably best to get someone else to work on it.
Ok, reassigning to Colin to at least figure out if this is exploitable or not, though I suspect it is.
Assignee: smichaud → cbarrett
Flags: blocking1.9- → blocking1.9+
Whiteboard: [sg:critical?][wanted-1.9] → [sg:critical?]
I don't believe so, although, I couldn't definitively say one way or the other. A method is invoked, internally, by calling objc_msgSend which takes an object, a SEL (const char * name of the method), and then variable arguments. What happens then is that the SEL is looked up in a table and, based upon the object's class, and transformed into an IMP, which is a function pointer like so id (*IMP)(id, SEL, ...). All ObjC methods are actually functions that take two additional arguments, id self and SEL _cmd. That's, in a nutshell, how the runtime works. I'm not sure how you would exploit that.
(In reply to comment #19) > the SEL is looked up in a table and, based upon the > object's class, and transformed into an IMP, which is a function pointer like > so id (*IMP)(id, SEL, ...). The question is, how does the runtime determine the object's class and find the table from |char *| -> IMP? In C++, this is done by having each object carry a vtable around with it (or really, a vtable ptr). When a virtual method is called, the generated code looks up the method address from a fixed offset into the vtable. If the object is deleted, then the vtable ptr will point to invalid memory, and the resulting function address will be bogus, but we'll still treat that address like a real function.
I talked with Colin about this and it sounds like this is exploitable. It might be harder to do it, and you'll get a lower percentage of attempts succeeding, but it seems very doable still.
As far as I know, an object's vtable is actually in the object, at a known (or easily knowable) location, but the SEL -> IMP table is elsewhere (there's a single table maintained by the Objective C Runtime). So I'm going to keep making trouble, and say that I still don't think this crash bug is exploitable :-)
Ok, so here's the rundown: In ObjC all objects contain an isa pointer. This pointer points to the class description containing the class name, what the class inherits, the functions contained in the class, etc. For each function there's a name as a string and a pointer to where the code for the function lives. All objects of the same class have isa pointers pointing to the same class description. Function dispatch gets the isa pointer. It then looks up the requested function name in the list of functions for the class, gets the pointer for the implementation of that function and calls it. Here is how you exploit a call to function "myFunc" on a deleted object. 1. Fill memory with |nop| instructions tailed with evil code that hacks your machine. Create several of these chunks all over memory. 2. Spread fake class description tables all over memory. This table should at least contain a function with the name "myFunc". The implementation pointer is a random address in memory. 3. Make the code make a call to the "myFunc" function on a deleted object 4. The ObjC dispatch code will read the isa pointer on the deleted object and get a random value back since it's reading deleted memory. 5. Chances are that the isa pointer will point to a fake class description table since they are all over the heap. 6. The ObjC dispatch code will dispatch to the random address in the fake class description table. 7. Chances are that this will end up at one of the nop-runs ending with the evil code. This is more or less exactly the same as a standard exploit C++ calling a virtual function on a deleted object which has been shown to work with high success rate. The only difference is that you need to go through the fake class description table, but that only reduces your chances of success, not eliminates it.
I think this scenario is very much less likely than one that uses a deleted object containing a vtable -- there's a much greater chance that a virtual function's vtable pointer (containing random data) points to a nop instruction (leading up to evil code) than that a deleted Objective C's isa pointer points to the beginning of an evil class description table (a class description table is 40 bytes, and a nop is (I think) just one byte). But I concede that it's not impossible. Thanks for your explanation -- I've learned something from it (and from the rest of this discussion).
Assignee: cbarrett → smichaud
I've found that the crash bug is a browser bug, and have spun it off in bug 381087.
Keywords: crash
Keywords: testcase
Jesse just added the keyword "testcase" to this bug. I assume this means that a testcase can be found here (which is true). But I need to say how the testcase should be used for bug 381087 (which is where the "deleted contentView" part of this bug has been spun off). (By the way, the reason I'm talking about this here rather than in bug 381087 is that this bug is potentially security-sensitive.) To use this bug's testcase (attachment 258840 [details]) on bug 381087, you need to make sure your trunk build's bundled version of the JEP is 0.9.6 or older (later versions contain a workaround for bug 381087). The simplest way to do this is to download JEP 0.9.6 (from http://javaplugin.sourceforge.net/) and copy that distro's JavaEmbeddingPlugin.bundle and MRJPlugin.plugin over the existing copies of these bundles in your trunk build's Contents/MacOS/plugins directory. Trunk nightlies built before the fix for bug 373122 was landed should crash with a trace that looks like the "non-currupt stack trace" (attachment 259607 [details]). Trunk nightlies built after that fix was landed shouldn't crash. (The fix for bug 373122 also fixes bug 381087.)
Depends on: 381087
Steven says the sg:critical crash is fixed (I guess that refers to comment 11). I'm resolving this as fixed to reduce confusion. Steven, can you file bugs on the remaining problems, even if you're not planning to fix them right away?
Status: NEW → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
> Steven, can you file bugs on the remaining problems, even if you're > not planning to fix them right away? Yes, I'll do that later this week or early next week.
> Steven says the sg:critical crash is fixed (I guess that refers to > comment 11). No. I'm referring to comment #25 (and comment #26).
qawanted: Does this affect the 1.8 branch as well? We use the same (or nearly) JEP and haven't really touched Java/OJI/Liveconnect so I'd expect so.
Keywords: qawanted
(In reply to comment #30) If you mean the crash bug that was spun off into bug 381087, and which triggered crashes in old versions of the JEP (0.9.6 and older) the answer is "no". (By the way, the JEP version in all current Mozilla.org browsers is now 0.9.6.2.)
The other two problems are also browser bugs (in LiveConnect, see comment #9), but aren't security related. So none of the three different bugs reported here is caused by the JEP, though the crash bug could be triggered by older versions of the JEP.
I'm pretty sure that the "two other bugs" reported in comment #3 _do_ effect the 1.8 branch (and all other current branches), but I haven't tested to be sure.
Steven, have you had time to test? Are those bugs filed separately? If this bug, on its own, doesn't affect the branch, can you add "[post 1.8-branch]" to the status whiteboard? (If there are other, unfiled security bugs that affect the branch, please file them and request blocking.)
The only unfinished business here is opening separate bugs for the "two other bugs" mentioned in comment #3. I hope to file them by the end of this week. (Neither of these bugs is a security bug, and neither of them is urgent, or likely to be attended to anytime soon even after I file them.) > If this bug, on its own, doesn't affect the branch, can you add > "[post 1.8-branch]" to the status whiteboard? "This bug" is a mess. The original report, while technically correct, was totally misleading. I did eventually find the real problem, which I spun off into bug 381087 to avoid confusion. I think this was the correct thing to do ... but it hasn't avoided confusion :-) So (for some purposes at least) I've been treating "this bug" as a dup of bug 381087. That's why Jesse (on my recommendation) marked it FIXED. So in the same spirit I'll add "[post 1.8-branch]" to the status whiteboard. While I'm at it I'll remove qawanted and testcase from the keywords. > If there are other, unfiled security bugs that affect the branch, > please file them and request blocking. There aren't any.
Keywords: qawanted, testcase
Whiteboard: [sg:critical?] → [sg:critical?][post 1.8-branch]
> The original report, while technically correct, was totally > misleading. I skimmed the bug yet again and found part of the reason why people have gotten so confused about this bug -- the "user agent" string in comment #0 refers to Firefox 2.0.0.2. But comment #0's "build identifier" refers to a Minefield nightly. And the two relevant crash logs (attachment 258839 [details] and attachment 259607) were both made using Minefield.
Component: Plug-ins → Widget: Cocoa
Hardware: PC → Macintosh
Version: unspecified → Trunk
> "two other bugs" mentioned in comment #3 Sorry. This should have been: > "two other bugs" mentioned in comment #9
I've opened bugs for the two problems I mentioned in comment #9: "LiveConnect mistakenly tries to use a Java __iterator__ method" bug 389751 "js_ReportIsNotFunction can go into an infinite loop" bug 389863 I also opened bug 389597 ("Use Java Package.getPackage() in JavaScript JavaPackage_resolve()"), which contains a patch that fixes bug 347598 (mentioned several times above) and stops the "infinite loop" from happening with this bug's test case.
Flags: wanted1.8.1.x-
Flags: wanted1.8.0.x-
Group: security
Flags: in-testsuite?
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: