diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 9a242af9464..1d806c96244 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -216,6 +216,32 @@ ThrowException(nsresult ex, JSContext *cx) return JS_FALSE; } +static inline +JSBool +EnsureLegalActivity(JSContext *cx, JSObject *obj) +{ + jsval flags; + + ::JS_GetReservedSlot(cx, obj, 0, &flags); + if (HAS_FLAGS(flags, FLAG_EXPLICIT)) { + // Can't make any assertions about the owner of this wrapper. + return JS_TRUE; + } + + JSStackFrame *frame = nsnull; + uint32 fileFlags = JS_GetTopScriptFilenameFlags(cx, NULL); + if (!JS_FrameIterator(cx, &frame) || + fileFlags == JSFILENAME_NULL || + (fileFlags & JSFILENAME_SYSTEM)) { + // We expect implicit native wrappers in system files. + return JS_TRUE; + } + + // Otherwise, we're looking at a non-system file with a handle on an + // implcit wrapper. This is a bug! Deny access. + return ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); +} + static JSBool WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval) { @@ -265,12 +291,17 @@ XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) // Note: no need to protect *vp from GC here, since it's already in the slot // on |obj|. - return RewrapIfDeepWrapper(cx, obj, *vp, vp); + return EnsureLegalActivity(cx, obj) && + RewrapIfDeepWrapper(cx, obj, *vp, vp); } JS_STATIC_DLL_CALLBACK(JSBool) XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + XPC_NW_BYPASS_BASE(cx, obj, // We're being notified of a delete operation on id in this // XPCNativeWrapper, so forward to the right high-level hook, @@ -414,6 +445,10 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } } + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + XPCWrappedNative *wrappedNative = XPCNativeWrapper::GetWrappedNative(cx, obj); @@ -623,6 +658,10 @@ XPC_NW_Enumerate(JSContext *cx, JSObject *obj) // JS_Enumerate API. Then reflect properties named by the enumerated // identifiers from the wrapped native to the native wrapper. + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + XPCWrappedNative *wn = XPCNativeWrapper::GetWrappedNative(cx, obj); if (!wn) { return JS_TRUE; @@ -682,6 +721,10 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, return JS_TRUE; } + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + // We can't use XPC_NW_BYPASS here, because we need to do a full // OBJ_LOOKUP_PROPERTY on the wrapped native's object, in order to // trigger reflection along the wrapped native prototype chain. @@ -893,8 +936,11 @@ XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JS_STATIC_DLL_CALLBACK(JSBool) XPC_NW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { - XPC_NW_BYPASS(cx, obj, convert, (cx, obj, type, vp)); + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + XPC_NW_BYPASS(cx, obj, convert, (cx, obj, type, vp)); return JS_TRUE; } @@ -1256,6 +1302,10 @@ XPC_NW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } } + if (!EnsureLegalActivity(cx, obj)) { + return JS_FALSE; + } + // Check whether toString was overridden in any object along // the wrapped native's object's prototype chain. XPCJSRuntime *rt = nsXPConnect::GetRuntime(); diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 752e61445c2..54ad5518638 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -836,6 +836,23 @@ inline nsresult UnexpectedFailure(nsresult rv) return rv; } +class SaveFrame +{ +public: + SaveFrame(JSContext *cx) + : mJSContext(cx) { + mFrame = JS_SaveFrameChain(mJSContext); + } + + ~SaveFrame() { + JS_RestoreFrameChain(mJSContext, mFrame); + } + +private: + JSContext *mJSContext; + JSStackFrame *mFrame; +}; + /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */ NS_IMETHODIMP nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) @@ -843,6 +860,7 @@ nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aGlobalJSObj, "bad param"); + SaveFrame sf(aJSContext); XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); @@ -980,6 +998,7 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, JS_SetPrototype(aJSContext, protoJSObject, scope->GetPrototypeJSObject()); } + SaveFrame sf(ccx); if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, globalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE);