diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index d8cd4a064f9..9e4c1bc8f05 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -46,7 +46,7 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler * object (via UnwrapObjectChecked) will throw. Otherwise, they will succeed. */ void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; } - bool isSafeToUnwrap() { return mSafeToUnwrap; } + virtual bool isSafeToUnwrap() { return mSafeToUnwrap; } static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, Wrapper *handler); diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index a5153a58387..91a3a00311b 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -269,6 +269,19 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper) return false; } +bool +OnlyIfSubjectIsSystem::isSafeToUnwrap() +{ + if (XPCJSRuntime::Get()->XBLScopesEnabled()) + return false; + // It's nasty to use the context stack here, but the alternative is passing cx all + // the way down through UnwrapObjectChecked, which we just undid in a 100k patch. :-( + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + if (!cx) + return true; + return AccessCheck::isSystemOnlyAccessPermitted(cx); +} + enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 }; static bool diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h index dd95e040731..c426a688a93 100644 --- a/js/xpconnect/wrappers/AccessCheck.h +++ b/js/xpconnect/wrappers/AccessCheck.h @@ -50,6 +50,9 @@ struct Opaque : public Policy { { return false; } + static bool isSafeToUnwrap() { + return false; + } }; // This policy only permits access to the object if the subject can touch @@ -67,6 +70,8 @@ struct OnlyIfSubjectIsSystem : public Policy { { return AccessCheck::isSystemOnlyAccessPermitted(cx); } + + static bool isSafeToUnwrap(); }; // This policy only permits access to properties that are safe to be used @@ -82,6 +87,10 @@ struct CrossOriginAccessiblePropertiesOnly : public Policy { { return false; } + + static bool isSafeToUnwrap() { + return false; + } }; // This policy only permits access to properties if they appear in the @@ -94,6 +103,10 @@ struct ExposedPropertiesOnly : public Policy { return act == js::Wrapper::GET; } static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl); + + static bool isSafeToUnwrap() { + return false; + } }; // Components specific policy @@ -106,6 +119,10 @@ struct ComponentsObjectPolicy : public Policy { static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) { return false; } + + static bool isSafeToUnwrap() { + return false; + } }; } diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index d8d06841f92..5ba3b356b2a 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -29,6 +29,13 @@ FilteringWrapper::~FilteringWrapper() { } +template +bool +FilteringWrapper::isSafeToUnwrap() +{ + return Policy::isSafeToUnwrap(); +} + template static bool Filter(JSContext *cx, JSObject *wrapper, AutoIdVector &props) diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index b084da30529..c02fc80bb07 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -19,6 +19,9 @@ class FilteringWrapper : public Base { FilteringWrapper(unsigned flags); virtual ~FilteringWrapper(); + // This is potentially dynamic until XBL scopes are no longer behind a pref. + virtual bool isSafeToUnwrap(); + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE; virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props) MOZ_OVERRIDE; diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 057953ed553..ad5f32d1632 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -284,8 +284,8 @@ DEBUG_CheckUnwrapSafety(JSObject *obj, js::Wrapper *handler, // The Components object that is restricted regardless of origin. MOZ_ASSERT(!handler->isSafeToUnwrap()); } else if (AccessCheck::needsSystemOnlyWrapper(obj)) { - // SOWs are opaque to everyone but Chrome and XBL scopes. - MOZ_ASSERT(handler->isSafeToUnwrap() == nsContentUtils::CanAccessNativeAnon()); + // SOWs have a dynamic unwrap check, so we can't really say anything useful + // about them here :-( } else { // Otherwise, it should depend on whether the target subsumes the origin. MOZ_ASSERT(handler->isSafeToUnwrap() == AccessCheck::subsumes(target, origin)); @@ -499,7 +499,8 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, JSObject *obj) // The WN knows what to do. JSObject *wrapper = wn->GetSameCompartmentSecurityWrapper(cx); - MOZ_ASSERT_IF(wrapper != obj, !Wrapper::wrapperHandler(wrapper)->isSafeToUnwrap()); + MOZ_ASSERT_IF(wrapper != obj && IsComponentsObject(js::UnwrapObject(obj)), + !Wrapper::wrapperHandler(wrapper)->isSafeToUnwrap()); return wrapper; }