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;