diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
index b1e85635cc7..5b0ee27403a 100644
--- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
@@ -244,6 +244,9 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject *
XPC_COW_WrappedObject(JSContext *cx, JSObject *obj);
+static JSBool
+WrapFunction(JSContext *cx, JSObject *scope, JSObject *funobj, jsval *vp);
+
using namespace XPCWrapper;
namespace ChromeObjectWrapper {
@@ -275,6 +278,10 @@ JSExtendedClass COWClass = {
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
{
+ if (JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v))) {
+ return WrapFunction(cx, parent, JSVAL_TO_OBJECT(v), vp);
+ }
+
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
if (!wrapperObj) {
@@ -361,9 +368,9 @@ GetWrappedObject(JSContext *cx, JSObject *wrapper)
// Forward declaration for the function wrapper.
JSBool
-XPC_COW_RewrapForChrome(JSContext *cx, JSObject *wrapperObj, jsval *vp);
+RewrapForChrome(JSContext *cx, JSObject *wrapperObj, jsval *vp);
JSBool
-XPC_COW_RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp);
+RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp);
// This function wrapper calls a function from untrusted content into chrome.
@@ -371,57 +378,51 @@ static JSBool
XPC_COW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
- JSObject *wrappedObj;
-
- // Allow 'this' to be either a COW, in which case we unwrap it or something
- // that isn't a COW. We disallow invalid COWs that have no wrapped object.
-
- wrappedObj = GetWrapper(obj);
- if (wrappedObj) {
- wrappedObj = GetWrappedObject(cx, wrappedObj);
- if (!wrappedObj) {
- return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
- }
- } else {
- wrappedObj = obj;
- }
-
jsval funToCall;
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]),
XPCWrapper::eWrappedFunctionSlot, &funToCall)) {
return JS_FALSE;
}
+ JSObject *scope = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(funToCall));
for (uintN i = 0; i < argc; ++i) {
- if (!XPC_COW_RewrapForChrome(cx, obj, &argv[i])) {
+ if (!JSVAL_IS_PRIMITIVE(argv[i]) &&
+ !RewrapObject(cx, scope, JSVAL_TO_OBJECT(argv[i]), UNKNOWN, &argv[i])) {
return JS_FALSE;
}
}
- if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) {
+ if (!RewrapObject(cx, scope, obj, UNKNOWN, rval) ||
+ !JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(*rval), funToCall, argc, argv,
+ rval)) {
return JS_FALSE;
}
- return XPC_COW_RewrapForContent(cx, obj, rval);
+ return RewrapForContent(cx, obj, rval);
}
-JSBool
-XPC_COW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
- jsval *rval)
+static JSBool
+WrapFunction(JSContext *cx, JSObject *scope, JSObject *funobj, jsval *rval)
{
+ scope = JS_GetGlobalForObject(cx, scope);
jsval funobjVal = OBJECT_TO_JSVAL(funobj);
JSFunction *wrappedFun =
reinterpret_cast(xpc_GetJSPrivate(funobj));
JSNative native = JS_GetFunctionNative(cx, wrappedFun);
- if (!native || native == XPC_COW_FunctionWrapper) {
- *rval = funobjVal;
- return JS_TRUE;
+ if (native == XPC_COW_FunctionWrapper) {
+ if (STOBJ_GET_PARENT(funobj) == scope) {
+ *rval = funobjVal;
+ return JS_TRUE;
+ }
+
+ JS_GetReservedSlot(cx, funobj, XPCWrapper::eWrappedFunctionSlot, &funobjVal);
+ funobj = JSVAL_TO_OBJECT(funobjVal);
}
JSFunction *funWrapper =
JS_NewFunction(cx, XPC_COW_FunctionWrapper,
JS_GetFunctionArity(wrappedFun), 0,
- JS_GetGlobalForObject(cx, outerObj),
+ scope,
JS_GetFunctionName(wrappedFun));
if (!funWrapper) {
return JS_FALSE;
@@ -436,63 +437,32 @@ XPC_COW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
}
JSBool
-XPC_COW_RewrapForChrome(JSContext *cx, JSObject *wrapperObj, jsval *vp)
+RewrapForChrome(JSContext *cx, JSObject *wrapperObj, jsval *vp)
{
jsval v = *vp;
if (JSVAL_IS_PRIMITIVE(v)) {
return JS_TRUE;
}
- // We're rewrapping for chrome, so this is safe.
- JSObject *obj = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v));
- if (!obj) {
- *vp = JSVAL_NULL;
- return JS_TRUE;
- }
-
- XPCWrappedNative *wn;
- JSBool ok;
-
- // Set aside the frame chain so that we'll be able to wrap this object for
- // chrome's use.
- JSStackFrame *fp = JS_SaveFrameChain(cx);
-
- if (IS_WN_WRAPPER(obj) &&
- (wn = (XPCWrappedNative*)xpc_GetJSPrivate(obj)) &&
- !nsXPCWrappedJSClass::IsWrappedJS(wn->Native())) {
- // Return an explicit XPCNativeWrapper in case "chrome" code happens to be
- // XBL code cloned into an untrusted context.
- ok = XPCNativeWrapper::CreateExplicitWrapper(cx, wn, JS_TRUE, vp);
- } else {
- // Note: we're passing the wrapped chrome object as the scope for the SJOW.
- ok = XPCSafeJSObjectWrapper::WrapObject(cx, GetWrappedObject(cx, wrapperObj),
- *vp, vp);
- }
-
- JS_RestoreFrameChain(cx, fp);
-
- return ok;
+ return RewrapObject(cx, JS_GetGlobalForObject(cx, GetWrappedObject(cx, wrapperObj)),
+ JSVAL_TO_OBJECT(v), UNKNOWN, vp);
}
JSBool
-XPC_COW_RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp)
+RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp)
{
jsval v = *vp;
if (JSVAL_IS_PRIMITIVE(v)) {
return JS_TRUE;
}
- JSObject *obj = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v));
- if (!obj) {
- *vp = JSVAL_NULL;
- return JS_TRUE;
+ JSObject *scope = JS_GetScopeChain(cx);
+ if (!scope) {
+ return JS_FALSE;
}
- if (JS_ObjectIsFunction(cx, obj)) {
- return XPC_COW_WrapFunction(cx, wrapperObj, obj, vp);
- }
-
- return WrapObject(cx, JS_GetScopeChain(cx), OBJECT_TO_JSVAL(obj), vp);
+ return RewrapObject(cx, JS_GetGlobalForObject(cx, scope),
+ JSVAL_TO_OBJECT(v), COW, vp);
}
static JSBool
@@ -549,7 +519,7 @@ XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
}
}
- return XPC_COW_RewrapForChrome(cx, obj, vp) &&
+ return RewrapForChrome(cx, obj, vp) &&
JS_DefinePropertyById(cx, wrappedObj, interned_id, *vp,
desc.getter, desc.setter, desc.attrs);
}
@@ -632,7 +602,7 @@ XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx);
}
- if (!XPC_COW_RewrapForChrome(cx, obj, vp)) {
+ if (isSet && !RewrapForChrome(cx, obj, vp)) {
return JS_FALSE;
}
@@ -643,7 +613,7 @@ XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_FALSE;
}
- return XPC_COW_RewrapForContent(cx, obj, vp);
+ return RewrapForContent(cx, obj, vp);
}
static JSBool
@@ -714,7 +684,8 @@ XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx);
}
- return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
+ return XPCWrapper::NewResolve(cx, obj, JS_FALSE, wrappedObj, id, flags,
+ objp);
}
static JSBool
@@ -743,7 +714,7 @@ XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return JS_FALSE;
}
- return XPC_COW_RewrapForContent(cx, obj, vp);
+ return RewrapForContent(cx, obj, vp);
}
static JSBool
diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp
index 4d6bed0253a..d1b74db4be1 100644
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -235,59 +235,33 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval)
// Re-wrap non-primitive values if this is a deep wrapper, i.e.
// if (HAS_FLAGS(flags, FLAG_DEEP).
if (HAS_FLAGS(flags, FLAG_DEEP) && !primitive) {
- // Unwrap a cross origin wrapper, since we're more restrictive.
- if (STOBJ_GET_CLASS(nativeObj) == &XPCCrossOriginWrapper::XOWClass.base) {
- if (!::JS_GetReservedSlot(cx, nativeObj, sWrappedObjSlot,
- &v)) {
- return JS_FALSE;
- }
-
- // If v is primitive, allow nativeObj to remain a cross origin wrapper,
- // which will fail below (since it isn't a wrapped native).
- if (!JSVAL_IS_PRIMITIVE(v)) {
- nativeObj = JSVAL_TO_OBJECT(v);
- }
- }
-
- XPCWrappedNative* wrappedNative =
- XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, nativeObj);
- if (!wrappedNative) {
- return XPCSafeJSObjectWrapper::WrapObject(cx, JS_GetScopeChain(cx),
- v, rval);
- }
-
- if (HAS_FLAGS(flags, FLAG_EXPLICIT)) {
-#ifdef DEBUG_XPCNativeWrapper
- printf("Rewrapping for deep explicit wrapper\n");
-#endif
- if (wrappedNative == XPCNativeWrapper::SafeGetWrappedNative(obj)) {
- // Already wrapped, return the wrapper.
- *rval = OBJECT_TO_JSVAL(obj);
- return JS_TRUE;
- }
-
- // |obj| is an explicit deep wrapper. We want to construct another
- // explicit deep wrapper for |v|.
-
- return XPCNativeWrapper::CreateExplicitWrapper(cx, wrappedNative,
- JS_TRUE, rval);
- }
-
-#ifdef DEBUG_XPCNativeWrapper
- printf("Rewrapping for deep implicit wrapper\n");
-#endif
- // Just using GetNewOrUsed on the return value of
- // GetWrappedNativeOfJSObject will give the right thing -- the unique deep
- // implicit wrapper associated with wrappedNative.
- JSObject* wrapperObj = XPCNativeWrapper::GetNewOrUsed(cx, wrappedNative,
- JS_GetScopeChain(cx),
- nsnull);
- if (!wrapperObj) {
+ JSObject *scope = JS_GetScopeChain(cx);
+ if (!scope) {
return JS_FALSE;
}
- *rval = OBJECT_TO_JSVAL(wrapperObj);
+ WrapperType type = HAS_FLAGS(flags, FLAG_EXPLICIT)
+ ? XPCNW_EXPLICIT : XPCNW_IMPLICIT;
+
+ if (!RewrapObject(cx, JS_GetGlobalForObject(cx, scope),
+ nativeObj, type, rval)) {
+ return JS_FALSE;
+ }
} else {
+ if (!JSVAL_IS_PRIMITIVE(v)) {
+ JSObject *scope = JS_GetScopeChain(cx);
+ if (!scope) {
+ return JS_FALSE;
+ }
+
+ // NB: Because we're not a deep wrapper, we give a hint of SJOW to
+ // imitate not having a wrapper at all.
+ if (!RewrapObject(cx, JS_GetGlobalForObject(cx, scope),
+ JSVAL_TO_OBJECT(v), SJOW, &v)) {
+ return JS_FALSE;
+ }
+ }
+
*rval = v;
}
@@ -460,6 +434,7 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj,
// Otherwise, we're looking at a non-system file with a handle on an
// implicit wrapper. This is a bug! Deny access.
NS_ERROR("Implicit native wrapper in content code");
+ return JS_FALSE;
#else
return JS_TRUE;
#endif
@@ -976,49 +951,49 @@ XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *nativeObj = JSVAL_TO_OBJECT(native);
- // Unwrap a cross origin wrapper, since we're more restrictive than it is.
- JSObject *wrapper;
- if ((wrapper = UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass, nativeObj))) {
- nativeObj = wrapper;
- } else if ((wrapper = UnwrapGeneric(cx, &XPCSafeJSObjectWrapper::SJOWClass, nativeObj))) {
- nativeObj = wrapper;
+ // First, if this is another type of security wrapper, unwrap it to see what
+ // we're really dealing with.
+ nativeObj = UnsafeUnwrapSecurityWrapper(cx, nativeObj);
+ if (!nativeObj) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
+ }
+ native = OBJECT_TO_JSVAL(nativeObj);
+
+ // Now, figure out if we're allowed to create an XPCNativeWrapper around it.
+ JSObject *scope = JS_GetScopeChain(cx);
+ if (!scope) {
+ return JS_FALSE;
}
+ XPCWrappedNativeScope *xpcscope =
+ XPCWrappedNativeScope::FindInJSObjectScope(cx, scope);
+ NS_ASSERTION(xpcscope, "what crazy scope are we in?");
+
XPCWrappedNative *wrappedNative;
+ WrapperType type = xpcscope->GetWrapperFor(cx, nativeObj, XPCNW_EXPLICIT,
+ &wrappedNative);
- if (XPCNativeWrapper::IsNativeWrapper(nativeObj)) {
- // We're asked to wrap an already wrapped object. Re-wrap the
- // object wrapped by the given wrapper.
+ if (type != NONE && !(type & XPCNW_EXPLICIT)) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
+ }
-#ifdef DEBUG_XPCNativeWrapper
- printf("Wrapping already wrapped object\n");
-#endif
-
- // It's always safe to re-wrap an object.
- wrappedNative = XPCNativeWrapper::SafeGetWrappedNative(nativeObj);
-
- if (!wrappedNative) {
- return ThrowException(NS_ERROR_INVALID_ARG, cx);
- }
-
- nativeObj = wrappedNative->GetFlatJSObject();
- native = OBJECT_TO_JSVAL(nativeObj);
- } else {
+ // We might have to morph.
+ if (!wrappedNative) {
wrappedNative =
XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, nativeObj);
if (!wrappedNative) {
return ThrowException(NS_ERROR_INVALID_ARG, cx);
}
+ }
- // Prevent wrapping a double-wrapped JS object in an
- // XPCNativeWrapper!
- nsCOMPtr xpcwrappedjs =
- do_QueryWrappedNative(wrappedNative);
+ // Prevent wrapping a double-wrapped JS object in an
+ // XPCNativeWrapper!
+ nsCOMPtr xpcwrappedjs =
+ do_QueryWrappedNative(wrappedNative);
- if (xpcwrappedjs) {
- return ThrowException(NS_ERROR_INVALID_ARG, cx);
- }
+ if (xpcwrappedjs) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
}
PRBool hasStringArgs = PR_FALSE;
@@ -1057,8 +1032,16 @@ XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
}
}
- return XPCNativeWrapper::CreateExplicitWrapper(cx, wrappedNative,
- !hasStringArgs, rval);
+ if (!XPCNativeWrapper::CreateExplicitWrapper(cx, wrappedNative,
+ !hasStringArgs, rval)) {
+ return JS_FALSE;
+ }
+
+ if (!(type & SOW)) {
+ return JS_TRUE;
+ }
+
+ return SystemOnlyWrapper::MakeSOW(cx, JSVAL_TO_OBJECT(*rval));
}
static void
diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
index 1811ca3684a..cd62bc73d9d 100644
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -94,18 +94,18 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject *
XPC_SJOW_WrappedObject(JSContext *cx, JSObject *obj);
+using namespace XPCSafeJSObjectWrapper;
+using namespace XPCWrapper;
+
static inline
JSBool
ThrowException(nsresult ex, JSContext *cx)
{
- XPCThrower::Throw(ex, cx);
+ DoThrowException(ex, cx);
return JS_FALSE;
}
-using namespace XPCSafeJSObjectWrapper;
-using namespace XPCWrapper;
-
// Find the subject and object principal. The argument
// subjectPrincipal can be null if the caller doesn't care about the
// subject principal, and secMgr can also be null if the caller
@@ -274,8 +274,59 @@ JSExtendedClass SJOWClass = {
JSBool
WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp)
{
- *vp = v;
- return XPC_SJOW_Construct(cx, scope, 1, vp, vp);
+ // This might be redundant if called from XPC_SJOW_Construct, but it should
+ // be cheap in that case.
+ JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(v));
+ if (!objToWrap) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
+ }
+
+ // Prevent script created Script objects from ever being wrapped
+ // with XPCSafeJSObjectWrapper, and never let the eval function
+ // object be directly wrapped.
+
+ if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass ||
+ (JS_ObjectIsFunction(cx, objToWrap) &&
+ JS_GetFunctionFastNative(cx, JS_ValueToFunction(cx, v)) ==
+ XPCWrapper::sEvalNative)) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
+ }
+
+ XPCWrappedNativeScope *xpcscope =
+ XPCWrappedNativeScope::FindInJSObjectScope(cx, scope);
+ NS_ASSERTION(xpcscope, "what crazy scope are we in?");
+
+ XPCWrappedNative *wrappedNative;
+ WrapperType type = xpcscope->GetWrapperFor(cx, objToWrap, SJOW,
+ &wrappedNative);
+
+ // NB: We allow XOW here because we're as restrictive as it is (and we know
+ // we're same origin here).
+ if (type != NONE && type != XOW && !(type & SJOW)) {
+ return ThrowException(NS_ERROR_INVALID_ARG, cx);
+ }
+
+ SLIM_LOG_WILL_MORPH(cx, objToWrap);
+ if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) {
+ return ThrowException(NS_ERROR_FAILURE, cx);
+ }
+
+ JSObject *wrapperObj =
+ JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, scope);
+
+ if (!wrapperObj) {
+ // JS_NewObjectWithGivenProto already threw.
+ return JS_FALSE;
+ }
+
+ *vp = OBJECT_TO_JSVAL(wrapperObj);
+ if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot,
+ OBJECT_TO_JSVAL(objToWrap)) ||
+ !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) {
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
}
PRBool
@@ -347,21 +398,16 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval)
if (JSVAL_IS_PRIMITIVE(val)) {
*rval = val;
} else {
+ if (!RewrapObject(cx, STOBJ_GET_PARENT(obj), JSVAL_TO_OBJECT(val), SJOW,
+ rval)) {
+ return JS_FALSE;
+ }
// Construct a new safe wrapper. Note that it doesn't matter what
// parent we pass in here, the construct hook will ensure we get
// the right parent for the wrapper.
- JSObject *safeObj =
- ::JS_ConstructObjectWithArguments(cx, &SJOWClass.base, nsnull,
- nsnull, 1, &val);
- if (!safeObj) {
- return JS_FALSE;
- }
-
- // Set *rval to safeObj here to ensure it doesn't get collected in
- // any of the code below.
- *rval = OBJECT_TO_JSVAL(safeObj);
-
- if (JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) {
+ JSObject *safeObj = JSVAL_TO_OBJECT(*rval);
+ if (STOBJ_GET_CLASS(safeObj) == &SJOWClass.base &&
+ JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) {
// Check to see if the new object we just wrapped is accessible
// from the unsafe object we got the new object through. If not,
// force the new wrapper to use the principal of the unsafe
@@ -423,21 +469,6 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval)
return ok;
}
-static jsval
-UnwrapJSValue(JSContext *cx, jsval val)
-{
- if (JSVAL_IS_PRIMITIVE(val)) {
- return val;
- }
-
- JSObject *unsafeObj = GetUnsafeObject(cx, JSVAL_TO_OBJECT(val));
- if (unsafeObj) {
- return OBJECT_TO_JSVAL(unsafeObj);
- }
-
- return val;
-}
-
static JSBool
XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
@@ -470,6 +501,16 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_FALSE;
}
+ if (!JSVAL_IS_PRIMITIVE(*vp)) {
+ // Adding an object of some type to the content object, make sure it's
+ // properly wrapped.
+ JSObject *added = JSVAL_TO_OBJECT(*vp);
+ if (!RewrapObject(cx, JS_GetGlobalForObject(cx, unsafeObj), added,
+ UNKNOWN, vp)) {
+ return JS_FALSE;
+ }
+ }
+
return XPCWrapper::AddProperty(cx, obj, JS_FALSE, unsafeObj, id, vp);
}
@@ -571,8 +612,11 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_FALSE;
}
- if (aIsSet) {
- *vp = UnwrapJSValue(cx, *vp);
+ if (aIsSet &&
+ !JSVAL_IS_PRIMITIVE(*vp) &&
+ !RewrapObject(cx, JS_GetGlobalForObject(cx, unsafeObj),
+ JSVAL_TO_OBJECT(*vp), UNKNOWN, vp)) {
+ return JS_FALSE;
}
JSBool ok = aIsSet
@@ -657,7 +701,8 @@ XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
XPC_SJOW_toString, 0, 0) != nsnull;
}
- return XPCWrapper::NewResolve(cx, obj, JS_FALSE, unsafeObj, id, flags, objp);
+ return XPCWrapper::NewResolve(cx, obj, JS_FALSE, unsafeObj, id, flags,
+ objp);
}
static JSBool
@@ -778,11 +823,21 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
{
SafeCallGuard guard(cx, FindObjectPrincipals(cx, safeObj, funToCall));
+ JSObject *scope = JS_GetGlobalForObject(cx, funToCall);
for (uintN i = 0; i < argc; ++i) {
- argv[i] = UnwrapJSValue(cx, argv[i]);
+ // NB: Passing NONE for a hint here.
+ if (!JSVAL_IS_PRIMITIVE(argv[i]) &&
+ !RewrapObject(cx, scope, JSVAL_TO_OBJECT(argv[i]), NONE, &argv[i])) {
+ return JS_FALSE;
+ }
}
- if (!JS_CallFunctionValue(cx, callThisObj, OBJECT_TO_JSVAL(funToCall),
+ jsval v;
+ if (!RewrapObject(cx, scope, callThisObj, NONE, &v)) {
+ return JS_FALSE;
+ }
+
+ if (!JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(v), OBJECT_TO_JSVAL(funToCall),
argc, argv, rval)) {
return JS_FALSE;
}
@@ -814,55 +869,18 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_TRUE;
}
- JSObject *objToWrap = JSVAL_TO_OBJECT(argv[0]);
-
- // Prevent script created Script objects from ever being wrapped
- // with XPCSafeJSObjectWrapper, and never let the eval function
- // object be directly wrapped.
-
- if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass ||
- (::JS_ObjectIsFunction(cx, objToWrap) &&
- ::JS_GetFunctionFastNative(cx, ::JS_ValueToFunction(cx, argv[0])) ==
- XPCWrapper::sEvalNative)) {
+ JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(argv[0]));
+ if (!objToWrap) {
return ThrowException(NS_ERROR_INVALID_ARG, cx);
}
- SLIM_LOG_WILL_MORPH(cx, objToWrap);
- if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) {
- return ThrowException(NS_ERROR_FAILURE, cx);
- }
-
// Check that the caller can access the unsafe object.
if (!CanCallerAccess(cx, nsnull, objToWrap)) {
// CanCallerAccess() already threw for us.
return JS_FALSE;
}
- JSObject *unsafeObj = GetUnsafeObject(cx, objToWrap);
-
- if (unsafeObj) {
- // We're asked to wrap an already wrapped object. Re-wrap the
- // object wrapped by the given wrapper.
-
- objToWrap = unsafeObj;
- }
-
- JSObject *wrapperObj =
- JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, scope);
-
- if (!wrapperObj) {
- // JS_NewObjectWithGivenProto already threw.
- return JS_FALSE;
- }
-
- *rval = OBJECT_TO_JSVAL(wrapperObj);
- if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot,
- OBJECT_TO_JSVAL(objToWrap)) ||
- !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) {
- return JS_FALSE;
- }
-
- return JS_TRUE;
+ return WrapObject(cx, scope, OBJECT_TO_JSVAL(objToWrap), rval);
}
static JSBool
@@ -885,7 +903,21 @@ XPC_SJOW_Create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_FALSE;
}
- if (!JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(callee),
+ JSObject *scope = JS_GetGlobalForObject(cx, unsafeObj);
+ for (uintN i = 0; i < argc; ++i) {
+ // NB: Passing NONE for a hint here.
+ if (!JSVAL_IS_PRIMITIVE(argv[i]) &&
+ !RewrapObject(cx, scope, JSVAL_TO_OBJECT(argv[i]), NONE, &argv[i])) {
+ return JS_FALSE;
+ }
+ }
+
+ jsval v;
+ if (!RewrapObject(cx, scope, obj, NONE, &v)) {
+ return JS_FALSE;
+ }
+
+ if (!JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(v), OBJECT_TO_JSVAL(unsafeObj),
argc, argv, rval)) {
return JS_FALSE;
}
@@ -944,20 +976,6 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
return nsnull;
}
- JSObject *tmp =
- XPCWrapper::UnwrapGeneric(cx, &XPCCrossOriginWrapper::XOWClass,
- unsafeObj);
- if (tmp) {
- unsafeObj = tmp;
-
- // Repeat the CanCallerAccess check because the XOW is parented to our
- // scope's global object which makes the above CanCallerAccess call lie.
- if (!CanCallerAccess(cx, nsnull, unsafeObj)) {
- // CanCallerAccess() already threw for us.
- return nsnull;
- }
- }
-
// Create our dummy SJOW.
JSObject *wrapperIter =
JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull,
diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
index e95d8d449cf..37de6fd9143 100644
--- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
@@ -555,7 +555,7 @@ XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return JS_FALSE;
}
- return NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
+ return NewResolve(cx, obj, JS_FALSE, wrappedObj, id, flags, objp);
}
static JSBool
diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp
index afc12b2853c..61cbdbe4448 100644
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -181,19 +181,11 @@ JSBool
RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
jsval *vp)
{
- if (IsSecurityWrapper(obj)) {
- jsval v;
- JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &v);
- NS_ASSERTION(!JSVAL_IS_PRIMITIVE(v), "bad object");
- obj = JSVAL_TO_OBJECT(v);
- } else if (XPCNativeWrapper::IsNativeWrapper(obj)) {
- XPCWrappedNative *wn = XPCNativeWrapper::SafeGetWrappedNative(obj);
- if (!wn) {
- *vp = JSVAL_NULL;
- return JS_TRUE;
- }
-
- obj = wn->GetFlatJSObject();
+ obj = UnsafeUnwrapSecurityWrapper(cx, obj);
+ if (!obj) {
+ // A wrapper wrapping NULL (such as XPCNativeWrapper.prototype).
+ *vp = JSVAL_NULL;
+ return JS_TRUE;
}
XPCWrappedNativeScope *nativescope =
@@ -210,6 +202,28 @@ RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
return CreateWrapperFromType(cx, scope, wn, answer, vp);
}
+JSObject *
+UnsafeUnwrapSecurityWrapper(JSContext *cx, JSObject *obj)
+{
+ if (IsSecurityWrapper(obj)) {
+ jsval v;
+ JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &v);
+ NS_ASSERTION(!JSVAL_IS_PRIMITIVE(v), "bad object");
+ return JSVAL_TO_OBJECT(v);
+ }
+
+ if (XPCNativeWrapper::IsNativeWrapper(obj)) {
+ XPCWrappedNative *wn = XPCNativeWrapper::SafeGetWrappedNative(obj);
+ if (!wn) {
+ return nsnull;
+ }
+
+ return wn->GetFlatJSObject();
+ }
+
+ return obj;
+}
+
JSBool
CreateWrapperFromType(JSContext *cx, JSObject *scope, XPCWrappedNative *wn,
WrapperType hint, jsval *vp)
diff --git a/js/src/xpconnect/src/XPCWrapper.h b/js/src/xpconnect/src/XPCWrapper.h
index a605a04ce5b..3566a971da2 100644
--- a/js/src/xpconnect/src/XPCWrapper.h
+++ b/js/src/xpconnect/src/XPCWrapper.h
@@ -424,6 +424,9 @@ JSBool
RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
jsval *vp);
+JSObject *
+UnsafeUnwrapSecurityWrapper(JSContext *cx, JSObject *obj);
+
JSBool
CreateWrapperFromType(JSContext *cx, JSObject *scope, XPCWrappedNative *wn,
WrapperType hint, jsval *vp);
@@ -463,11 +466,14 @@ Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj);
* Resolves a property (that may be) defined on |innerObj| onto
* |wrapperObj|. This will also resolve random, page-defined objects
* and is therefore unsuitable for cross-origin resolution.
+ *
+ * If |caller| is not NONE, then we will call the proper WrapObject
+ * hook for any getters or setters about to be lifted onto
+ * |wrapperObj|.
*/
JSBool
-NewResolve(JSContext *cx, JSObject *wrapperObj,
- JSBool preserveVal, JSObject *innerObj,
- jsval id, uintN flags, JSObject **objp);
+NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool preserveVal,
+ JSObject *innerObj, jsval id, uintN flags, JSObject **objp);
/**
* Resolve a native property named id from innerObj onto wrapperObj. The
diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp
index 97fd3234792..85517b4f096 100644
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -1053,15 +1053,19 @@ XPCWrappedNativeScope::GetWrapperFor(JSContext *cx, JSObject *obj,
XPCCrossOriginWrapper::ClassNeedsXOW(obj->getClass()->name);
// Is other a chrome object?
+ JSObject *obj2;
+ XPCWrappedNative *wrapper =
+ XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nsnull, &obj2);
if(principalEqual || obj->isSystem())
- return (hint & XPCNW) ? hint : wantsXOW ? SJOW : NONE;
+ {
+ if(hint & XPCNW)
+ return (wrapper || obj2) ? hint : NONE;
+ return wantsXOW ? SJOW : NONE;
+ }
// Other isn't a chrome object: we need to wrap it in a SJOW or an
// XPCNW.
- JSObject *obj2;
- XPCWrappedNative *wrapper =
- XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nsnull, &obj2);
if(!wrapper && !obj2)
hint = SJOW;
@@ -1105,9 +1109,13 @@ XPCWrappedNativeScope::GetWrapperFor(JSContext *cx, JSObject *obj,
// any other types of wrapper than the hint.
if(!wrapper && !obj2)
{
- NS_ASSERTION(principalEqual,
+#if 0
+ // XXX Re-enable these assertions when we have a better mochitest
+ // solution than UniversalXPConnect.
+ NS_ASSERTION(principalEqual || hint == COW,
"touching non-wrappednative object cross origin?");
- NS_ASSERTION(hint == SJOW || hint == UNKNOWN, "bad hint");
+ NS_ASSERTION(hint == SJOW || hint == COW || hint == UNKNOWN, "bad hint");
+#endif
return hint;
}
@@ -1132,7 +1140,10 @@ XPCWrappedNativeScope::GetWrapperFor(JSContext *cx, JSObject *obj,
if(!principalEqual ||
XPCCrossOriginWrapper::ClassNeedsXOW(obj->getClass()->name))
{
- NS_ASSERTION(hint != SJOW, "shouldn't have a SJOW for cross origin access?");
+ // NB: We want to assert that hint is not SJOW here, but it can
+ // be because of shallow XPCNativeWrappers. In that case, XOW is
+ // the right return value because XPCNativeWrappers are meant for
+ // chrome, and we're in content which shouldn't expect SJOWs.
return (hint & XPCNW) ? XPCNW_EXPLICIT : XOW;
}
diff --git a/js/src/xpconnect/tests/chrome/Makefile.in b/js/src/xpconnect/tests/chrome/Makefile.in
index 5fe0c107635..918ab0c470c 100644
--- a/js/src/xpconnect/tests/chrome/Makefile.in
+++ b/js/src/xpconnect/tests/chrome/Makefile.in
@@ -48,6 +48,7 @@ _CHROME_FILES = \
bug503926.xul \
test_bug503926.xul \
test_bug533596.xul \
+ test_wrappers.xul \
$(NULL)
libs:: $(_CHROME_FILES)
diff --git a/js/src/xpconnect/tests/chrome/bug503926.xul b/js/src/xpconnect/tests/chrome/bug503926.xul
index 31afa8ab765..39c7b290528 100644
--- a/js/src/xpconnect/tests/chrome/bug503926.xul
+++ b/js/src/xpconnect/tests/chrome/bug503926.xul
@@ -18,9 +18,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=503926
var passed = false;
var obj = { QueryInterface: function() { passed = true; } }
try { document.documentElement.appendChild(obj); } catch (e) {}
- var isDialog = location.hash != 'iframe';
- var outer = isDialog ? opener.wrappedJSObject : top.wrappedJSObject;
- outer.ok(passed, "chrome/chrome test passed");
+ var isDialog = location.hash != '#iframe';
+ var outer = XPCNativeWrapper.unwrap(isDialog ? opener : top);
+ outer.ok(passed, "chrome/chrome test passed: " + (isDialog ? "dialog" : "iframe"));
if (isDialog)
close();
]]>
diff --git a/js/src/xpconnect/tests/chrome/test_bug503926.xul b/js/src/xpconnect/tests/chrome/test_bug503926.xul
index e2032e8b73e..0ee851a41a4 100644
--- a/js/src/xpconnect/tests/chrome/test_bug503926.xul
+++ b/js/src/xpconnect/tests/chrome/test_bug503926.xul
@@ -15,10 +15,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=503926
Mozilla Bug 503926
-
+ src="chrome://mochikit/content/chrome/js/src/xpconnect/tests/chrome/bug503926.xul#iframe"/>
+
+ Mozilla Bug 533596
+
+