Bug 958324 - Remove same-compartment security wrappers for WNs. r=peterv,r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Tue, 21 Jan 2014 08:26:40 -0800
changeset 181477 a8587cf48bb369cb1b8ca1cfabecc32304347b5d
parent 181476 960d29ff5ab0889dab79e4d247af531c046a8aa7
child 181478 05d4d9b9807c12a4ed79d0a53121b11b70c267a7
push id462
push userraliiev@mozilla.com
push dateTue, 22 Apr 2014 00:22:30 +0000
treeherdermozilla-release@ac5db8c74ac0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, mrbkap
bugs958324
milestone29.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 958324 - Remove same-compartment security wrappers for WNs. r=peterv,r=mrbkap We've fixed Components, and SOWs are new-binding only. Youpie!
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
xpcom/base/ErrorList.h
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -23,25 +23,16 @@
 #include "mozilla/dom/BindingUtils.h"
 #include <algorithm>
 
 using namespace xpc;
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace JS;
 
-bool
-xpc_OkToHandOutWrapper(nsWrapperCache *cache)
-{
-    MOZ_ASSERT(cache->GetWrapper(), "Must have wrapper");
-    MOZ_ASSERT(IS_WN_REFLECTOR(cache->GetWrapper()),
-               "Must have XPCWrappedNative wrapper");
-    return !XPCWrappedNative::Get(cache->GetWrapper())->NeedsSOW();
-}
-
 /***************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
 
 // No need to unlink the JS objects: if the XPCWrappedNative is cycle
 // collected then its mFlatJSObject will be cycle collected too and
 // finalization of the mFlatJSObject will unlink the JS objects (see
 // XPC_WN_NoHelper_Finalize and FlatJSObjectFinalized).
@@ -357,33 +348,28 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     // itself.
     const XPCNativeScriptableCreateInfo& sciWrapper =
         isClassInfo ? sci :
         GatherScriptableCreateInfo(identity, info, sciProto, sci);
 
     RootedObject parent(cx, Scope->GetGlobalJSObject());
 
     RootedValue newParentVal(cx, NullValue());
-    bool needsSOW = false;
-    bool needsCOW = false;
 
     mozilla::Maybe<JSAutoCompartment> ac;
 
     if (sciWrapper.GetFlags().WantPreCreate()) {
         // PreCreate may touch dead compartments.
         js::AutoMaybeTouchDeadZones agc(parent);
 
         RootedObject plannedParent(cx, parent);
         nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, cx,
                                                           parent, parent.address());
         if (NS_FAILED(rv))
             return rv;
-
-        if (rv == NS_SUCCESS_CHROME_ACCESS_ONLY)
-            needsSOW = true;
         rv = NS_OK;
 
         MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
                    "Xray wrapper being used to parent XPCWrappedNative?");
 
         ac.construct(static_cast<JSContext*>(cx), parent);
 
         if (parent != plannedParent) {
@@ -411,25 +397,16 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
                 MOZ_ASSERT(NS_FAILED(rv), "returning NS_OK on failure");
                 return rv;
             }
             *resultWrapper = wrapper.forget().get();
             return NS_OK;
         }
     } else {
         ac.construct(static_cast<JSContext*>(cx), parent);
-
-        nsISupports *Object = helper.Object();
-        if (nsXPCWrappedJSClass::IsWrappedJS(Object)) {
-            nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
-            if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrappedjs->GetJSObject())) &&
-                !xpc::AccessCheck::isChrome(js::GetObjectCompartment(Scope->GetGlobalJSObject()))) {
-                needsCOW = true;
-            }
-        }
     }
 
     AutoMarkingWrappedNativeProtoPtr proto(cx);
 
     // If there is ClassInfo (and we are not building a wrapper for the
     // nsIClassInfo interface) then we use a wrapper that needs a prototype.
 
     // Note that the security check happens inside FindTearOff - after the
@@ -468,21 +445,16 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     if (!wrapper->Init(parent, &sciWrapper))
         return NS_ERROR_FAILURE;
 
     if (!wrapper->FindTearOff(Interface, false, &rv)) {
         MOZ_ASSERT(NS_FAILED(rv), "returning NS_OK on failure");
         return rv;
     }
 
-    if (needsSOW)
-        wrapper->SetNeedsSOW();
-    if (needsCOW)
-        wrapper->SetNeedsCOW();
-
     return FinishCreate(Scope, Interface, cache, wrapper, resultWrapper);
 }
 
 static nsresult
 FinishCreate(XPCWrappedNativeScope* Scope,
              XPCNativeInterface* Interface,
              nsWrapperCache *cache,
              XPCWrappedNative* inWrapper,
@@ -662,31 +634,16 @@ XPCWrappedNative::Destroy()
         if (rt && rt->GetDoingFinalization()) {
             nsContentUtils::DeferredFinalize(mIdentity);
             mIdentity = nullptr;
         } else {
             NS_RELEASE(mIdentity);
         }
     }
 
-    /*
-     * The only time GetRuntime() will be nullptr is if Destroy is called a
-     * second time on a wrapped native. Since we already unregistered the
-     * pointer the first time, there's no need to unregister again.
-     * Unregistration is safe the first time because mWrapper isn't used
-     * afterwards.
-     */
-    if (XPCJSRuntime *rt = GetRuntime()) {
-        if (IsIncrementalBarrierNeeded(rt->Runtime()))
-            IncrementalObjectBarrier(GetWrapperPreserveColor());
-        mWrapper.setToCrashOnTouch();
-    } else {
-        MOZ_ASSERT(mWrapper.isSetToCrashOnTouch());
-    }
-
     mMaybeScope = nullptr;
 }
 
 void
 XPCWrappedNative::UpdateScriptableInfo(XPCNativeScriptableInfo *si)
 {
     MOZ_ASSERT(mScriptableInfo, "UpdateScriptableInfo expects an existing scriptable info");
 
@@ -1221,25 +1178,16 @@ XPCWrappedNative::ReparentWrapperIfFound
             // the private of |flat|.
             //
             // NB: It's important to do this _after_ copying the properties to
             // propertyHolder. Otherwise, an object with |foo.x === foo| will
             // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
             JS_SetPrivate(flat, nullptr);
         }
 
-        // Before proceeding, eagerly create any same-compartment security wrappers
-        // that the object might have. This forces us to take the 'WithWrapper' path
-        // while transplanting that handles this stuff correctly.
-        {
-            JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject());
-            if (!wrapper->GetSameCompartmentSecurityWrapper(cx))
-                return NS_ERROR_FAILURE;
-        }
-
         // Update scope maps. This section modifies global state, so from
         // here on out we crash if anything fails.
         Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
         Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
 
         oldMap->Remove(wrapper);
 
         if (wrapper->HasProto())
@@ -1266,30 +1214,20 @@ XPCWrappedNative::ReparentWrapperIfFound
 
         // Crash if the wrapper is already in the new scope.
         if (newMap->Find(wrapper->GetIdentityObject()))
             MOZ_CRASH();
 
         if (!newMap->Add(wrapper))
             MOZ_CRASH();
 
-        RootedObject ww(cx, wrapper->GetWrapper());
-        if (ww) {
-            RootedObject newwrapper(cx);
-            MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper");
-
-            // Oops. We don't support transplanting objects with SOWs anymore.
+        flat = xpc::TransplantObject(cx, flat, newobj);
+        if (!flat)
             MOZ_CRASH();
 
-        } else {
-            flat = xpc::TransplantObject(cx, flat, newobj);
-            if (!flat)
-                MOZ_CRASH();
-        }
-
         MOZ_ASSERT(flat);
         wrapper->mFlatJSObject = flat;
         wrapper->mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
 
         if (cache) {
             bool preserving = cache->PreservingWrapper();
             cache->SetPreservingWrapper(false);
             cache->SetWrapper(flat);
@@ -1304,21 +1242,16 @@ XPCWrappedNative::ReparentWrapperIfFound
             (void) si->GetCallback()->PostTransplant(wrapper, cx, flat);
     }
 
     // Now we can just fix up the parent and return the wrapper
 
     if (aNewParent) {
         if (!JS_SetParent(cx, flat, aNewParent))
             MOZ_CRASH();
-
-        JSObject *nw = wrapper->GetWrapper();
-        if (nw && !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) {
-            MOZ_CRASH();
-        }
     }
 
     return NS_OK;
 }
 
 // Orphans are sad little things - If only we could treat them better. :-(
 //
 // When a wrapper gets reparented to another scope (for example, when calling
@@ -1668,57 +1601,16 @@ XPCWrappedNative::InitTearOffJSObject(XP
     if (!obj)
         return false;
 
     JS_SetPrivate(obj, to);
     to->SetJSObject(obj);
     return true;
 }
 
-JSObject*
-XPCWrappedNative::GetSameCompartmentSecurityWrapper(JSContext *cx)
-{
-    // Grab the current state of affairs.
-    RootedObject flat(cx, GetFlatJSObject());
-    RootedObject wrapper(cx, GetWrapper());
-
-    // If we already have a wrapper, it must be what we want.
-    if (wrapper)
-        return wrapper;
-
-    // Chrome callers don't need same-compartment security wrappers.
-    JSCompartment *cxCompartment = js::GetContextCompartment(cx);
-    MOZ_ASSERT(cxCompartment == js::GetObjectCompartment(flat));
-    if (xpc::AccessCheck::isChrome(cxCompartment)) {
-        MOZ_ASSERT(wrapper == nullptr);
-        return flat;
-    }
-
-    // Check the possibilities. Note that we need to check for null in each
-    // case in order to distinguish between the 'no need for wrapper' and
-    // 'wrapping failed' cases.
-    //
-    // NB: We don't make SOWs for remote XUL domains where XBL scopes are
-    // disallowed.
-    if (NeedsSOW() && xpc::AllowXBLScope(js::GetContextCompartment(cx))) {
-        wrapper = xpc::WrapperFactory::WrapSOWObject(cx, flat);
-        if (!wrapper)
-            return nullptr;
-    }
-
-    // If we made a wrapper, cache it and return it.
-    if (wrapper) {
-        SetWrapper(wrapper);
-        return wrapper;
-    }
-
-    // Otherwise, just return the bare JS reflection.
-    return flat;
-}
-
 /***************************************************************************/
 
 static bool Throw(nsresult errNum, XPCCallContext& ccx)
 {
     XPCThrower::Throw(errNum, ccx);
     return false;
 }
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1025,36 +1025,16 @@ static inline bool IS_PROTO_CLASS(const 
 {
     return clazz == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
            clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass ||
            clazz == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
            clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
 }
 
 /***************************************************************************/
-
-namespace XPCWrapper {
-
-enum WrapperType {
-    UNKNOWN         = 0,
-    NONE            = 0,
-    XPCNW_IMPLICIT  = 1 << 0,
-    XPCNW_EXPLICIT  = 1 << 1,
-    XPCNW           = (XPCNW_IMPLICIT | XPCNW_EXPLICIT),
-    SJOW            = 1 << 2,
-    // SJOW must be the last wrapper type that can be returned to chrome.
-
-    XOW             = 1 << 3,
-    COW             = 1 << 4,
-    SOW             = 1 << 5
-};
-
-}
-
-/***************************************************************************/
 // XPCWrappedNativeScope is one-to-one with a JS global object.
 
 class nsXPCComponentsBase;
 class XPCWrappedNativeScope : public PRCList
 {
 public:
 
     static XPCWrappedNativeScope*
@@ -2184,17 +2164,16 @@ public:
             mSet->Mark();
             if (mScriptableInfo)
                 mScriptableInfo->Mark();
         }
         if (HasProto())
             GetProto()->TraceSelf(trc);
         else
             GetScope()->TraceSelf(trc);
-        TraceWrapper(trc);
         if (mFlatJSObject && JS_IsGlobalObject(mFlatJSObject))
         {
             TraceXPCGlobal(trc, mFlatJSObject);
         }
     }
 
     void TraceJS(JSTracer *trc) {
         TraceInside(trc);
@@ -2227,51 +2206,16 @@ public:
     // Returns a string that shuld be free'd using JS_smprintf_free (or null).
     char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;
 
     static void GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
                                                 XPCNativeScriptableCreateInfo& sciProto);
 
     bool HasExternalReference() const {return mRefCnt > 1;}
 
-    bool NeedsSOW() { return mWrapper.hasFlag(WRAPPER_NEEDS_SOW); }
-    void SetNeedsSOW() { mWrapper.setFlags(WRAPPER_NEEDS_SOW); }
-    bool NeedsCOW() { return mWrapper.hasFlag(WRAPPER_NEEDS_COW); }
-    void SetNeedsCOW() { mWrapper.setFlags(WRAPPER_NEEDS_COW); }
-
-    JSObject* GetWrapperPreserveColor() const { return mWrapper.getPtr(); }
-
-    JSObject* GetWrapper()
-    {
-        JSObject* wrapper = GetWrapperPreserveColor();
-        if (wrapper) {
-            JS::ExposeObjectToActiveJS(wrapper);
-            // Call this to unmark mFlatJSObject.
-            GetFlatJSObject();
-        }
-        return wrapper;
-    }
-    void SetWrapper(JSObject *obj)
-    {
-        JS::IncrementalObjectBarrier(GetWrapperPreserveColor());
-        mWrapper.setPtr(obj);
-    }
-
-    void TraceWrapper(JSTracer *trc)
-    {
-        JS_CallTenuredObjectTracer(trc, &mWrapper, "XPCWrappedNative::mWrapper");
-    }
-
-    // Returns the relevant same-compartment security if applicable, or
-    // mFlatJSObject otherwise.
-    //
-    // This takes care of checking mWrapper to see if we already have such
-    // a wrapper.
-    JSObject *GetSameCompartmentSecurityWrapper(JSContext *cx);
-
     void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
 
     // Make ctor and dtor protected (rather than private) to placate nsCOMPtr.
 protected:
     XPCWrappedNative(); // not implemented
 
     // This ctor is used if this object will have a proto.
     XPCWrappedNative(already_AddRefed<nsISupports> aIdentity,
@@ -2284,20 +2228,16 @@ protected:
 
     virtual ~XPCWrappedNative();
     void Destroy();
 
     void UpdateScriptableInfo(XPCNativeScriptableInfo *si);
 
 private:
     enum {
-        // Flags bits for mWrapper:
-        WRAPPER_NEEDS_SOW = JS_BIT(0),
-        WRAPPER_NEEDS_COW = JS_BIT(1),
-
         // Flags bits for mFlatJSObject:
         FLAT_JS_OBJECT_VALID = JS_BIT(0)
     };
 
 private:
 
     bool Init(JS::HandleObject parent, const XPCNativeScriptableCreateInfo* sci);
     bool FinishInit();
@@ -2321,17 +2261,16 @@ private:
     {
         XPCWrappedNativeScope*   mMaybeScope;
         XPCWrappedNativeProto*   mMaybeProto;
     };
     XPCNativeSet*                mSet;
     JS::TenuredHeap<JSObject*>   mFlatJSObject;
     XPCNativeScriptableInfo*     mScriptableInfo;
     XPCWrappedNativeTearOffChunk mFirstChunk;
-    JS::TenuredHeap<JSObject*>   mWrapper;
 };
 
 /***************************************************************************
 ****************************************************************************
 *
 * Core classes for wrapped JSObject for use from native code...
 *
 ****************************************************************************
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -114,28 +114,25 @@ struct RuntimeStats;
     JSCLASS_DOM_GLOBAL | JSCLASS_HAS_PRIVATE |                                \
     JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS |            \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS + n)
 
 #define XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET (JSCLASS_GLOBAL_SLOT_COUNT + DOM_GLOBAL_SLOTS)
 
 #define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0)
 
-extern bool
-xpc_OkToHandOutWrapper(nsWrapperCache *cache);
-
 inline JSObject*
 xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, JS::MutableHandleValue vp)
 {
     if (cache) {
         JSObject* wrapper = cache->GetWrapper();
         if (wrapper &&
             js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) &&
-            (cache->IsDOMBinding() ? !cache->HasSystemOnlyWrapper() :
-                                     xpc_OkToHandOutWrapper(cache))) {
+            !(cache->IsDOMBinding() && cache->HasSystemOnlyWrapper()))
+        {
             vp.setObject(*wrapper);
             return wrapper;
         }
     }
 
     return nullptr;
 }
 
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -258,22 +258,17 @@ AccessCheck::isCrossOriginAccessPermitte
 }
 
 bool
 AccessCheck::needsSystemOnlyWrapper(JSObject *obj)
 {
     JSObject* wrapper = obj;
     if (dom::GetSameCompartmentWrapperForDOMBinding(wrapper))
         return wrapper != obj;
-
-    if (!IS_WN_REFLECTOR(obj))
-        return false;
-
-    XPCWrappedNative *wn = XPCWrappedNative::Get(obj);
-    return wn->NeedsSOW();
+    return false;
 }
 
 enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };
 
 static void
 EnterAndThrow(JSContext *cx, JSObject *wrapper, const char *msg)
 {
     JSAutoCompartment ac(cx, wrapper);
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -489,32 +489,19 @@ WrapperFactory::WrapForSameCompartment(J
     // be a security wrapper. These checks implicitly handle the security
     // wrapper case.
 
     // Outerize if necessary. This, in combination with the check in
     // PrepareForUnwrapping, means that calling JS_Wrap* always outerizes.
     obj = JS_ObjectToOuterObject(cx, obj);
     NS_ENSURE_TRUE(obj, nullptr);
 
-    if (dom::GetSameCompartmentWrapperForDOMBinding(*obj.address())) {
-        return obj;
-    }
-
-    MOZ_ASSERT(!dom::IsDOMObject(obj));
-
-    if (!IS_WN_REFLECTOR(obj))
-        return obj;
-
-    // Extract the WN. It should exist.
-    XPCWrappedNative *wn = XPCWrappedNative::Get(obj);
-    MOZ_ASSERT(wn, "Trying to wrap a dead WN!");
-
-    // The WN knows what to do.
-    RootedObject wrapper(cx, wn->GetSameCompartmentSecurityWrapper(cx));
-    return wrapper;
+    // The method below is a no-op for non-DOM objects.
+    dom::GetSameCompartmentWrapperForDOMBinding(*obj.address());
+    return obj;
 }
 
 // Call WaiveXrayAndWrap when you have a JS object that you don't want to be
 // wrapped in an Xray wrapper. cx->compartment is the compartment that will be
 // using the returned object. If the object to be wrapped is already in the
 // correct compartment, then this returns the unwrapped object.
 bool
 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleValue vp)
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -595,20 +595,16 @@
   ERROR(NS_ERROR_XPC_BAD_INITIALIZER_NAME,             FAILURE(50)),
   ERROR(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN,                FAILURE(51)),
   ERROR(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN,           FAILURE(52)),
   ERROR(NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL,   FAILURE(53)),
   ERROR(NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE,         FAILURE(54)),
   /* any new errors here should have an associated entry added in xpc.msg */
 
   ERROR(NS_SUCCESS_I_DID_SOMETHING,      SUCCESS(1)),
-  /* Classes that want to only be touched by chrome (or from code whose
-   * filename begins with chrome://global/) shoudl return this from their
-   * scriptable helper's PreCreate hook. */
-  ERROR(NS_SUCCESS_CHROME_ACCESS_ONLY,   SUCCESS(2)),
 #undef MODULE
 
 
   /* ======================================================================= */
   /* 19: NS_ERROR_MODULE_PROFILE */
   /* ======================================================================= */
 #define MODULE NS_ERROR_MODULE_PROFILE
   ERROR(NS_ERROR_LAUNCHED_CHILD_PROCESS,  FAILURE(200)),