From 6f39df51bcfdc6745a2fbdcc408053eeb566c94d Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Thu, 17 Apr 2003 20:21:00 +0000 Subject: [PATCH] Fixing bug 201132. Always use the JSPrincipals from the target object when compiling event handlers, never use the principals of the global object in which the event handler is compiled. Also make sure we never use the principals that are precompiled into cloned Functions, always get the principal from the Function's scope in such cases. r=mstoltz@netscape.com (and heikki@netscape.com), sr=brendan@mozilla.org git-svn-id: svn://10.0.0.236/trunk@141333 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/caps/src/nsScriptSecurityManager.cpp | 47 +++++++++++--- mozilla/dom/src/base/nsJSEnvironment.cpp | 65 ++++++++++++-------- mozilla/dom/src/base/nsJSEnvironment.h | 1 - 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/mozilla/caps/src/nsScriptSecurityManager.cpp b/mozilla/caps/src/nsScriptSecurityManager.cpp index 69675c257c3..c32f40e90dc 100644 --- a/mozilla/caps/src/nsScriptSecurityManager.cpp +++ b/mozilla/caps/src/nsScriptSecurityManager.cpp @@ -1386,8 +1386,20 @@ nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj, getter_AddRefs(subject)); //-- If subject is null, get a principal from the function object's scope. if (NS_SUCCEEDED(rv) && !subject) + { +#ifdef DEBUG + { + JSFunction *fun = + (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj); + JSScript *script = JS_GetFunctionScript(aCx, fun); + + NS_ASSERTION(!script, "Null principal for non-native function!"); + } +#endif + rv = doGetObjectPrincipal(aCx, (JSObject*)aFunObj, getter_AddRefs(subject)); + } if (NS_FAILED(rv)) return rv; if (!subject) return NS_ERROR_FAILURE; @@ -1811,16 +1823,20 @@ nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx, nsCOMPtr scriptPrincipal; if (script) - if (NS_FAILED(GetScriptPrincipal(cx, script, getter_AddRefs(scriptPrincipal)))) + { + if (JS_GetFunctionObject(fun) != obj) + { + // Function is a clone, its prototype was precompiled from + // brutally shared chrome. For this case only, get the + // principals from the clone's scope since there's no + // reliable principals compiled into the function. + return doGetObjectPrincipal(cx, obj, result); + } + + if (NS_FAILED(GetScriptPrincipal(cx, script, + getter_AddRefs(scriptPrincipal)))) return NS_ERROR_FAILURE; - if (script && (JS_GetFunctionObject(fun) != obj) && - (scriptPrincipal.get() == mSystemPrincipal)) - { - // Function is brutally-shared chrome. For this case only, - // get a principal from the object's scope instead of the - // principal compiled into the function. - return doGetObjectPrincipal(cx, obj, result); } *result = scriptPrincipal.get(); @@ -1840,7 +1856,20 @@ nsScriptSecurityManager::GetFramePrincipal(JSContext *cx, JSScript *script = JS_GetFrameScript(cx, fp); return GetScriptPrincipal(cx, script, result); } - return GetFunctionObjectPrincipal(cx, obj, result); + + nsresult rv = GetFunctionObjectPrincipal(cx, obj, result); + +#ifdef DEBUG + if (NS_SUCCEEDED(rv) && !*result) + { + JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj); + JSScript *script = JS_GetFunctionScript(cx, fun); + + NS_ASSERTION(!script, "Null principal for non-native function!"); + } +#endif + + return rv; } nsresult diff --git a/mozilla/dom/src/base/nsJSEnvironment.cpp b/mozilla/dom/src/base/nsJSEnvironment.cpp index b80c3d809f2..6dbf208a499 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.cpp +++ b/mozilla/dom/src/base/nsJSEnvironment.cpp @@ -120,6 +120,7 @@ static PRBool sDidShutdown = PR_FALSE; static PRInt32 sContextCount = 0; +static nsIScriptSecurityManager *sSecurityManager = nsnull; void JS_DLL_CALLBACK NS_ScriptErrorReporter(JSContext *cx, @@ -436,8 +437,6 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE) nsJSContext::~nsJSContext() { - mSecurityManager = nsnull; // Force release - // Cope with JS_NewContext failure in ctor (XXXbe move NewContext to Init?) if (!mContext) return; @@ -469,9 +468,12 @@ nsJSContext::~nsJSContext() if (!sContextCount && sDidShutdown) { // The last context is being deleted, and we're already in the - // process of shutting down, release the JS runtime service. + // process of shutting down, release the JS runtime service, and + // the security manager. NS_IF_RELEASE(sRuntimeService); + + NS_IF_RELEASE(sSecurityManager); } } @@ -930,25 +932,35 @@ nsJSContext::CompileEventHandler(void *aTarget, nsIAtom *aName, const nsAString& aBody, PRBool aShared, void** aHandler) { + if (!sSecurityManager) { + NS_ERROR("Huh, we need a script security manager to compile " + "an event handler!"); + + return NS_ERROR_UNEXPECTED; + } + + JSObject *target = (JSObject*)aTarget; + JSPrincipals *jsprin = nsnull; - nsCOMPtr global; - GetGlobalObject(getter_AddRefs(global)); - if (global) { - // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func? - nsCOMPtr globalData = do_QueryInterface(global); - if (globalData) { - nsCOMPtr prin; - if (NS_FAILED(globalData->GetPrincipal(getter_AddRefs(prin)))) - return NS_ERROR_FAILURE; - prin->GetJSPrincipals(&jsprin); - } + if (target) { + // Get the principal of the event target (the object principal), + // don't get the principal of the global object in this context + // since that opens up security exploits with delayed event + // handler compilation on stale DOM objects (objects that live in + // a document that has already been unloaded). + nsCOMPtr prin; + nsresult rv = sSecurityManager->GetObjectPrincipal(mContext, target, + getter_AddRefs(prin)); + NS_ENSURE_SUCCESS(rv, rv); + + prin->GetJSPrincipals(&jsprin); + NS_ENSURE_TRUE(jsprin, NS_ERROR_NOT_AVAILABLE); } char charName[64]; AtomToEventHandlerName(aName, charName, sizeof charName); - JSObject *target = (JSObject*)aTarget; JSFunction* fun = ::JS_CompileUCFunctionForPrincipals(mContext, target, jsprin, charName, 1, gEventArgv, @@ -957,10 +969,12 @@ nsJSContext::CompileEventHandler(void *aTarget, nsIAtom *aName, //XXXbe filename, lineno: nsnull, 0); - if (jsprin) + if (jsprin) { JSPRINCIPALS_DROP(mContext, jsprin); - if (!fun) + } + if (!fun) { return NS_ERROR_FAILURE; + } JSObject *handler = ::JS_GetFunctionObject(fun); if (aHandler) @@ -1522,14 +1536,12 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated) NS_IMETHODIMP nsJSContext::GetSecurityManager(nsIScriptSecurityManager **aInstancePtr) { - if (!mSecurityManager) { - nsresult rv = NS_OK; + *aInstancePtr = sSecurityManager; - mSecurityManager = do_GetService(kScriptSecurityManagerContractID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (!sSecurityManager) { + return NS_ERROR_NOT_AVAILABLE; } - *aInstancePtr = mSecurityManager; NS_ADDREF(*aInstancePtr); return NS_OK; @@ -1679,9 +1691,7 @@ nsresult nsJSEnvironment::Init() return NS_OK; } - nsresult rv = nsServiceManager::GetService(kJSRuntimeServiceContractID, - NS_GET_IID(nsIJSRuntimeService), - (nsISupports**)&sRuntimeService); + nsresult rv = CallGetService(kJSRuntimeServiceContractID, &sRuntimeService); // get the JSRuntime from the runtime svc, if possible NS_ENSURE_SUCCESS(rv, rv); @@ -1732,6 +1742,8 @@ nsresult nsJSEnvironment::Init() } #endif /* OJI */ + rv = CallGetService(kScriptSecurityManagerContractID, &sSecurityManager); + isInitialized = NS_SUCCEEDED(rv); return rv; @@ -1754,9 +1766,10 @@ void nsJSEnvironment::ShutDown() if (!sContextCount) { // We're being shutdown, and there are no more contexts - // alive, release the JS runtime service. + // alive, release the JS runtime service and the security manager. NS_IF_RELEASE(sRuntimeService); + NS_IF_RELEASE(sSecurityManager); } sDidShutdown = PR_TRUE; diff --git a/mozilla/dom/src/base/nsJSEnvironment.h b/mozilla/dom/src/base/nsJSEnvironment.h index 7a3be515315..fb76255dc50 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.h +++ b/mozilla/dom/src/base/nsJSEnvironment.h @@ -144,7 +144,6 @@ private: JSContext *mContext; PRUint32 mNumEvaluations; - nsCOMPtr mSecurityManager; // [OWNER] nsIScriptContextOwner* mOwner; /* NB: weak reference, not ADDREF'd */ nsScriptTerminationFunc mTerminationFunc;