Bug 1273251: Part 1 - Mark nuked sandboxes as nuked and non-scriptable. r=bholley

MozReview-Commit-ID: tq9nExa1P7

--HG--
extra : rebase_source : 3c0e856335b8585457e2679b30177bd1df9ac6bb
This commit is contained in:
Kris Maglione 2017-01-12 14:47:38 -08:00
parent 71398a8500
commit e51f27d8cb
4 changed files with 29 additions and 3 deletions

View File

@ -3017,11 +3017,17 @@ nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx)
NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
JSObject* wrapper = &obj.toObject();
NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
JSObject* sb = UncheckedUnwrap(wrapper);
RootedObject sb(cx, UncheckedUnwrap(wrapper));
NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
NukeCrossCompartmentWrappers(cx, AllCompartments(),
SingleCompartment(GetObjectCompartment(sb)),
NukeWindowReferences);
// Now mark the compartment as nuked and non-scriptable.
auto compartmentPrivate = xpc::CompartmentPrivate::Get(sb);
compartmentPrivate->wasNuked = true;
compartmentPrivate->scriptability.Block();
return NS_OK;
}

View File

@ -199,6 +199,7 @@ CompartmentPrivate::CompartmentPrivate(JSCompartment* c)
, allowCPOWs(false)
, universalXPConnectEnabled(false)
, forcePermissiveCOWs(false)
, wasNuked(false)
, scriptability(c)
, scope(nullptr)
, mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH))

View File

@ -3183,6 +3183,10 @@ public:
// Using it in production is inherently unsafe.
bool forcePermissiveCOWs;
// True if this compartment has been nuked. If true, any wrappers into or
// out of it should be considered invalid.
bool wasNuked;
// Whether we've emitted a warning about a property that was filtered out
// by a security wrapper. See XrayWrapper.cpp.
bool wrapperDenialWarnings[WrapperDenialTypeCount];

View File

@ -324,7 +324,10 @@ static void
DEBUG_CheckUnwrapSafety(HandleObject obj, const js::Wrapper* handler,
JSCompartment* origin, JSCompartment* target)
{
if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
if (CompartmentPrivate::Get(origin)->wasNuked || CompartmentPrivate::Get(target)->wasNuked) {
// If either compartment has already been nuked, we should have an opaque wrapper.
MOZ_ASSERT(handler->hasSecurityPolicy());
} else if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
// If the caller is chrome (or effectively so), unwrap should always be allowed.
MOZ_ASSERT(!handler->hasSecurityPolicy());
} else if (CompartmentPrivate::Get(origin)->forcePermissiveCOWs) {
@ -443,9 +446,21 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
// First, handle the special cases.
//
// If we've somehow gotten to this point after either the source or target
// compartment has been nuked, return an opaque wrapper to prevent further
// access.
// Ideally, we should return a DeadProxyObject instead of a wrapper in this
// case (bug 1322273).
if (CompartmentPrivate::Get(origin)->wasNuked ||
CompartmentPrivate::Get(target)->wasNuked) {
NS_WARNING("Trying to create a wrapper into or out of a nuked compartment");
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
}
// If UniversalXPConnect is enabled, this is just some dumb mochitest. Use
// a vanilla CCW.
if (xpc::IsUniversalXPConnectEnabled(target)) {
else if (xpc::IsUniversalXPConnectEnabled(target)) {
CrashIfNotInAutomation();
wrapper = &CrossCompartmentWrapper::singleton;
}