From f66e09e47d8372b9555ca653e92af3d04fe7de4a Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 7 Sep 2012 09:15:34 +0100 Subject: [PATCH] Backout 5853df66d488, e8fadd906232, d787279d282c, 8c1ed6327355, 94cfcf5da7c8, 87aa103d7e87 (bug 585922) for failures in test_bug411236.html --- dom/base/nsDOMClassInfo.cpp | 2 +- js/xpconnect/src/XPCWrapper.cpp | 5 +- js/xpconnect/src/xpcprivate.h | 22 ++---- js/xpconnect/wrappers/AccessCheck.cpp | 82 +++++++++++++--------- js/xpconnect/wrappers/AccessCheck.h | 2 - js/xpconnect/wrappers/FilteringWrapper.cpp | 12 ++-- js/xpconnect/wrappers/WrapperFactory.cpp | 2 - js/xpconnect/wrappers/WrapperFactory.h | 7 +- js/xpconnect/wrappers/XrayWrapper.cpp | 42 ++++++++--- layout/base/tests/bug585922-ref.html | 5 +- layout/base/tests/bug585922.html | 6 +- 11 files changed, 113 insertions(+), 74 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 55244755f1b2..d57d9522dc99 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -2176,7 +2176,7 @@ bool nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj) { return xpc::WrapperFactory::IsXrayWrapper(obj) && - xpc::AccessCheck::isChrome(obj); + !xpc::WrapperFactory::IsPartiallyTransparent(obj); } nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData) diff --git a/js/xpconnect/src/XPCWrapper.cpp b/js/xpconnect/src/XPCWrapper.cpp index 0004fa2ca31b..8e68ab031072 100644 --- a/js/xpconnect/src/XPCWrapper.cpp +++ b/js/xpconnect/src/XPCWrapper.cpp @@ -7,9 +7,7 @@ #include "XPCWrapper.h" #include "AccessCheck.h" #include "WrapperFactory.h" -#include "AccessCheck.h" -using namespace xpc; namespace XPCNativeWrapper { static inline @@ -39,7 +37,8 @@ UnwrapNW(JSContext *cx, unsigned argc, jsval *vp) return true; } - if (WrapperFactory::IsXrayWrapper(obj) && AccessCheck::isChrome(obj)) { + if (xpc::WrapperFactory::IsXrayWrapper(obj) && + !xpc::WrapperFactory::IsPartiallyTransparent(obj)) { return JS_GetProperty(cx, obj, "wrappedJSObject", vp); } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index fd554fc35640..beb41d51757e 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -4380,21 +4380,16 @@ GetCompartmentPrivate(JSObject *object) return GetCompartmentPrivate(compartment); } -inline bool IsUniversalXPConnectEnabled(JSCompartment *compartment) -{ - CompartmentPrivate *priv = - static_cast(JS_GetCompartmentPrivate(compartment)); - if (!priv) - return false; - return priv->universalXPConnectEnabled; -} - inline bool IsUniversalXPConnectEnabled(JSContext *cx) { JSCompartment *compartment = js::GetContextCompartment(cx); if (!compartment) return false; - return IsUniversalXPConnectEnabled(compartment); + CompartmentPrivate *priv = + static_cast(JS_GetCompartmentPrivate(compartment)); + if (!priv) + return false; + return priv->universalXPConnectEnabled; } inline void EnableUniversalXPConnect(JSContext *cx) @@ -4407,13 +4402,6 @@ inline void EnableUniversalXPConnect(JSContext *cx) if (!priv) return; priv->universalXPConnectEnabled = true; - - // Recompute all the cross-compartment wrappers leaving the newly-privileged - // compartment. - mozilla::DebugOnly rv; - rv = js::RecomputeWrappers(cx, js::SingleCompartment(compartment), - js::AllCompartments()); - MOZ_ASSERT(rv); } } diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index 41ca1b516665..6ee0b7e851ce 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -52,16 +52,6 @@ AccessCheck::subsumes(JSCompartment *a, JSCompartment *b) return subsumes; } -// Does the compartment of the wrapper subsumes the compartment of the wrappee? -bool -AccessCheck::wrapperSubsumes(JSObject *wrapper) -{ - MOZ_ASSERT(js::IsWrapper(wrapper)); - JSObject *wrapped = js::UnwrapObject(wrapper); - return AccessCheck::subsumes(js::GetObjectCompartment(wrapper), - js::GetObjectCompartment(wrapped)); -} - bool AccessCheck::isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper) { @@ -101,12 +91,6 @@ AccessCheck::isChrome(JSCompartment *compartment) return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged; } -bool -AccessCheck::isChrome(JSObject *obj) -{ - return isChrome(js::GetObjectCompartment(obj)); -} - bool AccessCheck::callerIsChrome() { @@ -221,7 +205,7 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapper, jsid // PUNCTURE Is always denied for cross-origin access. if (act == Wrapper::PUNCTURE) { - return false; + return nsContentUtils::CallerHasUniversalXPConnect(); } const char *name; @@ -286,7 +270,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx) return true; } - return false; + return NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged; } bool @@ -311,7 +295,18 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper) if (flags & WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG) { if (flags & WrapperFactory::SOW_FLAG) return !isSystemOnlyAccessPermitted(cx); - return true; + + if (flags & WrapperFactory::PARTIALLY_TRANSPARENT) + return !XrayUtils::IsTransparent(cx, wrapper); + + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (!ssm) + return true; + + // Bypass script-only status if UniversalXPConnect is enabled. + bool privileged; + return !NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) || + !privileged; } // In addition, chrome objects can explicitly opt-in by setting .scriptOnly to true. @@ -361,6 +356,33 @@ Deny(JSContext *cx, jsid id, Wrapper::Action act) return false; } +bool +PermitIfUniversalXPConnect(JSContext *cx, jsid id, Wrapper::Action act, + ExposedPropertiesOnly::Permission &perm) +{ + // If UniversalXPConnect is enabled, allow access even if __exposedProps__ doesn't + // exists. + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (!ssm) { + return false; + } + + // Double-check that the subject principal according to CAPS is a content + // principal rather than the system principal. If it isn't, this check is + // meaningless. + NS_ASSERTION(!AccessCheck::callerIsChrome(), "About to do a meaningless security check!"); + + bool privileged; + if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && + privileged) { + perm = ExposedPropertiesOnly::PermitPropertyAccess; + return true; // Allow + } + + // Deny + return Deny(cx, id, act); +} + static bool IsInSandbox(JSContext *cx, JSObject *obj) { @@ -382,12 +404,12 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: perm = DenyAccess; if (act == Wrapper::PUNCTURE) - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS); // We need to enter the wrappee's compartment to look at __exposedProps__, - // but we want to be in the wrapper's compartment if we call Deny(). + // but we need to be in the wrapper's compartment to check UniversalXPConnect. // // Unfortunately, |cx| can be in either compartment when we call ::check. :-( JSAutoCompartment ac(cx, wrappedObject); @@ -429,7 +451,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: perm = PermitPropertyAccess; return true; } - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny } if (id == JSID_VOID) { @@ -444,7 +466,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: if (exposedProps.isNullOrUndefined()) { JSAutoCompartment wrapperAC(cx, wrapper); - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny } if (!exposedProps.isObject()) { @@ -463,7 +485,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: } if (desc.obj == NULL || !(desc.attrs & JSPROP_ENUMERATE)) { JSAutoCompartment wrapperAC(cx, wrapper); - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny } if (!JSVAL_IS_STRING(desc.value)) { @@ -509,7 +531,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: if ((act == Wrapper::SET && !(access & WRITE)) || (act != Wrapper::SET && !(access & READ))) { JSAutoCompartment wrapperAC(cx, wrapper); - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny } perm = PermitPropertyAccess; @@ -536,15 +558,7 @@ ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper } } - // We don't have any way to recompute same-compartment Components wrappers, - // so we need this dynamic check. This can go away when we expose Components - // as SpecialPowers.wrap(Components) during automation. - if (xpc::IsUniversalXPConnectEnabled(cx)) { - perm = PermitPropertyAccess; - return true; - } - - return Deny(cx, id, act); + return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny } } diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h index 906d82355906..ff0f51954cf7 100644 --- a/js/xpconnect/wrappers/AccessCheck.h +++ b/js/xpconnect/wrappers/AccessCheck.h @@ -19,9 +19,7 @@ namespace xpc { class AccessCheck { public: static bool subsumes(JSCompartment *a, JSCompartment *b); - static bool wrapperSubsumes(JSObject *wrapper); static bool isChrome(JSCompartment *compartment); - static bool isChrome(JSObject *obj); static bool callerIsChrome(); static nsIPrincipal *getPrincipal(JSCompartment *compartment); static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id, diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index 143fd4eeeb32..bd3544d4ad17 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -125,10 +125,14 @@ template<> SOW SOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | WrapperFactory::SOW_FLAG); template<> SCSOW SCSOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | WrapperFactory::SOW_FLAG); -template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG); -template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG); -template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG); -template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG); +template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | + WrapperFactory::PARTIALLY_TRANSPARENT); +template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | + WrapperFactory::PARTIALLY_TRANSPARENT); +template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | + WrapperFactory::PARTIALLY_TRANSPARENT); +template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | + WrapperFactory::PARTIALLY_TRANSPARENT); template<> LW LW::singleton(WrapperFactory::SHADOWING_FORBIDDEN); template<> XLW XLW::singleton(WrapperFactory::SHADOWING_FORBIDDEN); diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index cf16f76e501a..a6646e485ae8 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -349,8 +349,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO } } } - } else if (xpc::IsUniversalXPConnectEnabled(target)) { - wrapper = &CrossCompartmentWrapper::singleton; } else if (AccessCheck::isChrome(origin)) { JSFunction *fun = JS_GetObjectFunction(obj); if (fun) { diff --git a/js/xpconnect/wrappers/WrapperFactory.h b/js/xpconnect/wrappers/WrapperFactory.h index 6b3334a7b093..588a2582bf31 100644 --- a/js/xpconnect/wrappers/WrapperFactory.h +++ b/js/xpconnect/wrappers/WrapperFactory.h @@ -18,7 +18,8 @@ class WrapperFactory { enum { WAIVE_XRAY_WRAPPER_FLAG = js::Wrapper::LAST_USED_FLAG << 1, IS_XRAY_WRAPPER_FLAG = WAIVE_XRAY_WRAPPER_FLAG << 1, SCRIPT_ACCESS_ONLY_FLAG = IS_XRAY_WRAPPER_FLAG << 1, - SOW_FLAG = SCRIPT_ACCESS_ONLY_FLAG << 1, + PARTIALLY_TRANSPARENT = SCRIPT_ACCESS_ONLY_FLAG << 1, + SOW_FLAG = PARTIALLY_TRANSPARENT << 1, // Prevent scripts from shadowing native properties. // NB: Applies only to Xray wrappers. @@ -37,6 +38,10 @@ class WrapperFactory { return HasWrapperFlag(wrapper, IS_XRAY_WRAPPER_FLAG); } + static bool IsPartiallyTransparent(JSObject *wrapper) { + return HasWrapperFlag(wrapper, PARTIALLY_TRANSPARENT); + } + static bool HasWaiveXrayFlag(JSObject *wrapper) { return HasWrapperFlag(wrapper, WAIVE_XRAY_WRAPPER_FLAG); } diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 362e83a2045c..47185cca48ad 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -910,6 +910,23 @@ nodePrincipal_getter(JSContext *cx, JSHandleObject wrapper, JSHandleId id, JSMut return true; } +static bool +ContentScriptHasUniversalXPConnect() +{ + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (ssm) { + // Double-check that the subject principal according to CAPS is a content + // principal rather than the system principal. If it is, this check is + // meaningless. + NS_ASSERTION(!AccessCheck::callerIsChrome(), "About to do a meaningless security check!"); + + bool privileged; + if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged) + return true; + } + return false; +} + bool XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWrapper, JSObject *wrapper, JSObject *holder, jsid id, @@ -919,12 +936,13 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWra // in the wrapper's compartment here, not the wrappee. MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx)); XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); - if (AccessCheck::isChrome(wrapper) && + if (!WrapperFactory::IsPartiallyTransparent(wrapper) && (((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) || id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) && Is(wrapper)) || (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) && - Is(wrapper)))) { + Is(wrapper))) && + (AccessCheck::callerIsChrome() || ContentScriptHasUniversalXPConnect())) { bool status; Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET; desc->obj = NULL; // default value @@ -1280,7 +1298,16 @@ namespace XrayUtils { bool IsTransparent(JSContext *cx, JSObject *wrapper) { - return WrapperFactory::HasWaiveXrayFlag(wrapper); + if (WrapperFactory::HasWaiveXrayFlag(wrapper)) + return true; + + if (!WrapperFactory::IsPartiallyTransparent(wrapper)) + return false; + + // Redirect access straight to the wrapper if UniversalXPConnect is enabled. + // We don't need to check for system principal here, because only content + // scripts have Partially Transparent wrappers. + return ContentScriptHasUniversalXPConnect(); } JSObject * @@ -1387,11 +1414,10 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrappe if (!holder) return false; - // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes) - // get .wrappedJSObject. We can check this by determining if the compartment - // of the wrapper subsumes that of the wrappee. + // Partially transparent wrappers (which used to be known as XOWs) don't + // have a .wrappedJSObject property. XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); - if (AccessCheck::wrapperSubsumes(wrapper) && + if (!WrapperFactory::IsPartiallyTransparent(wrapper) && id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { bool status; Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET; @@ -1582,7 +1608,7 @@ XrayWrapper::enumerate(JSContext *cx, JSObject *wrapper, unsigned return js::GetPropertyNames(cx, obj, flags, &props); } - if (!AccessCheck::isChrome(wrapper)) { + if (WrapperFactory::IsPartiallyTransparent(wrapper)) { JS_ReportError(cx, "Not allowed to enumerate cross origin objects"); return false; } diff --git a/layout/base/tests/bug585922-ref.html b/layout/base/tests/bug585922-ref.html index 18a9f7726a66..d301f6b7d583 100644 --- a/layout/base/tests/bug585922-ref.html +++ b/layout/base/tests/bug585922-ref.html @@ -7,10 +7,13 @@