JSBool XPC_COW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj, jsval *rval) { jsval funobjVal = OBJECT_TO_JSVAL(funobj); JSFunction *wrappedFun = reinterpret_cast<JSFunction *>(xpc_GetJSPrivate(funobj)); JSNative native = JS_GetFunctionNative(cx, wrappedFun); if (!native || native == XPC_COW_FunctionWrapper) { *rval = funobjVal; return JS_TRUE; } JSFunction *funWrapper = JS_NewFunction(cx, XPC_COW_FunctionWrapper, JS_GetFunctionArity(wrappedFun), 0, JS_GetGlobalForObject(cx, outerObj), JS_GetFunctionName(wrappedFun)); if (!funWrapper) { return JS_FALSE; } JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper); *rval = OBJECT_TO_JSVAL(funWrapperObj); return JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eWrappedFunctionSlot, funobjVal); }
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); }
JSBool XPC_NW_WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval) { // If funobj is already a wrapped function, just return it. if (JS_GetFunctionNative(cx, JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj))) == XPC_NW_FunctionWrapper) { *rval = OBJECT_TO_JSVAL(funobj); return JS_TRUE; } // Ensure that we've been called from JS. Native code should extract // the wrapped native and deal with that directly. // XXX Can we simply trust |cx| here? JSStackFrame *iterator = nsnull; if (!::JS_FrameIterator(cx, &iterator)) { ::JS_ReportError(cx, "XPCNativeWrappers must be used from script"); return JS_FALSE; } // Create a new function that'll call our given function. This new // function's parent will be the original function and that's how we // get the right thing to call when this function is called. // Note that we pass nsnull as the nominal parent so that we'll inherit // our caller's Function.prototype. JSFunction *funWrapper = ::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, nsnull, "XPCNativeWrapper function wrapper"); if (!funWrapper) { return JS_FALSE; } JSObject* funWrapperObj = ::JS_GetFunctionObject(funWrapper); ::JS_SetParent(cx, funWrapperObj, funobj); *rval = OBJECT_TO_JSVAL(funWrapperObj); return JS_TRUE; }
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); }