Bug 958324 - Remove same-compartment security wrappers for WNs. r=peterv,r=mrbkap
We've fixed Components, and SOWs are new-binding only. Youpie!
--- 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)),