diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 658edac1fc4..831f0e82a0f 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -49,6 +49,7 @@ #include "nsJSPrincipals.h" #include "nsWrapperCache.h" #include "WrapperFactory.h" +#include "AccessCheck.h" //#define STRICT_CHECK_OF_UNICODE #ifdef STRICT_CHECK_OF_UNICODE @@ -1383,6 +1384,23 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, flat = locationWrapper; } + else if(wrapper->NeedsSOW() && + !xpc::AccessCheck::isChrome(cx->compartment)) + { + JSObject *sowWrapper = wrapper->GetWrapper(); + if(!sowWrapper) + { + sowWrapper = xpc::WrapperFactory::WrapSOWObject(cx, flat); + if(!sowWrapper) + return JS_FALSE; + + // Cache the sow wrapper to ensure that we maintain + // the identity of this node. + wrapper->SetWrapper(sowWrapper); + } + + flat = sowWrapper; + } else { OBJ_TO_OUTER_OBJECT(cx, flat); diff --git a/js/src/xpconnect/wrappers/AccessCheck.cpp b/js/src/xpconnect/wrappers/AccessCheck.cpp index 46e8b0c6854..b219ae2dc00 100644 --- a/js/src/xpconnect/wrappers/AccessCheck.cpp +++ b/js/src/xpconnect/wrappers/AccessCheck.cpp @@ -329,6 +329,9 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper) // If the wrapper indicates script-only access, we are done. if (flags & WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG) { + if (flags & WrapperFactory::SOW_FLAG) + return !isSystemOnlyAccessPermitted(cx); + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) return true; diff --git a/js/src/xpconnect/wrappers/FilteringWrapper.cpp b/js/src/xpconnect/wrappers/FilteringWrapper.cpp index 1622408d383..c5bed2efa5b 100644 --- a/js/src/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/src/xpconnect/wrappers/FilteringWrapper.cpp @@ -150,6 +150,7 @@ FilteringWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, } #define SOW FilteringWrapper +#define SCSOW FilteringWrapper #define COW FilteringWrapper #define XOW FilteringWrapper, \ CrossOriginAccessiblePropertiesOnly> @@ -159,7 +160,10 @@ FilteringWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, #define XLW FilteringWrapper, \ SameOriginOrCrossOriginAccessiblePropertiesOnly> -template<> SOW SOW::singleton(0); +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<> COW COW::singleton(0); template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | WrapperFactory::PARTIALLY_TRANSPARENT); diff --git a/js/src/xpconnect/wrappers/WrapperFactory.cpp b/js/src/xpconnect/wrappers/WrapperFactory.cpp index 99251519469..52464ed6ee6 100644 --- a/js/src/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp @@ -198,22 +198,16 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO } } } else if (AccessCheck::isChrome(origin)) { - // If an object that needs a system only wrapper crosses into content - // from chrome, we have to wrap it into a system only wrapper on the - // fly. In this case we don't need to restrict to exposed properties - // since only privileged content will be allowed to touch it anyway. + wrapper = &FilteringWrapper::singleton; + } else if (AccessCheck::isSameOrigin(origin, target)) { + // Same origin we use a transparent wrapper, unless the compartment asks + // for an Xray or the wrapper needs a SOW. if (AccessCheck::needsSystemOnlyWrapper(obj)) { wrapper = &FilteringWrapper::singleton; - } else { - wrapper = &FilteringWrapper::singleton; - } - } else if (AccessCheck::isSameOrigin(origin, target)) { - // Same origin we use a transparent wrapper, unless the compartment asks - // for an Xray. - if (static_cast(target->data)->preferXrays && - IS_WN_WRAPPER(obj)) { + } else if (static_cast(target->data)->preferXrays && + IS_WN_WRAPPER(obj)) { typedef XrayWrapper Xray; wrapper = &Xray::singleton; xrayHolder = Xray::createHolder(cx, obj, parent); @@ -223,6 +217,9 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO wrapper = &JSCrossCompartmentWrapper::singleton; } } else { + NS_ASSERTION(!AccessCheck::needsSystemOnlyWrapper(obj), + "bad object exposed across origins"); + // Cross origin we want to disallow scripting and limit access to // a predefined set of properties. XrayWrapper adds a property // (.wrappedJSObject) which allows bypassing the XrayWrapper, but @@ -307,4 +304,14 @@ WrapperFactory::WaiveXrayAndWrap(JSContext *cx, jsval *vp) return JS_WrapValue(cx, vp); } +JSObject * +WrapperFactory::WrapSOWObject(JSContext *cx, JSObject *obj) +{ + JSObject *wrapperObj = + JSWrapper::New(cx, obj, obj->getProto(), NULL, + &FilteringWrapper::singleton); + return wrapperObj; +} + } diff --git a/js/src/xpconnect/wrappers/WrapperFactory.h b/js/src/xpconnect/wrappers/WrapperFactory.h index 275721870be..ceb356f08c3 100644 --- a/js/src/xpconnect/wrappers/WrapperFactory.h +++ b/js/src/xpconnect/wrappers/WrapperFactory.h @@ -47,7 +47,8 @@ class WrapperFactory { enum { WAIVE_XRAY_WRAPPER_FLAG = (1<<0), IS_XRAY_WRAPPER_FLAG = (1<<1), SCRIPT_ACCESS_ONLY_FLAG = (1<<2), - PARTIALLY_TRANSPARENT = (1<<3) }; + PARTIALLY_TRANSPARENT = (1<<3), + SOW_FLAG = (1<<4) }; // Return true if any of any of the nested wrappers have the flag set. static bool HasWrapperFlag(JSObject *wrapper, uintN flag) { @@ -89,6 +90,9 @@ class WrapperFactory { // Wrap wrapped object into a waiver wrapper and then re-wrap it. static bool WaiveXrayAndWrap(JSContext *cx, jsval *vp); + + // Wrap a (same compartment) object in a SOW. + static JSObject *WrapSOWObject(JSContext *cx, JSObject *obj); }; extern JSWrapper WaiveXrayWrapperWrapper;