Bug 504021 - Add an API to the script security manager to clamp principals for a given context. r=jst/bzbarsky sr=dveditz

This commit is contained in:
Blake Kaplan 2009-08-21 18:20:20 -07:00
Родитель c77dd603f8
Коммит 7050590b13
6 изменённых файлов: 282 добавлений и 227 удалений

Просмотреть файл

@ -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++

Просмотреть файл

@ -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<nsIPrincipal> mPrincipal;
};
// JS strings we need to clean up on shutdown
static jsval sEnabledID;
@ -618,6 +629,7 @@ private:
nsCOMPtr<nsISecurityPref> mSecurityPref;
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
nsCOMPtr<nsIPrincipal> mSystemCertificate;
ContextPrincipal *mContextPrincipals;
nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
PRPackedBool mIsJavaScriptEnabled;
PRPackedBool mIsWritingPrefs;

Просмотреть файл

@ -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();

Просмотреть файл

@ -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)

Просмотреть файл

@ -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<nsIPrincipal *>(JSVAL_TO_PRIVATE(v));
}
nsCOMPtr<nsIPrincipal> 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

Просмотреть файл

@ -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<nsIPrincipal> 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)))