Closed Bug 413902 Opened 17 years ago Closed 17 years ago

XPCSafeJSObjectWrapper's equality hook returns true too much

Categories

(Core :: XPConnect, defect, P2)

x86
Linux
defect

Tracking

()

RESOLVED FIXED

People

(Reporter: jeremy, Assigned: mrbkap)

References

Details

Attachments

(1 file, 2 obsolete files)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9b3pre) Gecko/2007122108
Build Identifier: xulrunner 1.9b3pre

The following simple XUL document demonstrates the problem:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script language="JavaScript" type="application/javascript;version=1.8"><![CDATA[
var w = new XPCNativeWrapper(window).wrappedJSObject;
w.foo = function() {yield;};
alert("Result: " + (w.foo() == {}));
]]></script>
</window>


Reproducible: Always
Maybe wrappedJSObject is returning a wrapper that has a busted JSExtendedClass.equality hook?

jbms also reports that
  typeof(w.foo().send) == 'object',
whereas
  typeof(function() {yield;}().send) == 'function'
Assignee: general → nobody
Blocks: 344494
Status: UNCONFIRMED → NEW
Component: JavaScript Engine → XPConnect
Ever confirmed: true
QA Contact: general → xpconnect
I think I see what's going on here. I'll attach a patch in a little bit.
Assignee: nobody → mrbkap
(In reply to comment #1)
>   typeof(w.foo().send) == 'object',

This is an unfortunate side-effect of how SJOWs work -- wrapped functions are actually SJOWs that know how to call an underlying function. The JS engine would need some additional work to fix this and I don't think anybody's thought that it's worth it.

Requesting blocking based on the relationship to bug 344494.
Status: NEW → ASSIGNED
Flags: blocking1.9?
Attached patch Proposed fix (obsolete) — Splinter Review
The problem is that XPC_GetIdentityObject was returning NULL for both sides of the equality test. I restructured things a little to allow myself to stay sane.
Attachment #299645 - Flags: superreview?(jst)
Attachment #299645 - Flags: review?(jst)
Attached patch With mochitest (obsolete) — Splinter Review
Sorry for the bugspam -- I realized that I'd forgotten to add mochitests.
Attachment #299645 - Attachment is obsolete: true
Attachment #299647 - Flags: superreview?(jst)
Attachment #299647 - Flags: review?(jst)
Attachment #299645 - Flags: superreview?(jst)
Attachment #299645 - Flags: review?(jst)
This problem came up for me when I had to obtain a reference to the top-level chrome window given a reference to an XPCNativeWrapper-wrapped DOMWindow in an xul:browser within the chrome window.  (This was for implementing nsIHelperAppLauncherDialog.)  Using the standard trick of walking up the doc shell tree to get at the top-level chrome window, the result is an XPCNativeWrapper-wrapped reference to the chrome window.  Using wrappedJSObject results in an XPCSafeJSObjectWrapper-wrapped reference, when what is really desired is the unwrapped reference.

Although it seems this particular bug should be fixed, the real solution would seem to be a method for fulling unwrapping an XPCSafeJSObjectWrapper, as there currently does not seem to be any way to do that from JavaScript.
That would be patently unsafe and cause extensions and chrome code to get hacked. Why, exactly, do you need an unwrapped content window? Ideally, we should be unwrapping when you pass your reference into C++ code that can safely deal with content windows.
It seems it would certainly be unsafe if used improperly, but I don't see why it couldn't be used properly, such as in this situation.  I don't want an unwrapped content window; I want an unwrapped reference to the top-level chrome window that contains the content window.  This is the code I am using to obtain a wrapped reference to the chrome window:  (please let me know if it could be exploited)

function get_window_from_frame(frame) {
    try {
        var window = frame.QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIWebNavigation)
            .QueryInterface(Ci.nsIDocShellTreeItem)
            .rootTreeItem
            .QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIDOMWindow).wrappedJSObject;
        /* window is now an XPCSafeJSObjectWrapper */
        return window;
    } catch (e) {
        return null;
    }
}
In this case, |frame| is a content frame? If so, it sounds like XPCNativeWrapper could auto-unwrap if you go from a content thing -> chrome thing, avoiding the need for XPCSafeJSObjectWrapper.

In general, without a wrapper between you and a content object, you cannot do *anything* with that object without becoming exploitable in some way. At this point, wrapper automation is really the only way to go.
Yes, |frame| is a content frame.  I don't understand what you mean by "could auto-unwrap".  That certainly does not seem to be what happens currently, but indeed it could perhaps be useful.  That would break existing code, though, unless you mean only the XPCSafeJSObjectWrapper would automatically not be used when accessing wrappedJSObject on a chrome object, but the XPCNativeWrapper would remain.
I mean an XPCNativeWrapper on a chrome object is mostly redundant and we wouldn't bother wrapping the chrome object as you get it. That would mean that you wouldn't need to use .wrappedJSObject at all at the end of your big expression because it would return the actual object (and not a wrapper wrapper). Am I missing something else?
I suppose that would be fine, but it seems like it could possibly be confusing if XPCNativeWrappers can go away implicitly.  It would also break some existing code.
Comment on attachment 299647 [details] [diff] [review]
With mochitest

- In js/src/xpconnect/tests/mochitest/test_wrappers.html:

+    ok(!(new XPCSafeJSObjectWrapper({}) == new XPCSafeJSObjectWrapper({})),
+       'SJOWs equality hook returns true correctly');
+
+    ok(!(new XPCSafeJSObjectWrapper({}) == new XPCSafeJSObjectWrapper({})),
+       'SJOWs equality hook returns false correctly');

Don't these two tests test the exact same thing, with different explanation?

r+sr=jst with that figured out.
Attachment #299647 - Flags: superreview?(jst)
Attachment #299647 - Flags: superreview+
Attachment #299647 - Flags: review?(jst)
Attachment #299647 - Flags: review+
I filed bug 414296 on avoiding SJOWs for chrome objects retrieved out of XPCNativeWrappers.

The duplicated test was a bad copy/paste.
This will be needed to further the work for a blocking-1.9+ bug.
Attachment #299647 - Attachment is obsolete: true
Attachment #299673 - Flags: superreview+
Attachment #299673 - Flags: review+
Attachment #299673 - Flags: approval1.9?
Comment on attachment 299673 [details] [diff] [review]
Updated to comments

a1.9+=damons
Attachment #299673 - Flags: approval1.9? → approval1.9+
Flags: blocking1.9? → blocking1.9+
Priority: -- → P2
Fix checked in.
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Summary: Improper generators produced using wrappedJSObject from an XPCNativeWrapper → XPCSafeJSObjectWrapper's equality hook returns true too much
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: