Bug 911864 - When QIing objects bound with XBL scopes, route the XPCWrappedJS through an XrayWrapper from the XBL scope. r=smaug
authorBobby Holley <bobbyholley@gmail.com>
Fri, 01 Nov 2013 15:31:57 +0100
changeset 153065 8a56460b9110deccc90e14e79cb56eaaac337d2b
parent 153064 922be1ea7e61a786b3641676d1225af0dd1fd833
child 153066 2662a96f83ef7aa73a4ed44476f86a8a284d8244
push id25566
push userryanvm@gmail.com
push dateFri, 01 Nov 2013 18:40:05 +0000
treeherdermozilla-central@5bb07c1ae9f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs911864
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 911864 - When QIing objects bound with XBL scopes, route the XPCWrappedJS through an XrayWrapper from the XBL scope. r=smaug
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
@@ -37,16 +37,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;
 
@@ -726,26 +728,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.
         //
--- 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;
 
 }