diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index 28cf4f60c023..837c75ab3792 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -105,7 +105,7 @@ interface nsIScriptSecurityManager : nsISupports boolean CanExecuteScripts(in nsIPrincipal principal); /** - * Return true if the given JavaScript function was compiled with + * Return true if the given JavaScript function object was compiled with * a principal that is allowed to execute scripts. */ boolean CanExecuteFunction(in voidStar jsFunction); diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index 927538214f7c..1468b7affbc9 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -39,6 +39,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIPrincipal.h" #include "jsapi.h" +#include "jsdbgapi.h" #include "nsIXPCSecurityManager.h" #include "nsHashtable.h" #include "nsDOMPropEnums.h" @@ -125,6 +126,20 @@ private: NS_IMETHOD CheckXPCPermissions(JSContext *cx); + NS_IMETHOD + GetFramePrincipal(JSContext *cx, JSStackFrame *fp, nsIPrincipal **result); + + NS_IMETHOD + GetScriptPrincipal(JSContext *cx, JSScript *script, nsIPrincipal **result); + + NS_IMETHOD + GetFunctionObjectPrincipal(JSContext *cx, JSObject *obj, + nsIPrincipal **result); + + NS_IMETHOD + GetPrincipalAndFrame(JSContext *cx, nsIPrincipal **result, + JSStackFrame **frameResult); + NS_IMETHOD InitFromPrefs(); diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 3ea5266898e7..a97ede3539fa 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -84,6 +84,23 @@ GetCurrentContext() { return cx; } +static JSContext * +GetSafeContext() { + // Get the "safe" JSContext: our JSContext of last resort + nsresult rv; + NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", + &rv); + if (NS_FAILED(rv)) + return nsnull; + nsCOMPtr tcs = do_QueryInterface(stack); + JSContext *cx; + if (NS_FAILED(tcs->GetSafeJSContext(&cx))) + return nsnull; + return cx; +} + + + static nsDOMProp findDomProp(const char *propName, int n); @@ -655,20 +672,74 @@ nsScriptSecurityManager::CanExecuteScripts(nsIPrincipal *principal, NS_IMETHODIMP -nsScriptSecurityManager::CanExecuteFunction(void *jsFunc, +nsScriptSecurityManager::CanExecuteFunction(void *jsFuncObj, PRBool *result) { - // norris TODO: figure out JSContext strategy, replace nsnulls below - // JavaScript is disabled, but we must still execute system JavaScript - JSScript *script = JS_GetFunctionScript(nsnull, (JSFunction *) jsFunc); - if (!script) - return NS_ERROR_FAILURE; - JSPrincipals *jsprin = JS_GetScriptPrincipals(nsnull, script); - if (!jsprin) - return NS_ERROR_FAILURE; - nsJSPrincipals *nsJSPrin = (nsJSPrincipals *) jsprin; + JSContext *cx = GetCurrentContext(); + if (!cx) { + cx = GetSafeContext(); + } + nsCOMPtr principal; + nsresult rv = GetFunctionObjectPrincipal(cx, (JSObject *) jsFuncObj, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) + return rv; + if (!principal) { + *result = PR_FALSE; + return NS_OK; + } + return CanExecuteScripts(principal, result); +} - return CanExecuteScripts(nsJSPrin->nsIPrincipalPtr, result); +NS_IMETHODIMP +nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx, + JSScript *script, + nsIPrincipal **result) +{ + if (!script) { + *result = nsnull; + return NS_OK; + } + JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script); + if (!jsp) { + // Script didn't have principals -- shouldn't happen. + return NS_ERROR_FAILURE; + } + nsJSPrincipals *nsJSPrin = NS_STATIC_CAST(nsJSPrincipals *, jsp); + *result = nsJSPrin->nsIPrincipalPtr; + if (!result) + return NS_ERROR_FAILURE; + NS_ADDREF(*result); + return NS_OK; + +} + +NS_IMETHODIMP +nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx, + JSObject *obj, + nsIPrincipal **result) +{ + JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, obj); + if (JS_GetFunctionObject(fun) != obj) { + // Function has been cloned; get principals from scope + return GetObjectPrincipal(cx, obj, result); + } + JSScript *script = JS_GetFunctionScript(cx, fun); + return GetScriptPrincipal(cx, script, result); +} + +NS_IMETHODIMP +nsScriptSecurityManager::GetFramePrincipal(JSContext *cx, + JSStackFrame *fp, + nsIPrincipal **result) +{ + JSObject *obj = JS_GetFrameFunctionObject(cx, fp); + if (!obj) { + // Must be in a top-level script. Get principal from the script. + JSScript *script = JS_GetFrameScript(cx, fp); + return GetScriptPrincipal(cx, script, result); + } + return GetFunctionObjectPrincipal(cx, obj, result); } @@ -685,42 +756,36 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability, *result = PR_TRUE; return NS_OK; } - while (fp) { - JSScript *script = JS_GetFrameScript(cx, fp); - if (script) { - JSPrincipals *principals = JS_GetScriptPrincipals(cx, script); - if (!principals) { - // Script didn't have principals! - return NS_ERROR_FAILURE; - } - - // First check if the principal is even able to enable the - // given capability. If not, don't look any further. - nsJSPrincipals *nsJSPrin = (nsJSPrincipals *) principals; - PRInt16 canEnable; - rv = nsJSPrin->nsIPrincipalPtr->CanEnableCapability(capability, - &canEnable); - if (NS_FAILED(rv)) - return rv; - if (canEnable != nsIPrincipal::ENABLE_GRANTED && - canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION) - { - *result = PR_FALSE; - return NS_OK; - } - - // Now see if the capability is enabled. - void *annotation = JS_GetFrameAnnotation(cx, fp); - rv = nsJSPrin->nsIPrincipalPtr->IsCapabilityEnabled(capability, - annotation, - result); - if (NS_FAILED(rv)) - return rv; - if (*result) - return NS_OK; + do { + nsCOMPtr principal; + if (NS_FAILED(GetFramePrincipal(cx, fp, getter_AddRefs(principal)))) { + return NS_ERROR_FAILURE; } - fp = JS_FrameIterator(cx, &fp); - } + if (!principal) + continue; + + // First check if the principal is even able to enable the + // given capability. If not, don't look any further. + PRInt16 canEnable; + rv = principal->CanEnableCapability(capability, &canEnable); + if (NS_FAILED(rv)) + return rv; + if (canEnable != nsIPrincipal::ENABLE_GRANTED && + canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION) + { + *result = PR_FALSE; + return NS_OK; + } + + // Now see if the capability is enabled. + void *annotation = JS_GetFrameAnnotation(cx, fp); + rv = principal->IsCapabilityEnabled(capability, annotation, + result); + if (NS_FAILED(rv)) + return rv; + if (*result) + return NS_OK; + } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull); *result = PR_FALSE; return NS_OK; } @@ -847,28 +912,21 @@ CheckConfirmDialog(const PRUnichar *szMessage, const PRUnichar *szCheckMessage, return (buttonPressed == 0); } -static nsresult -GetPrincipalAndFrame(JSContext *cx, nsIPrincipal **result, - JSStackFrame **frameResult) +NS_IMETHODIMP +nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx, + nsIPrincipal **result, + JSStackFrame **frameResult) { // Get principals from innermost frame of JavaScript or Java. JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost - fp = JS_FrameIterator(cx, &fp); - while (fp) { - JSScript *script = JS_GetFrameScript(cx, fp); - if (script) { - JSPrincipals *principals = JS_GetScriptPrincipals(cx, script); - if (!principals) { - // Script didn't have principals! - return NS_ERROR_FAILURE; - } - nsJSPrincipals *nsJSPrin = (nsJSPrincipals *) principals; - *result = nsJSPrin->nsIPrincipalPtr; - NS_ADDREF(*result); + for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp)) { + if (NS_FAILED(GetFramePrincipal(cx, fp, result))) { + return NS_ERROR_FAILURE; + } + if (*result) { *frameResult = fp; return NS_OK; } - fp = JS_FrameIterator(cx, &fp); } *result = nsnull; return NS_OK; diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 30713960684b..25bfa47155cd 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -703,11 +703,8 @@ nsJSContext::CallEventHandler(void *aTarget, void *aHandler, PRUint32 argc, if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - jsval funval = OBJECT_TO_JSVAL(aHandler); - JSFunction* fun = ::JS_ValueToFunction(mContext, funval); - PRBool ok; - rv = securityManager->CanExecuteFunction(fun, &ok); + rv = securityManager->CanExecuteFunction(aHandler, &ok); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; @@ -726,6 +723,7 @@ nsJSContext::CallEventHandler(void *aTarget, void *aHandler, PRUint32 argc, jsval val; if (ok) { + jsval funval = OBJECT_TO_JSVAL(aHandler); ok = ::JS_CallFunctionValue(mContext, (JSObject *)aTarget, funval, argc, (jsval *)argv, &val); } diff --git a/dom/src/base/nsLocation.cpp b/dom/src/base/nsLocation.cpp index 86e23e5c4e22..c6ede4b903ba 100644 --- a/dom/src/base/nsLocation.cpp +++ b/dom/src/base/nsLocation.cpp @@ -391,20 +391,23 @@ NS_IMETHODIMP LocationImpl::GetPathname(nsString& aPathname) { nsAutoString href; - nsIURI *url; + nsIURI *uri; nsresult result = NS_OK; result = GetHref(href); if (NS_OK == result) { - result = NS_NewURI(&url, href); + result = NS_NewURI(&uri, href); if (NS_OK == result) { - char* file; - result = url->GetPath(&file); - if (result == NS_OK) { - aPathname.AssignWithConversion(file); - nsCRT::free(file); + nsCOMPtr url = do_QueryInterface(uri); + if (url) { + char* file; + result = url->GetFilePath(&file); + if (result == NS_OK) { + aPathname.AssignWithConversion(file); + nsCRT::free(file); + } } - NS_IF_RELEASE(url); + NS_IF_RELEASE(uri); } } diff --git a/js/src/jsdbgapi.c b/js/src/jsdbgapi.c index 6752ab5bc963..279f546a2cf4 100644 --- a/js/src/jsdbgapi.c +++ b/js/src/jsdbgapi.c @@ -339,8 +339,23 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = wp->handler(cx, obj, js_IdToValue(sym_id(sym)), OBJ_GET_SLOT(cx, obj, wp->sprop->slot), vp, wp->closure); - if (ok) + if (ok) { + /* + * Create pseudo-frame for call to setter so that any + * stackwalking security code in the setter will correctly + * identify the guilty party. + */ + JSObject *funobj = (JSObject *) wp->closure; + JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, funobj); + JSStackFrame frame; + memset(&frame, 0, sizeof(frame)); + frame.script = fun->script; + frame.fun = fun; + frame.down = cx->fp; + cx->fp = &frame; ok = wp->setter(cx, obj, id, vp); + cx->fp = frame.down; + } DropWatchPoint(cx, wp); return ok; } @@ -644,6 +659,12 @@ JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp) return fp->fun; } +JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) +{ + return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL; +} + JS_PUBLIC_API(JSBool) JS_IsContructorFrame(JSContext *cx, JSStackFrame *fp) { diff --git a/js/src/jsdbgapi.h b/js/src/jsdbgapi.h index b350eccfd032..cb8243abe78a 100644 --- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -158,6 +158,9 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp); extern JS_PUBLIC_API(JSFunction *) JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp); +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp); + extern JS_PUBLIC_API(JSBool) JS_IsContructorFrame(JSContext *cx, JSStackFrame *fp); diff --git a/js/src/jsobj.c b/js/src/jsobj.c index f416dbccfdf6..cb780866f92a 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -2564,7 +2564,9 @@ js_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, if (!prop) { *vp = JSVAL_VOID; *attrsp = 0; - return JS_TRUE; + clasp = OBJ_GET_CLASS(cx, obj); + return !clasp->checkAccess || + clasp->checkAccess(cx, obj, id, mode, vp); } if (!OBJ_IS_NATIVE(pobj)) { OBJ_DROP_PROPERTY(cx, pobj, prop);