Bug 958324 - Remove same-compartment security wrappers for WNs. r=peterv,r=mrbkap

We've fixed Components, and SOWs are new-binding only. Youpie!
This commit is contained in:
Bobby Holley 2014-01-21 08:26:40 -08:00
parent 06f47384db
commit 44cd3fcb36
6 changed files with 8 additions and 202 deletions

View File

@ -28,15 +28,6 @@ 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)
@ -362,8 +353,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
RootedObject parent(cx, Scope->GetGlobalJSObject());
RootedValue newParentVal(cx, NullValue());
bool needsSOW = false;
bool needsCOW = false;
mozilla::Maybe<JSAutoCompartment> ac;
@ -376,9 +365,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
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),
@ -416,15 +402,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
}
} 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);
@ -473,11 +450,6 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
return rv;
}
if (needsSOW)
wrapper->SetNeedsSOW();
if (needsCOW)
wrapper->SetNeedsCOW();
return FinishCreate(Scope, Interface, cache, wrapper, resultWrapper);
}
@ -667,21 +639,6 @@ XPCWrappedNative::Destroy()
}
}
/*
* 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;
}
@ -1226,15 +1183,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
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();
@ -1271,20 +1219,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
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);
@ -1309,11 +1247,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
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;
@ -1673,47 +1606,6 @@ XPCWrappedNative::InitTearOffJSObject(XPCWrappedNativeTearOff* to)
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)

View File

@ -1029,26 +1029,6 @@ static inline bool IS_PROTO_CLASS(const js::Class *clazz)
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.
@ -2189,7 +2169,6 @@ public:
GetProto()->TraceSelf(trc);
else
GetScope()->TraceSelf(trc);
TraceWrapper(trc);
if (mFlatJSObject && JS_IsGlobalObject(mFlatJSObject))
{
TraceXPCGlobal(trc, mFlatJSObject);
@ -2232,41 +2211,6 @@ public:
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.
@ -2289,10 +2233,6 @@ protected:
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)
};
@ -2326,7 +2266,6 @@ private:
JS::TenuredHeap<JSObject*> mFlatJSObject;
XPCNativeScriptableInfo* mScriptableInfo;
XPCWrappedNativeTearOffChunk mFirstChunk;
JS::TenuredHeap<JSObject*> mWrapper;
};
/***************************************************************************

View File

@ -119,9 +119,6 @@ struct RuntimeStats;
#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)
{
@ -129,8 +126,8 @@ xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, JS::MutableHand
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;
}

View File

@ -263,12 +263,7 @@ 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 };

View File

@ -494,22 +494,9 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, HandleObject objArg)
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

View File

@ -600,10 +600,6 @@
/* 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