Don't wrap everything that comes out of a wrapped function, if that function is same-origin. bug 390946, r+sr+a=jst

This commit is contained in:
mrbkap@gmail.com 2007-08-15 14:09:27 -07:00
parent 8c0b0586f3
commit 8dc6a0e55f
2 changed files with 92 additions and 66 deletions

View File

@ -264,11 +264,14 @@ IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj)
return ssm->CheckSameOriginPrincipal(subjectPrin, objectPrin); return ssm->CheckSameOriginPrincipal(subjectPrin, objectPrin);
} }
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp);
static JSBool static JSBool
XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval) jsval *rval)
{ {
JSObject *wrappedObj; JSObject *wrappedObj, *outerObj = obj;
obj = GetWrapper(cx, obj); obj = GetWrapper(cx, obj);
if (!obj || (wrappedObj = GetWrappedObject(cx, obj)) == nsnull) { if (!obj || (wrappedObj = GetWrappedObject(cx, obj)) == nsnull) {
@ -286,6 +289,11 @@ XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
} }
nsresult rv = IsWrapperSameOrigin(cx, JSVAL_TO_OBJECT(funToCall));
if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
return ThrowException(rv, cx);
}
JSNative native = JS_GetFunctionNative(cx, fun); JSNative native = JS_GetFunctionNative(cx, fun);
NS_ASSERTION(native, "How'd we get here with a scripted function?"); NS_ASSERTION(native, "How'd we get here with a scripted function?");
@ -299,29 +307,55 @@ XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
return JS_FALSE; return JS_FALSE;
} }
if (NS_SUCCEEDED(rv)) {
return WrapSameOriginProp(cx, outerObj, rval);
}
return XPC_XOW_RewrapIfNeeded(cx, obj, rval); return XPC_XOW_RewrapIfNeeded(cx, obj, rval);
} }
static JSBool
WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp)
{
// Don't call XPC_XOW_RewrapIfNeeded for same origin properties. We only
// need to wrap window, document and location.
if (JSVAL_IS_PRIMITIVE(*vp)) {
return JS_TRUE;
}
JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp);
const char *name = JS_GET_CLASS(cx, wrappedObj)->name;
if (XPC_XOW_ClassNeedsXOW(name)) {
return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp);
}
if (JS_ObjectIsFunction(cx, wrappedObj) &&
JS_GetFunctionNative(cx, reinterpret_cast<JSFunction *>
(JS_GetPrivate(cx, wrappedObj))) ==
XPCWrapper::sEvalNative) {
return XPC_XOW_WrapFunction(cx, outerObj, wrappedObj, vp);
}
return JS_TRUE;
}
JSBool JSBool
XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj, XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
jsval *rval) jsval *rval)
{ {
jsval funobjVal = OBJECT_TO_JSVAL(funobj); jsval funobjVal = OBJECT_TO_JSVAL(funobj);
JSNative native = JS_GetFunctionNative(cx, JS_ValueToFunction(cx, funobjVal)); JSFunction *wrappedFun = reinterpret_cast<JSFunction *>(JS_GetPrivate(cx, funobj));
JSNative native = JS_GetFunctionNative(cx, wrappedFun);
if (!native || native == XPC_XOW_FunctionWrapper) { if (!native || native == XPC_XOW_FunctionWrapper) {
*rval = funobjVal; *rval = funobjVal;
return JS_TRUE; return JS_TRUE;
} }
JSFunction *wrappedFun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj));
NS_ASSERTION(wrappedFun, "We were told this was a function");
JSFunction *funWrapper = JSFunction *funWrapper =
JS_NewFunction(cx, XPC_XOW_FunctionWrapper, JS_NewFunction(cx, XPC_XOW_FunctionWrapper,
JS_GetFunctionArity(wrappedFun), 0, JS_GetFunctionArity(wrappedFun), 0,
JS_GetGlobalForObject(cx, outerObj), JS_GetGlobalForObject(cx, outerObj),
"Wrapped function"); JS_GetFunctionName(wrappedFun));
// XXX JS_GetFunctionName(wrappedFun));
if (!funWrapper) { if (!funWrapper) {
return JS_FALSE; return JS_FALSE;
} }
@ -366,6 +400,7 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp)
XPCWrappedNative *wn; XPCWrappedNative *wn;
if (!JSVAL_IS_OBJECT(*vp) || if (!JSVAL_IS_OBJECT(*vp) ||
!(wrappedObj = JSVAL_TO_OBJECT(*vp)) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
JS_GET_CLASS(cx, wrappedObj) == &sXPC_XOW_JSClass.base ||
!(wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj))) { !(wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj))) {
return JS_TRUE; return JS_TRUE;
} }
@ -515,6 +550,17 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
return JS_TRUE; return JS_TRUE;
} }
// Don't do anything if we already resolved to a wrapped function in
// NewResolve. In practice, this means that this is a wrapped eval
// function.
jsval v = *vp;
if (!JSVAL_IS_PRIMITIVE(v) &&
JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v)) &&
JS_GetFunctionNative(cx, JS_ValueToFunction(cx, v)) ==
XPC_XOW_FunctionWrapper) {
return JS_TRUE;
}
XPCCallContext ccx(JS_CALLER, cx); XPCCallContext ccx(JS_CALLER, cx);
if (!ccx.IsValid()) { if (!ccx.IsValid()) {
return ThrowException(NS_ERROR_FAILURE, cx); return ThrowException(NS_ERROR_FAILURE, cx);
@ -609,25 +655,7 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
} }
} }
// Don't call XPC_XOW_RewrapIfNeeded for same origin properties. We only return WrapSameOriginProp(cx, obj, vp);
// need to wrap window, document and location.
if (JSVAL_IS_PRIMITIVE(*vp)) {
return JS_TRUE;
}
wrappedObj = JSVAL_TO_OBJECT(*vp);
if (JS_ObjectIsFunction(cx, wrappedObj) &&
JS_GetFunctionNative(cx, JS_ValueToFunction(cx, *vp)) ==
XPCWrapper::sEvalNative) {
return XPC_XOW_WrapFunction(cx, obj, wrappedObj, vp);
}
const char *name = JS_GET_CLASS(cx, wrappedObj)->name;
if (XPC_XOW_ClassNeedsXOW(name)) {
return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, obj), vp);
}
return JS_TRUE;
} }
JS_STATIC_DLL_CALLBACK(JSBool) JS_STATIC_DLL_CALLBACK(JSBool)

View File

@ -140,58 +140,56 @@ XPCWrapper::NewResolve(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, jsval id, uintN flags, JSObject *innerObj, jsval id, uintN flags,
JSObject **objp, JSBool preserveVal) JSObject **objp, JSBool preserveVal)
{ {
jschar *chars = nsnull;
size_t length;
JSBool hasProp, ok;
jsval v = JSVAL_VOID; jsval v = JSVAL_VOID;
if (JSVAL_IS_STRING(id)) { jsid interned_id;
JSString *str = JSVAL_TO_STRING(id); if (!::JS_ValueToId(cx, id, &interned_id)) {
return JS_FALSE;
chars = ::JS_GetStringChars(str);
length = ::JS_GetStringLength(str);
ok = ::JS_HasUCProperty(cx, innerObj, chars, length, &hasProp);
if (preserveVal && ok && hasProp) {
ok = ::JS_LookupUCProperty(cx, innerObj, chars, length, &v);
}
} else if (JSVAL_IS_INT(id)) {
ok = ::JS_HasElement(cx, innerObj, JSVAL_TO_INT(id), &hasProp);
if (preserveVal && ok && hasProp) {
ok = ::JS_LookupElement(cx, innerObj, JSVAL_TO_INT(id), &v);
}
} else {
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=381662
// A non-string and non-int id is being resolved. We don't deal
// with those yet, return early.
return ThrowException(NS_ERROR_INVALID_ARG, cx);
} }
if (!ok || !hasProp) { JSProperty *prop;
// An error occured, or the property was not found. Return JSObject *innerObjp;
// early. This is safe even in the case of a set operation since if (!OBJ_LOOKUP_PROPERTY(cx, innerObj, interned_id, &innerObjp, &prop)) {
// if the property doesn't exist there's no chance of a setter return JS_FALSE;
// being called or any other code being run as a result of the }
// set.
return ok; if (!prop) {
// Nothing to define.
return JS_TRUE;
}
JSBool isXOW = (JS_GET_CLASS(cx, wrapperObj) == &sXPC_XOW_JSClass.base);
if (preserveVal || isXOW) {
JSScopeProperty *sprop = reinterpret_cast<JSScopeProperty *>(prop);
if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(innerObjp))) {
v = OBJ_GET_SLOT(cx, innerObjp, sprop->slot);
}
}
OBJ_DROP_PROPERTY(cx, innerObjp, prop);
// Hack alert: we only do this for same-origin calls on XOWs: we want
// to preserve 'eval' function wrapper on the wrapper object itself
// to preserve eval's identity.
if (!preserveVal && isXOW && !JSVAL_IS_PRIMITIVE(v)) {
JSObject *obj = JSVAL_TO_OBJECT(v);
if (JS_ObjectIsFunction(cx, obj)) {
JSFunction *fun = reinterpret_cast<JSFunction *>(JS_GetPrivate(cx, obj));
if (JS_GetFunctionNative(cx, fun) == sEvalNative &&
!WrapFunction(cx, wrapperObj, obj, &v, JS_FALSE)) {
return JS_FALSE;
}
}
} }
jsval oldSlotVal; jsval oldSlotVal;
if (!::JS_GetReservedSlot(cx, wrapperObj, sResolvingSlot, &oldSlotVal) || if (!::JS_GetReservedSlot(cx, wrapperObj, sResolvingSlot, &oldSlotVal) ||
!::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, !::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, JSVAL_TRUE)) {
BOOLEAN_TO_JSVAL(JS_TRUE))) {
return JS_FALSE; return JS_FALSE;
} }
if (chars) { JSBool ok = OBJ_DEFINE_PROPERTY(cx, wrapperObj, interned_id, v, nsnull,
ok = ::JS_DefineUCProperty(cx, wrapperObj, chars, length, v, nsnull, JSPROP_ENUMERATE, nsnull);
nsnull, nsnull, JSPROP_ENUMERATE);
} else {
ok = ::JS_DefineElement(cx, wrapperObj, JSVAL_TO_INT(id), v,
nsnull, nsnull, JSPROP_ENUMERATE);
}
if (ok && (ok = ::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, if (ok && (ok = ::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot,
oldSlotVal))) { oldSlotVal))) {