Bug 1029248 - Allow CPOWs to be converted to native interfaces (r=mrbkap)
authorBill McCloskey <wmccloskey@mozilla.com>
Thu, 10 Jul 2014 16:47:26 -0700
changeset 193506 c7df28f9f5458ea436a6acff5eacbc5429c073a2
parent 193505 f8be8f1a923bc543192df7be2a5414e702608c42
child 193507 3db5124bd6c04bd440227f81a78139dad55f3e21
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmrbkap
bugs1029248
milestone33.0a1
Bug 1029248 - Allow CPOWs to be converted to native interfaces (r=mrbkap)
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/xpcprivate.h
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -7,16 +7,17 @@
 /* Class that wraps JS objects to appear as XPCOM objects. */
 
 #include "xpcprivate.h"
 #include "jsprf.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsCxPusher.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
+#include "JavaScriptParent.h"
 
 using namespace mozilla;
 
 // NOTE: much of the fancy footwork is done in xpcstubs.cpp
 
 
 // nsXPCWrappedJS lifetime.
 //
@@ -329,17 +330,19 @@ nsXPCWrappedJS::GetNewOrUsed(JS::HandleO
     AutoJSContext cx;
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
     if (!map) {
         MOZ_ASSERT(map,"bad map");
         return NS_ERROR_FAILURE;
     }
 
-    nsRefPtr<nsXPCWrappedJSClass> clasp = nsXPCWrappedJSClass::GetNewOrUsed(cx, aIID);
+    bool allowNonScriptable = mozilla::jsipc::IsWrappedCPOW(jsObj);
+    nsRefPtr<nsXPCWrappedJSClass> clasp = nsXPCWrappedJSClass::GetNewOrUsed(cx, aIID,
+                                                                            allowNonScriptable);
     if (!clasp)
         return NS_ERROR_FAILURE;
 
     JS::RootedObject rootJSObj(cx, clasp->GetRootJSObject(cx, jsObj));
     if (!rootJSObj)
         return NS_ERROR_FAILURE;
 
     nsRefPtr<nsXPCWrappedJS> root = map->Find(rootJSObj);
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -8,16 +8,17 @@
 
 #include "xpcprivate.h"
 #include "jsprf.h"
 #include "nsArrayEnumerator.h"
 #include "nsContentUtils.h"
 #include "nsWrapperCache.h"
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
+#include "JavaScriptParent.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
@@ -85,28 +86,28 @@ bool xpc_IsReportableErrorCode(nsresult 
             return false;
         default:
             return true;
     }
 }
 
 // static
 already_AddRefed<nsXPCWrappedJSClass>
-nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID)
+nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID, bool allowNonScriptable)
 {
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
     nsRefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
 
     if (!clasp) {
         nsCOMPtr<nsIInterfaceInfo> info;
         nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
         if (info) {
             bool canScript, isBuiltin;
-            if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
+            if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && (canScript || allowNonScriptable) &&
                 NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
                 nsXPConnect::IsISupportsDescendant(info))
             {
                 clasp = new nsXPCWrappedJSClass(cx, aIID, info);
                 if (!clasp->mDescriptors)
                     clasp = nullptr;
             }
         }
@@ -197,22 +198,24 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 
     // Ensure that we are asking for a scriptable interface.
     // NB:  It's important for security that this check is here rather
     // than later, since it prevents untrusted objects from implementing
     // some interfaces in JS and aggregating a trusted object to
     // implement intentionally (for security) unscriptable interfaces.
     // We so often ask for nsISupports that we can short-circuit the test...
     if (!aIID.Equals(NS_GET_IID(nsISupports))) {
+        bool allowNonScriptable = mozilla::jsipc::IsWrappedCPOW(jsobj);
+
         nsCOMPtr<nsIInterfaceInfo> info;
         nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
         if (!info)
             return nullptr;
         bool canScript, isBuiltin;
-        if (NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
+        if (NS_FAILED(info->IsScriptable(&canScript)) || (!canScript && !allowNonScriptable) ||
             NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
             return nullptr;
     }
 
     id = xpc_NewIDObject(cx, jsobj, aIID);
     if (id) {
         // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
         // is not an exception that is ever worth reporting, but we don't want
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2237,17 +2237,18 @@ class nsXPCWrappedJSClass : public nsIXP
 {
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
     NS_IMETHOD DebugDump(int16_t depth);
 public:
 
     static already_AddRefed<nsXPCWrappedJSClass>
     GetNewOrUsed(JSContext* cx,
-                 REFNSIID aIID);
+                 REFNSIID aIID,
+                 bool allowNonScriptable = false);
 
     REFNSIID GetIID() const {return mIID;}
     XPCJSRuntime* GetRuntime() const {return mRuntime;}
     nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;}
     const char* GetInterfaceName();
 
     static bool IsWrappedJS(nsISupports* aPtr);