Backed out 3 changesets (bug 1905239) for causing build bustages @ FrontendContext.cpp CLOSED TREE

Backed out changeset 029305d7a99b (bug 1905239)
Backed out changeset a282ae3a55f7 (bug 1905239)
Backed out changeset f27e56ebfc0b (bug 1905239)
This commit is contained in:
Alexandru Marc
2024-12-11 12:16:57 +02:00
parent 34faf9734d
commit 2e177dcfbb
15 changed files with 49 additions and 508 deletions

View File

@@ -73,8 +73,6 @@
#include "nsJSUtils.h"
#include "nsILoadInfo.h"
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
#include "js/GCVector.h"
#include "js/Value.h"
// This should be probably defined on some other place... but I couldn't find it
#define WEBAPPS_PERM_NAME "webapps-manage"
@@ -464,12 +462,7 @@ NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager)
///////////////// Security Checks /////////////////
bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
JSContext* cx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
JS::CompilationType aCompilationType,
JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
JS::Handle<JSString*> aBodyString,
JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
JSContext* cx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCode) {
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
@@ -484,14 +477,13 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
if (contextForbidsEval) {
nsAutoJSString scriptSample;
if (aKind == JS::RuntimeCode::JS &&
NS_WARN_IF(!scriptSample.init(cx, aCodeString))) {
NS_WARN_IF(!scriptSample.init(cx, aCode))) {
return false;
}
if (!nsContentSecurityUtils::IsEvalAllowed(
cx, subjectPrincipal->IsSystemPrincipal(), scriptSample)) {
*aOutCanCompileStrings = false;
return true;
return false;
}
}
@@ -511,7 +503,6 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
}
// don't do anything unless there's a CSP
if (!csp) {
*aOutCanCompileStrings = true;
return true;
}
}
@@ -531,8 +522,7 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
nsresult rv = csp->GetAllowsEval(&reportViolation, &evalOK);
if (NS_FAILED(rv)) {
NS_WARNING("CSP: failed to get allowsEval");
*aOutCanCompileStrings = true; // fail open to not break sites.
return true;
return true; // fail open to not break sites.
}
} else {
if (NS_FAILED(csp->GetAllowsWasmEval(&reportViolation, &evalOK))) {
@@ -555,7 +545,8 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
auto caller = JSCallingLocation::Get(cx);
nsAutoJSString scriptSample;
if (aKind == JS::RuntimeCode::JS &&
NS_WARN_IF(!scriptSample.init(cx, aCodeString))) {
NS_WARN_IF(!scriptSample.init(cx, aCode))) {
JS_ClearPendingException(cx);
return false;
}
uint16_t violationType =
@@ -568,8 +559,7 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
caller.mLine, caller.mColumn, u""_ns, u""_ns);
}
*aOutCanCompileStrings = evalOK;
return true;
return evalOK;
}
// static
@@ -1564,7 +1554,6 @@ void nsScriptSecurityManager::InitJSCallbacks(JSContext* aCx) {
static const JSSecurityCallbacks securityCallbacks = {
ContentSecurityPolicyPermitsJSAction,
nullptr, // codeForEvalGets
JSPrincipalsSubsume,
};

View File

@@ -28,14 +28,17 @@ class SystemPrincipal;
namespace JS {
enum class RuntimeCode;
enum class CompilationType;
} // namespace JS
/////////////////////////////
// nsScriptSecurityManager //
/////////////////////////////
#define NS_SCRIPTSECURITYMANAGER_CID \
{0x7ee2a4c0, 0x4b93, 0x17d3, {0xba, 0x18, 0x00, 0x60, 0xb0, 0xf1, 0x99, 0xa2}}
#define NS_SCRIPTSECURITYMANAGER_CID \
{ \
0x7ee2a4c0, 0x4b93, 0x17d3, { \
0xba, 0x18, 0x00, 0x60, 0xb0, 0xf1, 0x99, 0xa2 \
} \
}
class nsScriptSecurityManager final : public nsIScriptSecurityManager {
public:
@@ -88,13 +91,9 @@ class nsScriptSecurityManager final : public nsIScriptSecurityManager {
virtual ~nsScriptSecurityManager();
// Decides, based on CSP, whether or not eval() and stuff can be executed.
static bool ContentSecurityPolicyPermitsJSAction(
JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
JS::CompilationType aCompilationType,
JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
JS::Handle<JSString*> aBodyString,
JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings);
static bool ContentSecurityPolicyPermitsJSAction(JSContext* cx,
JS::RuntimeCode kind,
JS::Handle<JSString*> aCode);
static bool JSPrincipalsSubsume(JSPrincipals* first, JSPrincipals* second);

View File

@@ -26,10 +26,8 @@
#include "jsfriendapi.h"
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/ContextOptions.h"
#include "js/GCVector.h"
#include "js/Initialization.h"
#include "js/LocaleSensitive.h"
#include "js/Value.h"
#include "js/WasmFeatures.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Atomics.h"
@@ -501,13 +499,8 @@ class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable {
~LogViolationDetailsRunnable() = default;
};
bool ContentSecurityPolicyAllows(
JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
JS::CompilationType aCompilationType,
JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
JS::Handle<JSString*> aBodyString,
JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
bool ContentSecurityPolicyAllows(JSContext* aCx, JS::RuntimeCode aKind,
JS::Handle<JSString*> aCode) {
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
worker->AssertIsOnWorkerThread();
@@ -516,14 +509,14 @@ bool ContentSecurityPolicyAllows(
uint16_t violationType;
nsAutoJSString scriptSample;
if (aKind == JS::RuntimeCode::JS) {
if (NS_WARN_IF(!scriptSample.init(aCx, aCodeString))) {
if (NS_WARN_IF(!scriptSample.init(aCx, aCode))) {
JS_ClearPendingException(aCx);
return false;
}
if (!nsContentSecurityUtils::IsEvalAllowed(
aCx, worker->UsesSystemPrincipal(), scriptSample)) {
*aOutCanCompileStrings = false;
return true;
return false;
}
evalOK = worker->IsEvalAllowed();
@@ -549,8 +542,7 @@ bool ContentSecurityPolicyAllows(
}
}
*aOutCanCompileStrings = evalOK;
return true;
return evalOK;
}
void CTypesActivityCallback(JSContext* aCx, JS::CTypesActivityType aType) {
@@ -1554,7 +1546,7 @@ class DumpCrashInfoRunnable final : public WorkerControlRunnable {
};
struct ActiveWorkerStats {
template <uint32_t ActiveWorkerStats::* Category>
template <uint32_t ActiveWorkerStats::*Category>
void Update(const nsTArray<WorkerPrivate*>& aWorkers) {
for (const auto worker : aWorkers) {
RefPtr<DumpCrashInfoRunnable> runnable =

View File

@@ -77,54 +77,23 @@ typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second);
namespace JS {
enum class RuntimeCode { JS, WASM };
enum class CompilationType { DirectEval, IndirectEval, Function, Undefined };
} // namespace JS
/*
* Used to check if a CSP instance wants to disable eval() and friends.
* See JSContext::isRuntimeCodeGenEnabled() in vm/JSContext.cpp.
*
* codeString, compilationType, parameterStrings, bodyString, parameterArgs,
* and bodyArg are defined in the "Dynamic Code Brand Checks" spec
* (see https://tc39.es/proposal-dynamic-code-brand-checks).
* `code` is the JavaScript source code passed to eval/Function, but nullptr
* for Wasm.
*
* An Undefined compilationType is used for cases that are not covered by that
* spec and unused parameters are null/empty. Currently, this includes Wasm
* (only check if compilation is enabled) and ShadowRealmEval (only check
* codeString).
*
* `outCanCompileStrings` is set to false if this callback prevents the
* execution/compilation of the code and to true otherwise.
*
* Return false on failure, true on success. The |outCanCompileStrings|
* parameter should not be modified in case of failure.
* Returning `false` from this callback will prevent the execution/compilation
* of the code.
*/
typedef bool (*JSCSPEvalChecker)(
JSContext* cx, JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
JS::CompilationType compilationType,
JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
JS::Handle<JSString*> bodyString,
JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings);
/*
* Provide a string of code from an Object argument, to be used by eval.
* See JSContext::getCodeForEval() in vm/JSContext.cpp as well as
* https://tc39.es/proposal-dynamic-code-brand-checks/#sec-hostgetcodeforeval
*
* `code` is the JavaScript object passed by the user.
* `outCode` is the JavaScript string to be actually executed, with nullptr
* meaning NO-CODE.
*
* Return false on failure, true on success. The |outCode| parameter should not
* be modified in case of failure.
*/
typedef bool (*JSCodeForEvalOp)(JSContext* cx, JS::HandleObject code,
JS::MutableHandle<JSString*> outCode);
typedef bool (*JSCSPEvalChecker)(JSContext* cx, JS::RuntimeCode kind,
JS::HandleString code);
struct JSSecurityCallbacks {
JSCSPEvalChecker contentSecurityPolicyAllows;
JSCodeForEvalOp codeForEvalGets;
JSSubsumesOp subsumes;
};

View File

@@ -239,41 +239,21 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
env->is<GlobalLexicalEnvironmentObject>());
AssertInnerizedEnvironmentChain(cx, *env);
// "Dynamic Code Brand Checks" adds support for Object values.
// https://tc39.es/proposal-dynamic-code-brand-checks/#sec-performeval
// Steps 2-4.
RootedString str(cx);
if (v.isString()) {
str = v.toString();
} else if (v.isObject()) {
RootedObject obj(cx, &v.toObject());
if (!cx->getCodeForEval(obj, &str)) {
return false;
}
}
if (!str) {
// Step 2.
if (!v.isString()) {
vp.set(v);
return true;
}
// Steps 6-8.
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(
JS::RuntimeCode::JS, str,
evalType == DIRECT_EVAL ? JS::CompilationType::DirectEval
: JS::CompilationType::IndirectEval,
parameterStrings, str, parameterArgs, v, &canCompileStrings)) {
return false;
}
if (!canCompileStrings) {
// Steps 3-4.
RootedString str(cx, v.toString());
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, str)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_EVAL);
return false;
}
// Step 9 ff.
// Step 5 ff.
// Per ES5, indirect eval runs in the global scope. (eval is specified this
// way so that the compiler can make assumptions about what bindings may or

View File

@@ -196,16 +196,7 @@ static bool PerformShadowRealmEval(JSContext* cx, Handle<JSString*> sourceText,
MOZ_ASSERT(callerRealm != evalRealm);
// Step 1. Perform ? HostEnsureCanCompileStrings(callerRealm, evalRealm).
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, sourceText,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return false;
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, sourceText)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_SHADOWREALM);
return false;

View File

@@ -40,7 +40,6 @@ UNIFIED_SOURCES += [
"testDeflateStringToUTF8Buffer.cpp",
"testDeleteProperty.cpp",
"testDifferentNewTargetInvokeConstructor.cpp",
"testDynamicCodeBrandChecks.cpp",
"testEmptyWindowIsOmitted.cpp",
"testErrorCopying.cpp",
"testErrorLineOfContext.cpp",

View File

@@ -1,269 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
*
* Tests that the column number of error reports is properly copied over from
* other reports when invoked from the C++ api.
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi-tests/tests.h"
BEGIN_TEST(testDynamicCodeBrandChecks_DefaultHostGetCodeForEval) {
JS::RootedValue v(cx);
// String arguments are evaluated.
EVAL("eval('5*8');", &v);
CHECK(v.isNumber() && v.toNumber() == 40);
// Other arguments are returned as is by eval.
EVAL("eval({myProp: 41});", &v);
CHECK(v.isObject());
JS::RootedObject obj(cx, &v.toObject());
JS::RootedValue myProp(cx);
CHECK(JS_GetProperty(cx, obj, "myProp", &myProp));
CHECK(myProp.isNumber() && myProp.toNumber() == 41);
EVAL("eval({trustedCode: '6*7'}).trustedCode;", &v);
CHECK(v.isString());
JSString* str = v.toString();
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "6*7"));
EVAL("eval({trustedCode: 42}).trustedCode;", &v);
CHECK(v.isNumber() && v.toNumber() == 42);
return true;
}
END_TEST(testDynamicCodeBrandChecks_DefaultHostGetCodeForEval)
static bool ExtractTrustedCodeStringProperty(
JSContext* aCx, JS::Handle<JSObject*> aCode,
JS::MutableHandle<JSString*> outCode) {
JS::RootedValue value(aCx);
if (!JS_GetProperty(aCx, aCode, "trustedCode", &value)) {
return false;
}
if (value.isUndefined()) {
// If the property is undefined, return NO-CODE.
outCode.set(nullptr);
return true;
}
if (value.isString()) {
// If the property is a string, return it.
outCode.set(value.toString());
return true;
}
// Otherwise, emulate a failure.
JS_ReportErrorASCII(aCx, "Unsupported value for trustedCode property");
return false;
}
BEGIN_TEST(testDynamicCodeBrandChecks_CustomHostGetCodeForEval) {
JSSecurityCallbacks securityCallbacksWithEvalAcceptingObject = {
nullptr, // contentSecurityPolicyAllows
ExtractTrustedCodeStringProperty, // codeForEvalGets
nullptr // subsumes
};
JS_SetSecurityCallbacks(cx, &securityCallbacksWithEvalAcceptingObject);
JS::RootedValue v(cx);
// String arguments are evaluated.
EVAL("eval('5*8');", &v);
CHECK(v.isNumber() && v.toNumber() == 40);
// Other arguments are returned as is by eval...
EVAL("eval({myProp: 41});", &v);
CHECK(v.isObject());
JS::RootedObject obj(cx, &v.toObject());
JS::RootedValue myProp(cx);
CHECK(JS_GetProperty(cx, obj, "myProp", &myProp));
CHECK(myProp.isNumber() && myProp.toNumber() == 41);
// ... but Objects are first tentatively converted to String by the
// codeForEvalGets callback.
EVAL("eval({trustedCode: '6*7'});", &v);
CHECK(v.isNumber() && v.toNumber() == 6 * 7);
// And if that codeForEvalGets callback fails, then so does the eval call.
CHECK(!execDontReport("eval({trustedCode: 6*7});", __FILE__, __LINE__));
return true;
}
END_TEST(testDynamicCodeBrandChecks_CustomHostGetCodeForEval)
// This snippet defines a TrustedType that wraps some trustedCode string and
// stringifies to that string, as well as a helper to create a fake instance
// that can stringify to a different string.
const char* customTypesSnippet =
"function TrustedType(aTrustedCode) { this.trustedCode = aTrustedCode; };"
"TrustedType.prototype.toString = function() { return this.trustedCode; };"
"function CreateFakeTrustedType(aTrustedCode, aString) {"
" let fake = new TrustedType(aTrustedCode);"
" fake.toString = () => { return aString; };"
" return fake;"
"};";
BEGIN_TEST(testDynamicCodeBrandChecks_CustomHostEnsureCanCompileStrings) {
JSSecurityCallbacks securityCallbacksWithCustomHostEnsureCanCompileStrings = {
StringifiedObjectsMatchTrustedCodeProperties, // contentSecurityPolicyAllows
ExtractTrustedCodeStringProperty, // codeForEvalGets
nullptr // subsumes
};
JS_SetSecurityCallbacks(
cx, &securityCallbacksWithCustomHostEnsureCanCompileStrings);
JS::RootedValue v(cx);
EXEC(customTypesSnippet);
// String arguments are evaluated.
EVAL("eval('5*8');", &v);
CHECK(v.isNumber() && v.toNumber() == 40);
EVAL("(new Function('a', 'b', 'return a * b'))(6, 7);", &v);
CHECK(v.isNumber() && v.toNumber() == 42);
// The same works with TrustedType wrappers.
EVAL("eval(new TrustedType('5*8'));", &v);
CHECK(v.isNumber() && v.toNumber() == 40);
EVAL(
"(new Function(new TrustedType('a'), new TrustedType('b'), new "
"TrustedType('return a * b')))(6, 7);",
&v);
CHECK(v.isNumber() && v.toNumber() == 42);
// new Function fails if one of the stringified argument does not match the
// trustedCode property.
CHECK(!execDontReport(
"new Function(CreateFakeTrustedType('a', 'c'), 'b', 'return b');",
__FILE__, __LINE__));
CHECK(!execDontReport(
"new Function('a', CreateFakeTrustedType('b', 'c'), 'return a');",
__FILE__, __LINE__));
CHECK(
!execDontReport("new Function('a', 'b', CreateFakeTrustedType('return a "
"* b', 'return a + b'));",
__FILE__, __LINE__));
// new Function also fails if StringifiedObjectsMatchTrustedCodeProperties
// returns false.
CHECK(!execDontReport("new Function('a', 'b', new TrustedType(undefined));",
__FILE__, __LINE__));
// PerformEval relies on ExtractTrustedCodeProperty rather than toString() to
// obtain the code to execute, so StringifiedObjectsMatchTrustedCodeProperties
// will always allow the code execution for the specified security callbacks.
EVAL("eval(CreateFakeTrustedType('5*8', '6*7'));", &v);
CHECK(v.isNumber() && v.toNumber() == 40);
EVAL("eval(new TrustedType(undefined));", &v);
CHECK(v.isObject());
JS::RootedObject obj(cx, &v.toObject());
JS::RootedValue trustedCode(cx);
CHECK(JS_GetProperty(cx, obj, "trustedCode", &trustedCode));
CHECK(trustedCode.isUndefined());
return true;
}
// This is a HostEnsureCanCompileStrings() implementation similar to some checks
// described in the CSP spec: verify that aBodyString and aParameterStrings
// match the corresponding trustedCode property on aBodyArg and aParameterArgs
// objects. See https://w3c.github.io/webappsec-csp/#can-compile-strings
static bool StringifiedObjectsMatchTrustedCodeProperties(
JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
JS::CompilationType aCompilationType,
JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
JS::Handle<JSString*> aBodyString,
JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
bool isTrusted = true;
auto comparePropertyAndString = [&aCx, &isTrusted](
JS::Handle<JS::Value> aValue,
JS::Handle<JSString*> aString) {
if (!aValue.isObject()) {
// Just trust non-Objects.
return true;
}
JS::RootedObject obj(aCx, &aValue.toObject());
JS::RootedString trustedCode(aCx);
if (!ExtractTrustedCodeStringProperty(aCx, obj, &trustedCode)) {
// Propagate the failure.
return false;
}
if (!trustedCode) {
// Emulate a failure if trustedCode is undefined.
JS_ReportErrorASCII(aCx,
"test failed, trustedCode property is undefined");
return false;
}
bool equals;
if (!EqualStrings(aCx, trustedCode, aString, &equals)) {
// Propagate the failure.
return false;
}
if (!equals) {
isTrusted = false;
}
return true;
};
if (!comparePropertyAndString(aBodyArg, aBodyString)) {
// Propagate the failure.
return false;
}
if (isTrusted) {
MOZ_ASSERT(aParameterArgs.length() == aParameterStrings.length());
for (size_t index = 0; index < aParameterArgs.length(); index++) {
if (!comparePropertyAndString(aParameterArgs[index],
aParameterStrings[index])) {
// Propagate the failure.
return false;
}
if (!isTrusted) {
break;
}
}
}
// Allow compilation if arguments are trusted.
*aOutCanCompileStrings = isTrusted;
return true;
}
END_TEST(testDynamicCodeBrandChecks_CustomHostEnsureCanCompileStrings)
BEGIN_TEST(testDynamicCodeBrandChecks_RejectObjectForEval) {
JSSecurityCallbacks securityCallbacksRejectObjectBody = {
DisallowObjectsAndFailOtherwise, // contentSecurityPolicyAllows
ExtractTrustedCodeStringProperty, // codeForEvalGets
nullptr // subsumes
};
JS_SetSecurityCallbacks(cx, &securityCallbacksRejectObjectBody);
JS::RootedValue v(cx);
EXEC(customTypesSnippet);
// With the specified security callbacks, eval() will always fail.
CHECK(!execDontReport("eval('5*8))", __FILE__, __LINE__));
CHECK(!execDontReport("eval(new TrustedType('5*8'))", __FILE__, __LINE__));
return true;
}
static bool DisallowObjectsAndFailOtherwise(
JSContext* aCx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCodeString,
JS::CompilationType aCompilationType,
JS::Handle<JS::StackGCVector<JSString*>> aParameterStrings,
JS::Handle<JSString*> aBodyString,
JS::Handle<JS::StackGCVector<JS::Value>> aParameterArgs,
JS::Handle<JS::Value> aBodyArg, bool* aOutCanCompileStrings) {
if (aBodyArg.isObject()) {
// Disallow compilation for objects.
*aOutCanCompileStrings = false;
return true;
}
// Otherwise, emulate a failure.
JS_ReportErrorASCII(aCx, "aBodyArg is not an Object");
return false;
}
END_TEST(testDynamicCodeBrandChecks_RejectObjectForEval)

View File

@@ -258,7 +258,6 @@ struct StructuredCloneTestPrincipals final : public JSPrincipals {
JSSecurityCallbacks StructuredCloneTestPrincipals::securityCallbacks = {
nullptr, // contentSecurityPolicyAllows
nullptr, // codeForEvalGets
subsumes};
BEGIN_TEST(testStructuredClone_SavedFrame) {

View File

@@ -955,7 +955,6 @@ class ShellPrincipals final : public JSPrincipals {
JSSecurityCallbacks ShellPrincipals::securityCallbacks = {
nullptr, // contentSecurityPolicyAllows
nullptr, // codeForEvalGets
subsumes};
// The fully-trusted principal subsumes all other principals.

View File

@@ -1233,35 +1233,15 @@ bool JSContext::isThrowingDebuggeeWouldRun() {
JSEXN_DEBUGGEEWOULDRUN;
}
bool JSContext::isRuntimeCodeGenEnabled(
JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
JS::CompilationType compilationType,
JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
JS::Handle<JSString*> bodyString,
JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings) {
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, kind, codeString, compilationType, parameterStrings,
bodyString, parameterArgs, bodyArg, outCanCompileStrings);
return allows(this, kind, code);
}
// Default implementation from the "Dynamic Code Brand Checks" spec.
// https://tc39.es/proposal-dynamic-code-brand-checks/#sec-hostensurecancompilestrings
*outCanCompileStrings = true;
return true;
}
bool JSContext::getCodeForEval(HandleObject code,
JS::MutableHandle<JSString*> outCode) {
if (JSCodeForEvalOp gets = runtime()->securityCallbacks->codeForEvalGets) {
return gets(this, code, outCode);
}
// Default implementation from the "Dynamic Code Brand Checks" spec.
// https://tc39.es/proposal-dynamic-code-brand-checks/#sec-hostgetcodeforeval
outCode.set(nullptr);
return true;
}

View File

@@ -803,17 +803,7 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
// Checks if the page's Content-Security-Policy (CSP) allows
// runtime code generation "unsafe-eval", or "wasm-unsafe-eval" for Wasm.
bool isRuntimeCodeGenEnabled(
JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
JS::CompilationType compilationType,
JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
JS::Handle<JSString*> bodyString,
JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings);
// Get code to be used by eval for Object argument.
bool getCodeForEval(JS::HandleObject code,
JS::MutableHandle<JSString*> outCode);
bool isRuntimeCodeGenEnabled(JS::RuntimeCode kind, js::HandleString code);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

View File

@@ -1346,32 +1346,19 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
return false;
}
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
if (args.length() > 1) {
RootedString str(cx);
// Steps 10, 14.d.
unsigned n = args.length() - 1;
if (!parameterStrings.reserve(n) || !parameterArgs.reserve(n)) {
return false;
}
for (unsigned i = 0; i < n; i++) {
if (!parameterArgs.append(args[i])) {
return false;
}
// Steps 14.a-b, 14.d.i-ii.
str = ToString<CanGC>(cx, args[i]);
if (!str) {
return false;
}
if (!parameterStrings.append(str)) {
return false;
}
// Steps 14.b, 14.d.iii.
if (!sb.append(str)) {
return false;
@@ -1399,13 +1386,10 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
return false;
}
JS::RootedValue bodyArg(cx);
RootedString bodyString(cx);
if (args.length() > 0) {
// Steps 13, 14.e, 15.
bodyArg = args[args.length() - 1];
bodyString = ToString<CanGC>(cx, bodyArg);
if (!bodyString || !sb.append(bodyString)) {
RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
if (!body || !sb.append(body)) {
return false;
}
}
@@ -1426,14 +1410,7 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
}
// Block this call if security callbacks forbid it.
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, functionText,
JS::CompilationType::Function,
parameterStrings, bodyString, parameterArgs,
bodyArg, &canCompileStrings)) {
return false;
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, functionText)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_FUNCTION);
return false;

View File

@@ -1619,16 +1619,7 @@ bool WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return false;
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.Module");
return false;
@@ -4446,16 +4437,7 @@ static bool WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) {
CallArgs callArgs = CallArgsFromVp(argc, vp);
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return RejectWithPendingException(cx, promise, callArgs);
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.compile");
return RejectWithPendingException(cx, promise, callArgs);
@@ -4539,16 +4521,7 @@ static bool WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
} else {
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return RejectWithPendingException(cx, promise, callArgs);
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.instantiate");
@@ -5141,16 +5114,7 @@ static bool WebAssembly_compileStreaming(JSContext* cx, unsigned argc,
CallArgs callArgs = CallArgsFromVp(argc, vp);
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return RejectWithPendingException(cx, resultPromise, callArgs);
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.compileStreaming");
@@ -5183,16 +5147,7 @@ static bool WebAssembly_instantiateStreaming(JSContext* cx, unsigned argc,
CallArgs callArgs = CallArgsFromVp(argc, vp);
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return RejectWithPendingException(cx, resultPromise, callArgs);
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM,
"WebAssembly.instantiateStreaming");

View File

@@ -206,16 +206,7 @@ JSObject* Module::createObject(JSContext* cx) const {
return nullptr;
}
JS::RootedVector<JSString*> parameterStrings(cx);
JS::RootedVector<Value> parameterArgs(cx);
bool canCompileStrings = false;
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr,
JS::CompilationType::Undefined,
parameterStrings, nullptr, parameterArgs,
NullHandleValue, &canCompileStrings)) {
return nullptr;
}
if (!canCompileStrings) {
if (!cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::WASM, nullptr)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_CSP_BLOCKED_WASM, "WebAssembly.Module");
return nullptr;