mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 834732 - Implement stricter cx handling in xpc_EvalInSandbox. r=mrbkap
This commit is contained in:
parent
51ba6ef50d
commit
1ffc542460
@ -3865,6 +3865,8 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
||||
JSVersion jsVersion, bool returnStringOnly, jsval *rval)
|
||||
{
|
||||
JS_AbortIfWrongThread(JS_GetRuntime(cx));
|
||||
JSAutoRequest ar(cx);
|
||||
*rval = JS::UndefinedValue();
|
||||
|
||||
bool waiveXray = xpc::WrapperFactory::HasWaiveXrayFlag(sandbox);
|
||||
sandbox = js::UnwrapObjectChecked(sandbox);
|
||||
@ -3876,10 +3878,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
||||
(nsIScriptObjectPrincipal*)xpc_GetJSPrivate(sandbox);
|
||||
NS_ASSERTION(sop, "Invalid sandbox passed");
|
||||
nsCOMPtr<nsIPrincipal> prin = sop->GetPrincipal();
|
||||
|
||||
if (!prin) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoCString filenameBuf;
|
||||
if (!filename) {
|
||||
@ -3889,114 +3888,81 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
||||
lineNo = 1;
|
||||
}
|
||||
|
||||
JSObject *callingScope;
|
||||
// We create a separate cx to do the sandbox evaluation. Scope it.
|
||||
JS::Value v = JS::UndefinedValue();
|
||||
JS::Value exn = JS::UndefinedValue();
|
||||
bool ok = true;
|
||||
{
|
||||
JSAutoRequest req(cx);
|
||||
|
||||
callingScope = JS_GetGlobalForScopeChain(cx);
|
||||
if (!callingScope) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<ContextHolder> sandcx = new ContextHolder(cx, sandbox, prin);
|
||||
if (!sandcx || !sandcx->GetJSContext()) {
|
||||
// Make a special cx for the sandbox and push it.
|
||||
// NB: As soon as the RefPtr goes away, the cx goes away. So declare
|
||||
// it first so that it disappears last.
|
||||
nsRefPtr<ContextHolder> sandcxHolder = new ContextHolder(cx, sandbox, prin);
|
||||
JSContext *sandcx = sandcxHolder->GetJSContext();
|
||||
if (!sandcx) {
|
||||
JS_ReportError(cx, "Can't prepare context for evalInSandbox");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
nsCxPusher pusher;
|
||||
pusher.Push(sandcx);
|
||||
|
||||
JSAutoRequest req(sandcx);
|
||||
JSAutoCompartment ac(sandcx, sandbox);
|
||||
|
||||
if (jsVersion != JSVERSION_DEFAULT)
|
||||
JS_SetVersion(sandcx->GetJSContext(), jsVersion);
|
||||
JS_SetVersion(sandcx, jsVersion);
|
||||
|
||||
XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack();
|
||||
MOZ_ASSERT(stack);
|
||||
if (!stack->Push(sandcx->GetJSContext())) {
|
||||
JS_ReportError(cx, "Unable to initialize XPConnect with the sandbox context");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
{
|
||||
JSAutoRequest req(sandcx->GetJSContext());
|
||||
JSAutoCompartment ac(sandcx->GetJSContext(), sandbox);
|
||||
|
||||
jsval v;
|
||||
JSString *str = nullptr;
|
||||
JS::CompileOptions options(sandcx->GetJSContext());
|
||||
JS::CompileOptions options(sandcx);
|
||||
options.setPrincipals(nsJSPrincipals::get(prin))
|
||||
.setFileAndLine(filename, lineNo);
|
||||
js::RootedObject rootedSandbox(sandcx->GetJSContext(), sandbox);
|
||||
bool ok = JS::Evaluate(sandcx->GetJSContext(), rootedSandbox, options,
|
||||
js::RootedObject rootedSandbox(sandcx, sandbox);
|
||||
ok = JS::Evaluate(sandcx, rootedSandbox, options,
|
||||
PromiseFlatString(source).get(), source.Length(), &v);
|
||||
if (ok && returnStringOnly && !(JSVAL_IS_VOID(v))) {
|
||||
ok = !!(str = JS_ValueToString(sandcx->GetJSContext(), v));
|
||||
JSString *str = JS_ValueToString(sandcx, v);
|
||||
ok = !!str;
|
||||
v = ok ? JS::StringValue(str) : JS::UndefinedValue();
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// The sandbox threw an exception, convert it to a string (if
|
||||
// asked) or convert it to a SJOW.
|
||||
|
||||
jsval exn;
|
||||
if (JS_GetPendingException(sandcx->GetJSContext(), &exn)) {
|
||||
JS_ClearPendingException(sandcx->GetJSContext());
|
||||
|
||||
// If the sandbox threw an exception, grab it off the context.
|
||||
if (JS_GetPendingException(sandcx, &exn)) {
|
||||
MOZ_ASSERT(!ok);
|
||||
JS_ClearPendingException(sandcx);
|
||||
if (returnStringOnly) {
|
||||
// The caller asked for strings only, convert the
|
||||
// exception into a string.
|
||||
str = JS_ValueToString(sandcx->GetJSContext(), exn);
|
||||
JSString *str = JS_ValueToString(sandcx, exn);
|
||||
exn = str ? JS::StringValue(str) : JS::UndefinedValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str) {
|
||||
// We converted the exception to a string. Use that
|
||||
// as the value exception.
|
||||
exn = STRING_TO_JSVAL(str);
|
||||
if (JS_WrapValue(cx, &exn)) {
|
||||
//
|
||||
// Alright, we're back on the caller's cx. If an error occured, try to
|
||||
// wrap and set the exception. Otherwise, wrap the return value.
|
||||
//
|
||||
|
||||
if (!ok) {
|
||||
// If we end up without an exception, it was probably due to OOM along
|
||||
// the way, in which case we thow. Otherwise, wrap it.
|
||||
if (exn.isUndefined() || !JS_WrapValue(cx, &exn))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Set the exception on our caller's cx.
|
||||
JS_SetPendingException(cx, exn);
|
||||
} else {
|
||||
JS_ClearPendingException(cx);
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
JS_ClearPendingException(cx);
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (JS_WrapValue(cx, &exn)) {
|
||||
JS_SetPendingException(cx, exn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clear str so we don't confuse callers.
|
||||
str = nullptr;
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
// Convert the result into something safe for our caller.
|
||||
JSAutoRequest req(cx);
|
||||
JSAutoCompartment ac(cx, callingScope);
|
||||
|
||||
if (str) {
|
||||
v = STRING_TO_JSVAL(str);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Transitively apply Xray waivers if |sb| was waived.
|
||||
if (waiveXray && !xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
if (!waiveXray && !JS_WrapValue(cx, &v))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
if (waiveXray) {
|
||||
ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
|
||||
} else {
|
||||
ok = JS_WrapValue(cx, &v);
|
||||
}
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Whew!
|
||||
*rval = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack)
|
||||
unused << stack->Pop();
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* JSObject import (in AUTF8String registryLocation,
|
||||
|
Loading…
Reference in New Issue
Block a user