Bug 1740263 - Block WASM code generation by CSP. r=lth,jandem

I put the CSP check in the 5 WASM function that V8 also uses: https://source.chromium.org/search?q=IsWasmCodegenAllowed
Is there somewhere else we might be generating WASM code? Some kind of caching etc.

Differential Revision: https://phabricator.services.mozilla.com/D141978
This commit is contained in:
Tom Schuster 2022-05-18 21:39:28 +00:00
Родитель f13a5edf0d
Коммит f05c922e89
8 изменённых файлов: 59 добавлений и 7 удалений

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

@ -66,11 +66,22 @@ extern JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx,
// engine when determining, e.g., which stack frames to display in a backtrace.
typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second);
namespace JS {
enum class RuntimeCode { JS, WASM };
} // namespace JS
/*
* Used to check if a CSP instance wants to disable eval() and friends.
* See JSContext::isRuntimeCodeGenEnabled() in vm/JSContext.cpp.
*
* `code` is the JavaScript source code passed to eval/Function, but nullptr
* for Wasm.
*
* Returning `false` from this callback will prevent the execution/compilation
* of the code.
*/
typedef bool (*JSCSPEvalChecker)(JSContext* cx, JS::HandleString code);
typedef bool (*JSCSPEvalChecker)(JSContext* cx, JS::RuntimeCode kind,
JS::HandleString code);
struct JSSecurityCallbacks {
JSCSPEvalChecker contentSecurityPolicyAllows;

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

@ -180,6 +180,7 @@ MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS, 0, JSEXN_RANGEERR, "too many arguments pr
// CSP
MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_EVALERR, "call to eval() blocked by CSP")
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_EVALERR, "call to Function() blocked by CSP")
MSG_DEF(JSMSG_CSP_BLOCKED_WASM, 1, JSEXN_WASMCOMPILEERROR, "call to {0}() blocked by CSP")
// Wrappers
MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}")

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

@ -238,7 +238,7 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
// Steps 3-4.
RootedString str(cx, v.toString());
if (!cx->isRuntimeCodeGenEnabled(str)) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, str)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_EVAL);
return false;

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

@ -1188,12 +1188,13 @@ bool JSContext::isThrowingDebuggeeWouldRun() {
JSEXN_DEBUGGEEWOULDRUN;
}
bool JSContext::isRuntimeCodeGenEnabled(HandleString code) {
bool JSContext::isRuntimeCodeGenEnabled(JS::RuntimeCode kind,
HandleString code) {
// Make sure that the CSP callback is installed and that it permits runtime
// code generation.
if (JSCSPEvalChecker allows =
runtime()->securityCallbacks->contentSecurityPolicyAllows) {
return allows(this, code);
return allows(this, kind, code);
}
return true;

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

@ -819,8 +819,8 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
inline bool runningWithTrustedPrincipals();
// Checks if the page's Content-Security-Policy (CSP) allows
// runtime code generation "unsafe-eval".
bool isRuntimeCodeGenEnabled(js::HandleString code);
// runtime code generation "unsafe-eval", or "wasm-unsafe-eval" for Wasm.
bool isRuntimeCodeGenEnabled(JS::RuntimeCode kind, js::HandleString code);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

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

@ -1621,7 +1621,7 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
}
// Block this call if security callbacks forbid it.
if (!cx->isRuntimeCodeGenEnabled(functionText)) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, functionText)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_FUNCTION);
return false;

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

@ -1796,6 +1796,12 @@ bool WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.Module");
return false;
}
if (!callArgs.requireAtLeast(cx, "WebAssembly.Module", 1)) {
return false;
}
@ -4729,6 +4735,12 @@ static bool WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) {
CallArgs callArgs = CallArgsFromVp(argc, vp);
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.compile");
return RejectWithPendingException(cx, promise, callArgs);
}
auto task = cx->make_unique<CompileBufferTask>(cx, promise);
if (!task || !task->init(cx, callArgs.get(1), "WebAssembly.compile")) {
return false;
@ -4790,6 +4802,13 @@ static bool WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
} else {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.instantiate");
return RejectWithPendingException(cx, promise, callArgs);
}
auto task = cx->make_unique<CompileBufferTask>(cx, promise, importObj);
if (!task || !task->init(cx, callArgs.get(2), "WebAssembly.instantiate")) {
return false;
@ -5361,6 +5380,13 @@ static bool WebAssembly_compileStreaming(JSContext* cx, unsigned argc,
CallArgs callArgs = CallArgsFromVp(argc, vp);
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.compileStreaming");
return RejectWithPendingException(cx, promise, callArgs);
}
if (!ResolveResponse(cx, callArgs, promise)) {
return RejectWithPendingException(cx, promise, callArgs);
}
@ -5384,6 +5410,13 @@ static bool WebAssembly_instantiateStreaming(JSContext* cx, unsigned argc,
CallArgs callArgs = CallArgsFromVp(argc, vp);
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.instantiateStreaming");
return RejectWithPendingException(cx, promise, callArgs);
}
RootedObject firstArg(cx);
RootedObject importObj(cx);
if (!GetInstantiateArgs(cx, callArgs, &firstArg, &importObj)) {

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

@ -265,6 +265,12 @@ JSObject* Module::createObject(JSContext* cx) const {
return nullptr;
}
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.Module");
return nullptr;
}
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule));
return WasmModuleObject::create(cx, *this, proto);
}