static JSBool XPC_XOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Nothing to call. return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't call. return ThrowException(rv, cx); } return JS_FALSE; } JSObject *callee = JSVAL_TO_OBJECT(argv[-2]); NS_ASSERTION(GetWrappedObject(cx, callee), "How'd we get here?"); callee = GetWrappedObject(cx, callee); if (!JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(callee), argc, argv, rval)) { return JS_FALSE; } return XPC_XOW_RewrapIfNeeded(cx, callee, rval); }
static JSBool XPC_COW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) { // Convert both sides to XPCWrappedNative and see if they match. if (JSVAL_IS_PRIMITIVE(v)) { *bp = JS_FALSE; return JS_TRUE; } JSObject *test = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v)); obj = GetWrappedObject(cx, obj); if (!obj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCWrappedNative *other = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, test); if (!other) { *bp = JS_FALSE; return JS_TRUE; } XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = me->GetFlatJSObject(); test = other->GetFlatJSObject(); return ((JSExtendedClass *)STOBJ_GET_CLASS(obj))-> equality(cx, obj, OBJECT_TO_JSVAL(test), bp); }
static JSBool XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, JSObject **objp) { obj = GetWrapper(obj); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // No wrappedObj means that this is probably the prototype. *objp = nsnull; return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } jsid id; JSBool canTouch; if (!JS_ValueToId(cx, idval, &id) || !CanTouchProperty(cx, obj, id, (flags & JSRESOLVE_ASSIGNING) != 0, &canTouch)) { return JS_FALSE; } if (!canTouch) { return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); } return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp); }
static JSBool XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *realObj = GetWrapper(JSVAL_TO_OBJECT(argv[-2])); JSObject *wrappedObj = GetWrappedObject(cx, realObj); if (!wrappedObj) { // Nothing to construct. return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't construct. return ThrowException(rv, cx); } return JS_FALSE; } if (!JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(wrappedObj), argc, argv, rval)) { return JS_FALSE; } return XPC_XOW_RewrapIfNeeded(cx, wrappedObj, rval); }
static void XPC_XOW_Finalize(JSContext *cx, JSObject *obj) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return; } // Get our scope. jsval scopeVal; if (!JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &scopeVal)) { return; } // Now that we have our scope, see if it's going away. If it is, // then our work here is going to be done when we destroy the scope // entirely. Scope can be null if we're an enumerating XOW. XPCWrappedNativeScope *scope = reinterpret_cast<XPCWrappedNativeScope *> (JSVAL_TO_PRIVATE(scopeVal)); if (!scope) { return; } // Remove ourselves from the map. scope->GetWrapperMap()->Remove(wrappedObj); }
static JSBool XPC_XOW_Enumerate(JSContext *cx, JSObject *obj) { obj = GetWrapper(obj); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Nothing to enumerate. return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't enumerate on foreign objects. return ThrowException(rv, cx); } return JS_FALSE; } return XPCWrapper::Enumerate(cx, obj, wrappedObj); }
static JSBool XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { // Don't do any work to convert to object. if (type == JSTYPE_OBJECT) { *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Converting the prototype to something. *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } if (!STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } return XPC_COW_RewrapForContent(cx, obj, vp); }
static JSBool XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't delete properties on foreign objects. return ThrowException(rv, cx); } return JS_FALSE; } // Same origin, pass this request along. return XPCWrapper::DelProperty(cx, wrappedObj, id, vp); }
static JSObject * XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { ThrowException(NS_ERROR_INVALID_ARG, cx); return nsnull; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { ThrowException(NS_ERROR_FAILURE, cx); return nsnull; } JSObject *wrapperIter = JS_NewObject(cx, &sXPC_COW_JSClass.base, nsnull, JS_GetGlobalForObject(cx, obj)); if (!wrapperIter) { return nsnull; } JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our COW. jsval v = OBJECT_TO_JSVAL(wrappedObj); if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) { return nsnull; } return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, keysonly); }
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); JSClass *clasp = STOBJ_GET_CLASS(wrappedObj); if (XPC_XOW_ClassNeedsXOW(clasp->name)) { return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp); } // Check if wrappedObj is an XOW. If so, verify that it's from the // right scope. if (clasp == &sXPC_XOW_JSClass.base && STOBJ_GET_PARENT(wrappedObj) != STOBJ_GET_PARENT(outerObj)) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, wrappedObj)); return XPC_XOW_WrapObject(cx, STOBJ_GET_PARENT(outerObj), vp); } return JS_TRUE; }
static JSBool XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *wrappedObj, *outerObj = obj; // Allow 'this' to be either an XOW, in which case we unwrap it. // We disallow invalid XOWs that have no wrapped object. Otherwise, // if it isn't an XOW, then pass it through as-is. wrappedObj = GetWrapper(obj); if (wrappedObj) { wrappedObj = GetWrappedObject(cx, wrappedObj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } } else { wrappedObj = obj; } JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]); jsval funToCall; if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot, &funToCall)) { return JS_FALSE; } JSFunction *fun = JS_ValueToFunction(cx, funToCall); if (!fun) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, JSVAL_TO_OBJECT(funToCall), nsnull); if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { return ThrowException(rv, cx); } #ifdef DEBUG JSNative native = JS_GetFunctionNative(cx, fun); NS_ASSERTION(native, "How'd we get here with a scripted function?"); #endif if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) { return JS_FALSE; } if (NS_SUCCEEDED(rv)) { return WrapSameOriginProp(cx, outerObj, rval); } return XPC_XOW_RewrapIfNeeded(cx, obj, rval); }
static JSBool XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, JSBool isSet) { obj = GetWrapper(obj); if (!obj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } AUTO_MARK_JSVAL(ccx, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } jsid interned_id; if (!JS_ValueToId(cx, id, &interned_id)) { return JS_FALSE; } if (interned_id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO) || interned_id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PARENT) || interned_id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)) { // No getting or setting __proto__ or __parent__ on my object. return ThrowException(NS_ERROR_INVALID_ARG, cx); // XXX better error message } JSBool canTouch; if (!CanTouchProperty(cx, obj, interned_id, isSet, &canTouch)) { return JS_FALSE; } if (!canTouch) { return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); } if (!XPC_COW_RewrapForChrome(cx, obj, vp)) { return JS_FALSE; } JSBool ok = isSet ? JS_SetPropertyById(cx, wrappedObj, interned_id, vp) : JS_GetPropertyById(cx, wrappedObj, interned_id, vp); if (!ok) { return JS_FALSE; } return XPC_COW_RewrapForContent(cx, obj, vp); }
static JSBool XPC_COW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode, jsval *vp) { // Simply forward checkAccess to our wrapped object. It's already expecting // untrusted things to ask it about accesses. uintN junk; jsid id; return JS_ValueToId(cx, prop, &id) && JS_CheckAccess(cx, GetWrappedObject(cx, obj), id, mode, vp, &junk); }
static JSBool XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) { JSObject *iface = GetWrappedObject(cx, obj); XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, iface, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Don't do this test across origins. return ThrowException(rv, cx); } return JS_FALSE; } JSClass *clasp = STOBJ_GET_CLASS(iface); *bp = JS_FALSE; if (!clasp->hasInstance) { return JS_TRUE; } // Prematurely unwrap the left hand side. if (!JSVAL_IS_PRIMITIVE(v)) { JSObject *test = JSVAL_TO_OBJECT(v); // GetWrappedObject does an instanceof check. test = GetWrappedObject(cx, test); if (test) { v = OBJECT_TO_JSVAL(test); } } return clasp->hasInstance(cx, iface, v, bp); }
static JSObject * XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { ThrowException(NS_ERROR_INVALID_ARG, cx); return nsnull; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { ThrowException(NS_ERROR_FAILURE, cx); return nsnull; } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't create iterators for foreign objects. ThrowException(rv, cx); return nsnull; } ThrowException(NS_ERROR_FAILURE, cx); return nsnull; } JSObject *wrapperIter = JS_NewObject(cx, &sXPC_XOW_JSClass.base, nsnull, JS_GetGlobalForObject(cx, obj)); if (!wrapperIter) { return nsnull; } JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || !JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot, PRIVATE_TO_JSVAL(nsnull))) { return nsnull; } return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, keysonly); }
static JSBool XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } // Deleting a property is safe. return XPCWrapper::DelProperty(cx, wrappedObj, id, vp); }
static JSBool XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = GetWrapper(obj); if (!obj) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Someone's calling toString on our prototype. NS_NAMED_LITERAL_CSTRING(protoString, "[object XPCCrossOriginWrapper]"); JSString *str = JS_NewStringCopyN(cx, protoString.get(), protoString.Length()); if (!str) { return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) { return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); } rv = ssm->CheckPropertyAccess(cx, wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name, GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING), nsIXPCSecurityManager::ACCESS_GET_PROPERTY); } if (NS_FAILED(rv)) { return JS_FALSE; } XPCWrappedNative *wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); return XPCWrapper::NativeToString(cx, wn, argc, argv, rval, JS_FALSE); }
static JSBool XPC_XOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { // Don't do any work to convert to object. if (type == JSTYPE_OBJECT) { *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Converting the prototype to something. if (type == JSTYPE_STRING || type == JSTYPE_VOID) { return XPC_XOW_toString(cx, obj, 0, nsnull, vp); } *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } // Note: JSTYPE_VOID and JSTYPE_STRING are equivalent. nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv) && (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED || (type != JSTYPE_STRING && type != JSTYPE_VOID))) { // Ensure that we report some kind of error. if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { ThrowException(rv, cx); } return JS_FALSE; } if (!STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } return NS_SUCCEEDED(rv) ? WrapSameOriginProp(cx, obj, vp) : XPC_XOW_RewrapIfNeeded(cx, obj, vp); }
static JSBool XPC_COW_Enumerate(JSContext *cx, JSObject *obj) { obj = GetWrapper(obj); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // Nothing to enumerate. return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } return XPCWrapper::Enumerate(cx, obj, wrappedObj); }
static JSBool XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { obj = GetWrapper(obj); jsval resolving; if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) { return JS_FALSE; } if (HAS_FLAGS(resolving, FLAG_RESOLVING)) { // Allow us to define a property on ourselves. return JS_TRUE; } // Someone's adding a property to us. We need to protect ourselves from // getters and setters. JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } jsid interned_id; JSPropertyDescriptor desc; if (!JS_ValueToId(cx, id, &interned_id) || !XPCWrapper::GetPropertyAttrs(cx, obj, interned_id, JSRESOLVE_QUALIFIED, JS_TRUE, &desc)) { return JS_FALSE; } NS_ASSERTION(desc.obj == obj, "The JS engine lies!"); if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) { // Only chrome is allowed to add getters or setters to our object. if (!AllowedToAct(cx, id)) { return JS_FALSE; } } return XPC_COW_RewrapForChrome(cx, obj, vp) && JS_DefinePropertyById(cx, wrappedObj, interned_id, *vp, desc.getter, desc.setter, desc.attrs); }
static JSBool XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { // All AddProperty needs to do is pass on addProperty requests to // same-origin objects, and throw for all else. obj = GetWrapper(obj); jsval resolving; if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) { return JS_FALSE; } if (HAS_FLAGS(resolving, FLAG_RESOLVING)) { // Allow us to define a property on ourselves. return JS_TRUE; } JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } JSBool privilegeEnabled = JS_FALSE; nsresult rv = CanAccessWrapper(cx, wrappedObj, &privilegeEnabled); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't override properties on foreign objects. return ThrowException(rv, cx); } return JS_FALSE; } // Same origin, pass this request along. return XPCWrapper::AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp); }
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; } for (uintN i = 0; i < argc; ++i) { if (!XPC_COW_RewrapForChrome(cx, obj, &argv[i])) { return JS_FALSE; } } if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) { return JS_FALSE; } return XPC_COW_RewrapForContent(cx, obj, rval); }
JSBool XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) { // Don't need to wrap primitive values. if (JSVAL_IS_PRIMITIVE(*vp)) { return JS_TRUE; } JSObject *obj = JSVAL_TO_OBJECT(*vp); if (JS_ObjectIsFunction(cx, obj)) { return XPC_XOW_WrapFunction(cx, outerObj, obj, vp); } XPCWrappedNative *wn = nsnull; if (STOBJ_GET_CLASS(obj) == &sXPC_XOW_JSClass.base && STOBJ_GET_PARENT(outerObj) != STOBJ_GET_PARENT(obj)) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { return JS_TRUE; } return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn); }
JSBool RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) { // Don't need to wrap primitive values. if (JSVAL_IS_PRIMITIVE(*vp)) { return JS_TRUE; } JSObject *obj = JSVAL_TO_OBJECT(*vp); if (JS_ObjectIsFunction(cx, obj)) { return WrapFunction(cx, outerObj, obj, vp); } XPCWrappedNative *wn = nsnull; if (obj->getClass() == &XOWClass && outerObj->getParent() != obj->getParent()) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { return JS_TRUE; } return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn); }
static JSObject * XPC_COW_WrappedObject(JSContext *cx, JSObject *obj) { return GetWrappedObject(cx, obj); }
static JSBool XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, JSBool isSet) { if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { 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; } JSObject *origObj = obj; obj = GetWrapper(obj); if (!obj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } AUTO_MARK_JSVAL(ccx, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } JSBool privilegeEnabled; nsresult rv = CanAccessWrapper(cx, wrappedObj, &privilegeEnabled); if (NS_FAILED(rv)) { if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { return JS_FALSE; } // This is a request to get a property across origins. We need to // determine if this property is allAccess. If it is, then we need to // actually get the property. If not, we simply need to throw an // exception. XPCWrappedNative *wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?"); if (!IsValFrame(wrappedObj, id, wn)) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) { return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); } rv = ssm->CheckPropertyAccess(cx, wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name, id, isSet ? XPCWrapper::sSecMgrSetProp : XPCWrapper::sSecMgrGetProp); if (NS_FAILED(rv)) { // The security manager threw an exception for us. return JS_FALSE; } } return XPCWrapper::GetOrSetNativeProperty(cx, obj, wn, id, vp, isSet, JS_FALSE); } JSObject *proto = nsnull; // Initialize this to quiet GCC. JSBool checkProto = (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)); if (checkProto) { proto = STOBJ_GET_PROTO(wrappedObj); } // Same origin, pass this request along as though nothing interesting // happened. jsid asId; if (!JS_ValueToId(cx, id, &asId)) { return JS_FALSE; } JSBool ok = isSet ? JS_SetPropertyById(cx, wrappedObj, asId, vp) : JS_GetPropertyById(cx, wrappedObj, asId, vp); if (!ok) { return JS_FALSE; } if (checkProto) { JSObject *newProto = STOBJ_GET_PROTO(wrappedObj); // If code is trying to set obj.__proto__ and we're on obj's // prototype chain, then the JS_GetPropertyById above will do the // wrong thing if wrappedObj still delegates to Object.prototype. // However, it's hard to figure out if wrappedObj still does // delegate to Object.prototype so check to see if proto changed as a // result of setting __proto__. if (origObj != obj) { // Undo the damage. if (!JS_SetPrototype(cx, wrappedObj, proto) || !JS_SetPrototype(cx, origObj, newProto)) { return JS_FALSE; } } else if (newProto) { // __proto__ setting is a bad hack, people shouldn't do it. In // this case we're setting the direct prototype of a XOW object, // in the interests of sanity only allow it to be set to null in // this case. JS_SetPrototype(cx, wrappedObj, proto); JS_ReportError(cx, "invalid __proto__ value (can only be set to null)"); return JS_FALSE; } } return WrapSameOriginProp(cx, obj, vp); }
static JSBool XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) { obj = GetWrapper(obj); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { // No wrappedObj means that this is probably the prototype. *objp = nsnull; return JS_TRUE; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { return ThrowException(NS_ERROR_FAILURE, cx); } JSBool privilegeEnabled; nsresult rv = CanAccessWrapper(cx, wrappedObj, &privilegeEnabled); if (NS_FAILED(rv)) { if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) { return JS_FALSE; } // We're dealing with a cross-origin lookup. Ensure that we're allowed to // resolve this property and resolve it if so. Otherwise, we deny access // and throw a security error. Note that this code does not actually check // to see if the property exists, that's dealt with below. XPCWrappedNative *wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj); NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?"); if (!IsValFrame(wrappedObj, id, wn)) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (!ssm) { return ThrowException(NS_ERROR_NOT_INITIALIZED, cx); } PRUint32 action = (flags & JSRESOLVE_ASSIGNING) ? XPCWrapper::sSecMgrSetProp : XPCWrapper::sSecMgrGetProp; rv = ssm->CheckPropertyAccess(cx, wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name, id, action); if (NS_FAILED(rv)) { // The security manager threw an exception for us. return JS_FALSE; } } // We're out! We're allowed to resolve this property. return XPCWrapper::ResolveNativeProperty(cx, obj, wrappedObj, wn, id, flags, objp, JS_FALSE); } if (privilegeEnabled && !(obj = GetUXPCObject(cx, obj))) { return JS_FALSE; } if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { jsval oldSlotVal; if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &oldSlotVal) || !JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) | FLAG_RESOLVING))) { return JS_FALSE; } JSBool ok = JS_DefineFunction(cx, obj, "toString", XPC_XOW_toString, 0, 0) != nsnull; JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, oldSlotVal); if (ok) { *objp = obj; } return ok; } return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp); }