Bug 911864 - When QIing objects bound with XBL scopes, route the XPCWrappedJS through an XrayWrapper from the XBL scope. r=smaug, a=bajaj
authorBobby Holley <bobbyholley@gmail.com>
Fri, 01 Nov 2013 15:31:57 +0100
changeset 166490 efe11f1a745210be3d3d458b38a6f73e827af6c8
parent 166489 0f6033849d0026c532dc9a909e4b27d2a936a8be
child 166491 48545fba1c3c1e357b2a993250a60d9f10be333e
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, bajaj
bugs911864
milestone27.0a2
Bug 911864 - When QIing objects bound with XBL scopes, route the XPCWrappedJS through an XrayWrapper from the XBL scope. r=smaug, a=bajaj
content/xbl/src/nsBindingManager.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcpublic.h
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -36,16 +36,18 @@
 #include "nsIXPConnect.h"
 #include "nsDOMCID.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsTHashtable.h"
 
 #include "nsIScriptContext.h"
 #include "nsBindingManager.h"
+#include "xpcpublic.h"
+#include "jswrapper.h"
 #include "nsCxPusher.h"
 
 #include "nsThreadUtils.h"
 #include "mozilla/dom/NodeListBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -725,26 +727,39 @@ nsBindingManager::GetBindingImplementati
         do_QueryInterface(doc->GetWindow());
       if (!global)
         return NS_NOINTERFACE;
 
       nsIScriptContext *context = global->GetContext();
       if (!context)
         return NS_NOINTERFACE;
 
-      AutoPushJSContext jscontext(context->GetNativeContext());
-      if (!jscontext)
+      AutoPushJSContext cx(context->GetNativeContext());
+      if (!cx)
         return NS_NOINTERFACE;
 
       nsIXPConnect *xpConnect = nsContentUtils::XPConnect();
 
-      JSObject* jsobj = aContent->GetWrapper();
+      JS::Rooted<JSObject*> jsobj(cx, aContent->GetWrapper());
       NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE);
 
-      nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, jscontext,
+      // If we're using an XBL scope, we need to use the Xray view to the bound
+      // content in order to view the full array of methods defined in the
+      // binding, some of which may not be exposed on the prototype of
+      // untrusted content.
+      //
+      // If there's no separate XBL scope, we'll end up with the global of the
+      // reflector, and this will all be a no-op.
+      JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScope(cx, jsobj));
+      JSAutoCompartment ac(cx, xblScope);
+      bool ok = JS_WrapObject(cx, &jsobj);
+      NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+      MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj));
+
+      nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx,
                                                         jsobj, aIID, aResult);
       if (NS_FAILED(rv))
         return rv;
 
       // We successfully created a wrapper.  We will own this wrapper for as long as the binding remains
       // alive.  At the time the binding is cleared out of the bindingManager, we will remove the wrapper
       // from the bindingManager as well.
       nsISupports* supp = static_cast<nsISupports*>(*aResult);
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -981,16 +981,21 @@ XPCConvert::JSObject2NativeInterface(voi
         // Note that if we have a non-null aOuter then it means that we are
         // forcing the creation of a wrapper even if the object *is* a
         // wrappedNative or other wise has 'nsISupportness'.
         // This allows wrapJSAggregatedToNative to work.
 
         // If we're looking at a security wrapper, see now if we're allowed to
         // pass it to C++. If we are, then fall through to the code below. If
         // we aren't, throw an exception eagerly.
+        //
+        // NB: It's very important that we _don't_ unwrap in the aOuter case,
+        // because the caller may explicitly want to create the XPCWrappedJS
+        // around a security wrapper. XBL does this with Xrays from the XBL
+        // scope - see nsBindingManager::GetBindingImplementation.
         JSObject* inner = js::CheckedUnwrap(src, /* stopAtOuter = */ false);
 
         // Hack - For historical reasons, wrapped chrome JS objects have been
         // passable as native interfaces. We'd like to fix this, but it
         // involves fixing the contacts API and PeerConnection to stop using
         // COWs. This needs to happen, but for now just preserve the old
         // behavior.
         if (!inner && MOZ_UNLIKELY(xpc::WrapperFactory::IsCOW(src)))
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1699,16 +1699,22 @@ bool
 Btoa(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!argc)
         return true;
 
     return xpc::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
 }
 
+bool
+IsXrayWrapper(JSObject *obj)
+{
+    return WrapperFactory::IsXrayWrapper(obj);
+}
+
 } // namespace xpc
 
 namespace mozilla {
 namespace dom {
 
 bool
 IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
 {
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -54,16 +54,19 @@ GetXBLScope(JSContext *cx, JSObject *con
 bool
 AllowXBLScope(JSCompartment *c);
 
 bool
 IsSandboxPrototypeProxy(JSObject *obj);
 
 bool
 IsReflector(JSObject *obj);
+
+bool
+IsXrayWrapper(JSObject *obj);
 } /* namespace xpc */
 
 namespace JS {
 
 struct RuntimeStats;
 
 }