Fixing bug 202994. Make sure the proper security check is done when converting the result of a JS expression in a javascript: URL to a string. r=mstoltz@netscape.com, sr=brendan@mozilla.org, a=asa@mozilla.org

This commit is contained in:
jst%netscape.com 2003-05-12 22:23:52 +00:00
parent 148c24f654
commit 72ec343461
4 changed files with 103 additions and 43 deletions

View File

@ -2047,7 +2047,7 @@ nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
///////////////// Capabilities API /////////////////////
NS_IMETHODIMP
nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
PRBool *result)
PRBool *result)
{
nsresult rv;
JSStackFrame *fp = nsnull;
@ -2097,9 +2097,12 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
if (!previousPrincipal)
{
// No principals on the stack, all native code. Allow execution.
*result = PR_TRUE;
// No principals on the stack, all native code. Allow
// execution if the subject principal is the system principal.
return SubjectPrincipalIsSystem(result);
}
return NS_OK;
}

View File

@ -617,6 +617,61 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
}
// Helper function to convert a jsval to an nsAString, and set
// exception flags if the conversion fails.
static nsresult
JSValueToAString(JSContext *cx, jsval val, nsAString *result,
PRBool *isUndefined)
{
if (isUndefined) {
*isUndefined = JSVAL_IS_VOID(val);
}
if (!result) {
return NS_OK;
}
JSString* jsstring = ::JS_ValueToString(cx, val);
if (jsstring) {
result->Assign(NS_REINTERPRET_CAST(const PRUnichar*,
::JS_GetStringChars(jsstring)),
::JS_GetStringLength(jsstring));
} else {
result->Truncate();
// We failed to convert val to a string. We're either OOM, or the
// security manager denied access to .toString(), or somesuch, on
// an object. Treat this case as if the result were undefined.
if (isUndefined) {
*isUndefined = PR_TRUE;
}
if (!::JS_IsExceptionPending(cx)) {
// JS_ValueToString() returned null w/o an exception
// pending. That means we're OOM.
return NS_ERROR_OUT_OF_MEMORY;
}
// We've got a pending exception. Tell XPConnect's current native
// call context (if any) about this exception so that it doesn't
// keep going as if nothing happened.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
if (xpc) {
nsCOMPtr<nsIXPCNativeCallContext> nccx;
xpc->GetCurrentNativeCallContext(getter_AddRefs(nccx));
if (nccx) {
nccx->SetExceptionWasThrown(PR_TRUE);
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsJSContext::EvaluateString(const nsAString& aScript,
void *aScopeObject,
@ -720,18 +775,7 @@ nsJSContext::EvaluateString(const nsAString& aScript,
// If all went well, convert val to a string (XXXbe unless undefined?).
if (ok) {
if (aIsUndefined) {
*aIsUndefined = JSVAL_IS_VOID(val);
}
JSString* jsstring = ::JS_ValueToString(mContext, val);
if (jsstring) {
aRetValue.Assign(NS_REINTERPRET_CAST(const PRUnichar*,
::JS_GetStringChars(jsstring)),
::JS_GetStringLength(jsstring));
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
rv = JSValueToAString(mContext, val, &aRetValue, aIsUndefined);
}
else {
if (aIsUndefined) {
@ -869,20 +913,8 @@ nsJSContext::ExecuteScript(void* aScriptObject,
if (ok) {
// If all went well, convert val to a string (XXXbe unless undefined?).
if (aIsUndefined) {
*aIsUndefined = JSVAL_IS_VOID(val);
}
if (aRetValue) {
JSString* jsstring = ::JS_ValueToString(mContext, val);
if (jsstring) {
aRetValue->Assign(NS_REINTERPRET_CAST(const PRUnichar*,
::JS_GetStringChars(jsstring)),
::JS_GetStringLength(jsstring));
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
} else {
if (aIsUndefined) {
*aIsUndefined = PR_TRUE;

View File

@ -233,8 +233,8 @@ nsDOMSOFactory::Observe(nsISupports *aSubject,
#ifdef MOZ_XUL
// Flush the XUL cache since it holds JS roots, and we're about to
// start the final GC.
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
nsCOMPtr<nsIXULPrototypeCache> cache(do_GetService(kXULPrototypeCacheCID));
nsCOMPtr<nsIXULPrototypeCache> cache =
do_GetService("@mozilla.org/xul/xul-prototype-cache;1");
if (cache)
cache->Flush();

View File

@ -66,6 +66,7 @@
#include "nsXPIDLString.h"
#include "prprf.h"
#include "nsEscape.h"
#include "nsIJSContextStack.h"
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
@ -157,6 +158,8 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel)
return NS_ERROR_FAILURE;
}
JSObject *globalJSObject = global->GetGlobalJSObject();
nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(global, &rv));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
@ -174,7 +177,6 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel)
// if necessary. So, basically, this call ensures that a document gets
// created -- if necessary.
nsCOMPtr<nsIDOMDocument> doc;
rv = domWindow->GetDocument(getter_AddRefs(doc));
NS_ASSERTION(doc, "No DOMDocument!");
if (NS_FAILED(rv)) {
@ -188,6 +190,31 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel)
if (!scriptContext) return NS_ERROR_FAILURE;
// Grab a context to evaluate the javascript: URL on. If the
// evaluation of a javascript: URL is caused by some running
// script, use the context of the running script. If no JS is
// running, use the context of the window where the javascript:
// URL is being evaluated.
nsCOMPtr<nsIScriptContext> evalContext;
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (stack) {
JSContext *cx;
if (NS_SUCCEEDED(stack->Peek(&cx)) && cx &&
(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
nsISupports *supports =
NS_STATIC_CAST(nsISupports*, ::JS_GetContextPrivate(cx));
evalContext = do_QueryInterface(supports);
}
}
if (!evalContext) {
// No JS on the stack, use the window's context.
evalContext = scriptContext;
}
// Unescape the script
NS_UnescapeURL(script);
@ -221,7 +248,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel)
nsCOMPtr<nsIPrincipal> objectPrincipal;
rv = securityManager->GetObjectPrincipal(
(JSContext*)scriptContext->GetNativeContext(),
global->GetGlobalJSObject(),
globalJSObject,
getter_AddRefs(objectPrincipal));
if (NS_FAILED(rv))
return rv;
@ -267,17 +294,15 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel)
// Finally, we have everything needed to evaluate the expression.
nsString result;
PRBool bIsUndefined;
{
NS_ConvertUTF8toUCS2 scriptString(script);
rv = scriptContext->EvaluateString(scriptString,
nsnull, // obj
principal,
url.get(), // url
1, // line no
nsnull,
result,
&bIsUndefined);
}
rv = evalContext->EvaluateString(NS_ConvertUTF8toUCS2(script),
globalJSObject, // obj
principal,
url.get(), // url
1, // line no
nsnull,
result,
&bIsUndefined);
if (NS_FAILED(rv)) {
rv = NS_ERROR_MALFORMED_URI;