From 7050590b13a59a527ee796ff76e71ec27088cdba Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Fri, 21 Aug 2009 18:20:20 -0700 Subject: [PATCH] Bug 504021 - Add an API to the script security manager to clamp principals for a given context. r=jst/bzbarsky sr=dveditz --- caps/idl/nsIScriptSecurityManager.idl | 25 +- caps/include/nsScriptSecurityManager.h | 20 +- caps/src/nsScriptSecurityManager.cpp | 69 +++- js/src/xpconnect/shell/xpcshell.cpp | 14 + .../xpconnect/src/XPCSafeJSObjectWrapper.cpp | 347 +++++++----------- js/src/xpconnect/src/xpcwrappedjsclass.cpp | 34 +- 6 files changed, 282 insertions(+), 227 deletions(-) diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index a1302bce2605..115ac3109041 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -41,7 +41,7 @@ interface nsIURI; interface nsIChannel; -[scriptable, uuid(f8e350b9-9f31-451a-8c8f-d10fea26b780)] +[scriptable, uuid(c0dbfd5e-b7ae-4c18-8674-82492f35d715)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// @@ -319,6 +319,29 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx); [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx, out JSStackFramePtr fp); + + /** + * If no scripted code is running "above" (or called from) fp, then + * instead of looking at cx->globalObject, we will return |principal|. + * This function only affects |cx|. If someone pushes another context onto + * the context stack, then it supercedes this call. + * NOTE: If |fp| is non-null popContextPrincipal must be called before fp + * has finished executing. + * + * @param cx The context to clamp. + * @param fp The frame pointer to clamp at. May be 'null'. + * @param principal The principal to clamp to. + */ + [noscript] void pushContextPrincipal(in JSContextPtr cx, + in JSStackFramePtr fp, + in nsIPrincipal principal); + + /** + * Removes a clamp set by pushContextPrincipal from cx. This must be + * called in a stack-like fashion (e.g., given two contexts |a| and |b|, + * it is not legal to do: push(a) push(b) pop(a)). + */ + [noscript] void popContextPrincipal(in JSContextPtr cx); }; %{C++ diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index ce2d8f33d765..f2d4aa11ed63 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -486,15 +486,15 @@ private: // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script for the // context. Callers MUST pass in a non-null rv here. - static nsIPrincipal* + nsIPrincipal* GetSubjectPrincipal(JSContext* cx, nsresult* rv); // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script for the frame. // Callers MUST pass in a non-null rv here. - static nsIPrincipal* + nsIPrincipal* GetFramePrincipal(JSContext* cx, JSStackFrame* fp, nsresult* rv); - + // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script. Callers MUST // pass in a non-null rv here. @@ -514,7 +514,7 @@ private: // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script // running. Callers MUST pass in a non-null rv here. - static nsIPrincipal* + nsIPrincipal* GetPrincipalAndFrame(JSContext *cx, JSStackFrame** frameResult, nsresult* rv); @@ -601,6 +601,17 @@ private: PrintPolicyDB(); #endif + struct ContextPrincipal { + ContextPrincipal(ContextPrincipal *next, JSContext *cx, + JSStackFrame *fp, nsIPrincipal *principal) + : mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {} + + ContextPrincipal *mNext; + JSContext *mCx; + JSStackFrame *mFp; + nsCOMPtr mPrincipal; + }; + // JS strings we need to clean up on shutdown static jsval sEnabledID; @@ -618,6 +629,7 @@ private: nsCOMPtr mSecurityPref; nsCOMPtr mSystemPrincipal; nsCOMPtr mSystemCertificate; + ContextPrincipal *mContextPrincipals; nsInterfaceHashtable mPrincipals; PRPackedBool mIsJavaScriptEnabled; PRPackedBool mIsWritingPrefs; diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 9ea28c9dde72..55b4e194e40b 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -402,6 +402,32 @@ nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFra return principal; } +NS_IMETHODIMP +nsScriptSecurityManager::PushContextPrincipal(JSContext *cx, + JSStackFrame *fp, + nsIPrincipal *principal) +{ + ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp, + principal); + if (!cp) + return NS_ERROR_OUT_OF_MEMORY; + + mContextPrincipals = cp; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptSecurityManager::PopContextPrincipal(JSContext *cx) +{ + NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop"); + + ContextPrincipal *next = mContextPrincipals->mNext; + delete mContextPrincipals; + mContextPrincipals = next; + + return NS_OK; +} + //////////////////// // Policy Storage // //////////////////// @@ -2196,7 +2222,6 @@ nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx, return GetScriptPrincipal(cx, script, rv); } -// static nsIPrincipal* nsScriptSecurityManager::GetFramePrincipal(JSContext *cx, JSStackFrame *fp, @@ -2226,22 +2251,36 @@ nsScriptSecurityManager::GetFramePrincipal(JSContext *cx, return result; } -// static nsIPrincipal* nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx, JSStackFrame **frameResult, nsresult* rv) { - NS_PRECONDITION(rv, "Null out param"); + NS_PRECONDITION(rv, "Null out param"); //-- If there's no principal on the stack, look at the global object // and return the innermost frame for annotations. *rv = NS_OK; + if (cx) { - // Get principals from innermost frame of JavaScript or Java. + JSStackFrame *target = nsnull; + nsIPrincipal *targetPrincipal = nsnull; + for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext) + { + if (cp->mCx == cx) + { + target = cp->mFp; + targetPrincipal = cp->mPrincipal; + break; + } + } + + // Get principals from innermost JavaScript frame. JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp)) { + if (fp == target) + break; nsIPrincipal* result = GetFramePrincipal(cx, fp, rv); if (result) { @@ -2251,6 +2290,25 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx, } } + // If targetPrincipal is non-null, then it means that someone wants to + // clamp the principals on this context to this principal. Note that + // fp might not equal target here (fp might be null) because someone + // could have set aside the frame chain in the meantime. + if (targetPrincipal) + { + if (fp && fp == target) + { + *frameResult = fp; + } + else + { + JSStackFrame *inner = nsnull; + *frameResult = JS_FrameIterator(cx, &inner); + } + + return targetPrincipal; + } + nsIScriptContext *scriptContext = GetScriptContext(cx); if (scriptContext) { @@ -2277,7 +2335,6 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx, return nsnull; } -// static nsIPrincipal* nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx, nsresult* rv) @@ -3278,6 +3335,7 @@ nsScriptSecurityManager::nsScriptSecurityManager(void) : mOriginToPolicyMap(nsnull), mDefaultPolicy(nsnull), mCapabilities(nsnull), + mContextPrincipals(nsnull), mIsJavaScriptEnabled(PR_FALSE), mIsWritingPrefs(PR_FALSE), mPolicyPrefsChanged(PR_TRUE) @@ -3360,6 +3418,7 @@ jsval nsScriptSecurityManager::sEnabledID = JSVAL_VOID; nsScriptSecurityManager::~nsScriptSecurityManager(void) { + NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals"); delete mOriginToPolicyMap; if(mDefaultPolicy) mDefaultPolicy->Drop(); diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index 252384d7c0f1..6a87a56c742d 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -1382,6 +1382,20 @@ FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval) return *_retval ? NS_OK : NS_ERROR_FAILURE; } +/* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */ +NS_IMETHODIMP +FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal) +{ + return NS_OK; +} + +/* [noscript] void popContextPrincipal (in JSContextPtr cx); */ +NS_IMETHODIMP +FullTrustSecMan::PopContextPrincipal(JSContext * cx) +{ + return NS_OK; +} + /* [noscript] nsIPrincipal getSystemPrincipal (); */ NS_IMETHODIMP FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval) diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 4de9ad46c260..b4f0e322c07e 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -42,6 +42,7 @@ #include "jsscript.h" // for js_ScriptClass #include "XPCWrapper.h" #include "jsregexp.h" +#include "nsJSPrincipals.h" static JSBool XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); @@ -167,23 +168,47 @@ CanCallerAccess(JSContext *cx, JSObject *unsafeObj) return PR_TRUE; } -static JSPrincipals * -FindObjectPrincipals(JSContext *cx, JSObject *obj) +// Reserved slot indexes on safe wrappers. + +// Boolean value, initialized to false on object creation and true +// only while we're resolving a property on the object. +#define XPC_SJOW_SLOT_IS_RESOLVING 0 + +// Slot for holding on to the principal to use if a principal other +// than that of the unsafe object is desired for this wrapper +// (nsIPrincipal, strong reference). +#define XPC_SJOW_SLOT_PRINCIPAL 1 + + +// Returns a weak reference. +static nsIPrincipal * +FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj) { + // Check if we have a cached principal first. + jsval v; + if (!JS_GetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, &v)) { + return nsnull; + } + + if (!JSVAL_IS_VOID(v)) { + // Found one! No need to do any more refcounting. + return static_cast(JSVAL_TO_PRIVATE(v)); + } + nsCOMPtr objPrincipal; - nsresult rv = FindPrincipals(cx, obj, getter_AddRefs(objPrincipal), nsnull, + nsresult rv = FindPrincipals(cx, innerObj, getter_AddRefs(objPrincipal), nsnull, nsnull); if (NS_FAILED(rv)) { return nsnull; } - JSPrincipals *jsprin; - rv = objPrincipal->GetJSPrincipals(cx, &jsprin); - if (NS_FAILED(rv)) { + if (!JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, + PRIVATE_TO_JSVAL(objPrincipal.get()))) { return nsnull; } - return jsprin; + // The wrapper owns the principal now. + return objPrincipal.forget().get(); } @@ -217,29 +242,6 @@ static JSBool XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -// Reserved slot indexes on safe wrappers. - -// Boolean value, initialized to false on object creation and true -// only while we're resolving a property on the object. -#define XPC_SJOW_SLOT_IS_RESOLVING 0 - -// Slot for caching a compiled scripted function for property -// get/set. -#define XPC_SJOW_SLOT_SCRIPTED_GETSET 1 - -// Slot for caching a compiled scripted function for function -// calling. -#define XPC_SJOW_SLOT_SCRIPTED_FUN 2 - -// Slot for caching a compiled scripted function for calling -// toString(). -#define XPC_SJOW_SLOT_SCRIPTED_TOSTRING 3 - -// Slot for holding on to the principal to use if a principal other -// than that of the unsafe object is desired for this wrapper -// (nsIPrincipal, strong reference). -#define XPC_SJOW_SLOT_PRINCIPAL 4 - // Wrap a JS value in a safe wrapper of a function wrapper if // needed. Note that rval must point to something rooted when calling @@ -266,21 +268,7 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval) // any of the code below. *rval = OBJECT_TO_JSVAL(safeObj); - // If obj and safeObj are from the same scope, propagate cached - // scripted functions to the new safe object. - if (JS_GetGlobalForObject(cx, obj) == JS_GetGlobalForObject(cx, safeObj)) { - jsval rsval; - if (!::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_SCRIPTED_GETSET, - &rsval) || - !::JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_SCRIPTED_GETSET, - rsval) || - !::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_SCRIPTED_FUN, - &rsval) || - !::JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_SCRIPTED_FUN, - rsval)) { - return JS_FALSE; - } - } else { + if (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 @@ -395,81 +383,6 @@ UnwrapJSValue(jsval val) return val; } -// Get a scripted function for use with the safe wrapper (obj) when -// accessing an unsafe object (unsafeObj). If a scripted function -// already exists in the reserved slot slotIndex, use it, otherwise -// create a new one and cache it in that same slot. The source of the -// script is passed in funScript, and the resulting (new or cached) -// scripted function is returned through scriptedFunVal. -/* Keep GetScriptedFunction prototype in sync with corresponding macro */ -static JSBool -GetScriptedFunction(JSContext *cx, JSObject *obj, JSObject *unsafeObj, - uint32 slotIndex, const nsAFlatCString& funScript, - jsval *scriptedFunVal, uintN lineno) -{ - if (!::JS_GetReservedSlot(cx, obj, slotIndex, scriptedFunVal)) { - return JS_FALSE; - } - - // If we either have no scripted function in the requested slot yet, - // or if the scope of the unsafeObj changed since we compiled the - // scripted function, re-compile to make sure the scripted function - // is properly scoped etc. - if (JSVAL_IS_VOID(*scriptedFunVal) || - JS_GetGlobalForObject(cx, unsafeObj) != - JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(*scriptedFunVal))) { - // Check whether we have a cached principal or not. - jsval pv; - if (!::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_PRINCIPAL, &pv)) { - return JS_FALSE; - } - - JSPrincipals *jsprin = nsnull; - - if (!JSVAL_IS_VOID(pv)) { - nsIPrincipal *principal = (nsIPrincipal *)JSVAL_TO_PRIVATE(pv); - - // Found a cached principal, use it rather than looking up the - // principal of the unsafe object. - principal->GetJSPrincipals(cx, &jsprin); - } else { - // No cached principal found, look up the principal based on the - // unsafe object. - jsprin = FindObjectPrincipals(cx, unsafeObj); - } - - if (!jsprin) { - return ThrowException(NS_ERROR_UNEXPECTED, cx); - } - - JSFunction *scriptedFun = - ::JS_CompileFunctionForPrincipals(cx, - JS_GetGlobalForObject(cx, unsafeObj), - jsprin, nsnull, 0, nsnull, - funScript.get(), funScript.Length(), - "XPCSafeJSObjectWrapper.cpp", - lineno); - - JSPRINCIPALS_DROP(cx, jsprin); - - if (!scriptedFun) { - return ThrowException(NS_ERROR_FAILURE, cx); - } - - *scriptedFunVal = OBJECT_TO_JSVAL(::JS_GetFunctionObject(scriptedFun)); - - if (*scriptedFunVal == JSVAL_NULL || - !::JS_SetReservedSlot(cx, obj, slotIndex, *scriptedFunVal)) { - return JS_FALSE; - } - } - - return JS_TRUE; -} - -#define GetScriptedFunction(cx, obj, unsafeObj, slotIndex, funScript, scriptedFunVal) \ - (GetScriptedFunction)(cx, obj, unsafeObj, slotIndex, funScript, scriptedFunVal, __LINE__) - static JSBool XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { @@ -523,22 +436,52 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return XPCWrapper::DelProperty(cx, unsafeObj, id, vp); } -static inline JSBool -CallWithoutStatics(JSContext *cx, JSObject *obj, jsval fval, uintN argc, - jsval *argv, jsval *rval) -{ +NS_STACK_CLASS class SafeCallGuard { +public: + SafeCallGuard(JSContext *cx, nsIPrincipal *principal) + : cx(cx) { + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (ssm) { + // Note: We pass null as the target frame pointer because we know that + // we're about to set aside the frame chain. + nsresult rv = ssm->PushContextPrincipal(cx, nsnull, principal); + if (NS_FAILED(rv)) { + NS_WARNING("Not allowing call because we're out of memory"); + JS_ReportOutOfMemory(cx); + this->cx = nsnull; + return; + } + } + + js_SaveAndClearRegExpStatics(cx, &statics, &tvr); + fp = JS_SaveFrameChain(cx); + options = + JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT); + } + + JSBool ready() { + return cx != nsnull; + } + + ~SafeCallGuard() { + if (cx) { + JS_SetOptions(cx, options); + JS_RestoreFrameChain(cx, fp); + js_RestoreRegExpStatics(cx, &statics, &tvr); + nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); + if (ssm) { + ssm->PopContextPrincipal(cx); + } + } + } + +private: + JSContext *cx; JSRegExpStatics statics; JSTempValueRooter tvr; - js_SaveAndClearRegExpStatics(cx, &statics, &tvr); - JSStackFrame *fp = JS_SaveFrameChain(cx); - uint32 options = - JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT); - JSBool ok = ::JS_CallFunctionValue(cx, obj, fval, argc, argv, rval); - JS_SetOptions(cx, options); - JS_RestoreFrameChain(cx, fp); - js_RestoreRegExpStatics(cx, &statics, &tvr); - return ok; -} + uint32 options; + JSStackFrame *fp; +}; static JSBool XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, @@ -563,35 +506,30 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - // Function body for wrapping property get/set in a scripted - // caller. This scripted function's first argument is the property - // to get/set. If the operation is a get operation, the function is - // passed one argument. If the operation is a set operation, the - // function gets two arguments and the second argument will be the - // value to set the property to. - NS_NAMED_LITERAL_CSTRING(funScript, - "if (arguments.length == 1) return this[arguments[0]];" - "return this[arguments[0]] = arguments[1];"); + { + SafeCallGuard guard(cx, FindObjectPrincipals(cx, obj, unsafeObj)); + if (!guard.ready()) { + return JS_FALSE; + } - jsval scriptedFunVal; - if (!GetScriptedFunction(cx, obj, unsafeObj, XPC_SJOW_SLOT_SCRIPTED_GETSET, - funScript, &scriptedFunVal)) { - return JS_FALSE; + jsid interned_id; + if (!JS_ValueToId(cx, id, &interned_id)) { + return JS_FALSE; + } + + if (aIsSet) { + *vp = UnwrapJSValue(*vp); + } + + JSBool ok = aIsSet + ? JS_SetPropertyById(cx, unsafeObj, interned_id, vp) + : JS_GetPropertyById(cx, unsafeObj, interned_id, vp); + if (!ok) { + return JS_FALSE; + } } - // Build up our argument array per the comment above. - jsval args[2]; - - args[0] = id; - - if (aIsSet) { - args[1] = UnwrapJSValue(*vp); - } - - jsval val; - JSBool ok = CallWithoutStatics(cx, unsafeObj, scriptedFunVal, - aIsSet ? 2 : 1, args, &val); - return ok && WrapJSValue(cx, obj, val, vp); + return WrapJSValue(cx, obj, *vp, vp); } static JSBool @@ -766,7 +704,8 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, callThisObj = unsafeObj; } - JSObject *funToCall = GetUnsafeObject(JSVAL_TO_OBJECT(argv[-2])); + JSObject *safeObj = JSVAL_TO_OBJECT(argv[-2]); + JSObject *funToCall = GetUnsafeObject(safeObj); if (!funToCall) { // Someone has called XPCSafeJSObjectWrapper.prototype() causing @@ -782,50 +721,20 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - // Function body for wrapping calls to functions or callable objects - // in a scripted caller. This scripted function's first argument is - // a native call wrapper, and the second argument is the unsafe - // function to call. All but the first argument are passed to the - // call wrapper. - NS_NAMED_LITERAL_CSTRING(funScript, - "var args = [];" - "for (var i = 1; i < arguments.length; i++)" - "args.push(arguments[i]);" - "return arguments[0].apply(this, args);"); + { + SafeCallGuard guard(cx, FindObjectPrincipals(cx, safeObj, funToCall)); - // Get the scripted function. - jsval scriptedFunVal; - if (!GetScriptedFunction(cx, obj, unsafeObj, XPC_SJOW_SLOT_SCRIPTED_FUN, - funScript, &scriptedFunVal)) { - return JS_FALSE; - } + for (uintN i = 0; i < argc; ++i) { + argv[i] = UnwrapJSValue(argv[i]); + } - // Build up our argument array per earlier comment. - jsval argsBuf[8]; - jsval *args = argsBuf; - - if (argc > 7) { - args = (jsval *)nsMemory::Alloc((argc + 1) * sizeof(jsval *)); - if (!args) { - return ThrowException(NS_ERROR_OUT_OF_MEMORY, cx); + if (!JS_CallFunctionValue(cx, callThisObj, OBJECT_TO_JSVAL(funToCall), + argc, argv, rval)) { + return JS_FALSE; } } - args[0] = OBJECT_TO_JSVAL(funToCall); - - for (uintN i = 0; i < argc; ++i) { - args[i + 1] = UnwrapJSValue(argv[i]); - } - - jsval val; - JSBool ok = CallWithoutStatics(cx, callThisObj, scriptedFunVal, argc + 1, - args, &val); - - if (args != argsBuf) { - nsMemory::Free(args); - } - - return ok && WrapJSValue(cx, obj, val, rval); + return WrapJSValue(cx, obj, *rval, rval); } JSBool @@ -918,9 +827,19 @@ XPC_SJOW_Create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - JSBool ok = CallWithoutStatics(cx, obj, OBJECT_TO_JSVAL(callee), argc, argv, - rval); - return ok && WrapJSValue(cx, callee, *rval, rval); + { + SafeCallGuard guard(cx, FindObjectPrincipals(cx, callee, unsafeObj)); + if (!guard.ready()) { + return JS_FALSE; + } + + if (!JS_CallFunctionValue(cx, obj, OBJECT_TO_JSVAL(callee), + argc, argv, rval)) { + return JS_FALSE; + } + } + + return WrapJSValue(cx, callee, *rval, rval); } static JSBool @@ -1043,19 +962,19 @@ XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - // Function body for wrapping toString() in a scripted caller. - NS_NAMED_LITERAL_CSTRING(funScript, "return '' + this;"); + { + SafeCallGuard guard(cx, FindObjectPrincipals(cx, obj, unsafeObj)); + if (!guard.ready()) { + return JS_FALSE; + } - jsval scriptedFunVal; - if (!GetScriptedFunction(cx, obj, unsafeObj, XPC_SJOW_SLOT_SCRIPTED_TOSTRING, - funScript, &scriptedFunVal)) { - return JS_FALSE; + JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(unsafeObj)); + if (!str) { + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); } - - jsval val; - JSBool ok = CallWithoutStatics(cx, unsafeObj, scriptedFunVal, 0, nsnull, - &val); - return ok && WrapJSValue(cx, obj, val, rval); + return JS_TRUE; } PRBool diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 14e485796889..2a93636914dc 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1275,6 +1275,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, XPCContext* xpcc; JSContext* cx; JSObject* thisObj; + JSBool popPrincipal = JS_FALSE; + nsIScriptSecurityManager* ssm = nsnull; // Make sure not to set the callee on ccx until after we've gone through // the whole nsIXPCFunctionThisTranslator bit. That code uses ccx to @@ -1597,8 +1599,6 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, *sp++ = val; } - - readyToDoTheCall = JS_TRUE; pre_call_clean_up: @@ -1660,6 +1660,31 @@ pre_call_clean_up: JS_ClearPendingException(cx); + if(XPCPerThreadData::IsMainThread(ccx)) + { + ssm = XPCWrapper::GetSecurityManager(); + if(ssm) + { + nsCOMPtr objPrincipal; + ssm->GetObjectPrincipal(ccx, obj, getter_AddRefs(objPrincipal)); + if(objPrincipal) + { + JSStackFrame* fp = nsnull; + nsresult rv = + ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp), + objPrincipal); + if(NS_FAILED(rv)) + { + JS_ReportOutOfMemory(ccx); + retval = NS_ERROR_OUT_OF_MEMORY; + goto done; + } + + popPrincipal = JS_TRUE; + } + } + } + if(XPT_MD_IS_GETTER(info->flags)) success = JS_GetProperty(cx, obj, name, &result); else if(XPT_MD_IS_SETTER(info->flags)) @@ -1696,7 +1721,10 @@ pre_call_clean_up: } } - if (!success) + if(popPrincipal) + ssm->PopContextPrincipal(ccx); + + if(!success) { PRBool forceReport; if(NS_FAILED(mInfo->IsFunction(&forceReport)))