Commit 4bd4fb1a authored by ulan@chromium.org's avatar ulan@chromium.org

Throw a more descriptive exception when blocking 'eval' via CSP.

BUG=140191

R=svenpanne@chromium.org,mkwst@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10837358

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12525 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 70e09a7e
...@@ -3742,6 +3742,13 @@ class V8EXPORT Context { ...@@ -3742,6 +3742,13 @@ class V8EXPORT Context {
*/ */
bool IsCodeGenerationFromStringsAllowed(); bool IsCodeGenerationFromStringsAllowed();
/**
* Sets the error description for the exception that is thrown when
* code generation from strings is not allowed and 'eval' or the 'Function'
* constructor are called.
*/
void SetErrorMessageForCodeGenerationFromStrings(Handle<String> message);
/** /**
* Stack-allocated class which sets the execution context for all * Stack-allocated class which sets the execution context for all
* operations executed within a local scope. * operations executed within a local scope.
......
...@@ -4599,6 +4599,22 @@ bool Context::IsCodeGenerationFromStringsAllowed() { ...@@ -4599,6 +4599,22 @@ bool Context::IsCodeGenerationFromStringsAllowed() {
} }
void Context::SetErrorMessageForCodeGenerationFromStrings(
Handle<String> error) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate,
"v8::Context::SetErrorMessageForCodeGenerationFromStrings()")) {
return;
}
ENTER_V8(isolate);
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
i::Handle<i::Object> error_handle = Utils::OpenHandle(*error);
context->set_error_message_for_code_gen_from_strings(*error_handle);
}
void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) { void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) {
i::GlobalHandles::SetWrapperClassId(global_handle, class_id); i::GlobalHandles::SetWrapperClassId(global_handle, class_id);
} }
......
...@@ -305,6 +305,18 @@ void Context::ClearOptimizedFunctions() { ...@@ -305,6 +305,18 @@ void Context::ClearOptimizedFunctions() {
} }
Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
Handle<Object> result(error_message_for_code_gen_from_strings());
if (result->IsUndefined()) {
const char* error =
"Code generation from strings disallowed for this context";
Isolate* isolate = Isolate::Current();
result = isolate->factory()->NewStringFromAscii(i::CStrVector(error));
}
return result;
}
#ifdef DEBUG #ifdef DEBUG
bool Context::IsBootstrappingOrValidParentContext( bool Context::IsBootstrappingOrValidParentContext(
Object* object, Context* child) { Object* object, Context* child) {
......
...@@ -154,6 +154,8 @@ enum BindingFlags { ...@@ -154,6 +154,8 @@ enum BindingFlags {
V(MAP_CACHE_INDEX, Object, map_cache) \ V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \ V(CONTEXT_DATA_INDEX, Object, data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \ V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \ V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
to_complete_property_descriptor) \ to_complete_property_descriptor) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \ V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
...@@ -281,6 +283,7 @@ class Context: public FixedArray { ...@@ -281,6 +283,7 @@ class Context: public FixedArray {
OUT_OF_MEMORY_INDEX, OUT_OF_MEMORY_INDEX,
CONTEXT_DATA_INDEX, CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
DERIVED_HAS_TRAP_INDEX, DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX, DERIVED_GET_TRAP_INDEX,
...@@ -381,6 +384,8 @@ class Context: public FixedArray { ...@@ -381,6 +384,8 @@ class Context: public FixedArray {
Object* OptimizedFunctionsListHead(); Object* OptimizedFunctionsListHead();
void ClearOptimizedFunctions(); void ClearOptimizedFunctions();
Handle<Object> ErrorMessageForCodeGenerationFromStrings();
#define NATIVE_CONTEXT_FIELD_ACCESSORS(index, type, name) \ #define NATIVE_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void set_##name(type* value) { \ void set_##name(type* value) { \
ASSERT(IsNativeContext()); \ ASSERT(IsNativeContext()); \
......
...@@ -140,7 +140,7 @@ function FormatMessage(message) { ...@@ -140,7 +140,7 @@ function FormatMessage(message) {
var messagesDictionary = [ var messagesDictionary = [
// Error // Error
"cyclic_proto", ["Cyclic __proto__ value"], "cyclic_proto", ["Cyclic __proto__ value"],
"code_gen_from_strings", ["Code generation from strings disallowed for this context"], "code_gen_from_strings", ["%0"],
// TypeError // TypeError
"unexpected_token", ["Unexpected token ", "%0"], "unexpected_token", ["Unexpected token ", "%0"],
"unexpected_token_number", ["Unexpected number"], "unexpected_token_number", ["Unexpected number"],
......
...@@ -9061,8 +9061,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { ...@@ -9061,8 +9061,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
// strings. Throw an exception if it doesn't. // strings. Throw an exception if it doesn't.
if (context->allow_code_gen_from_strings()->IsFalse() && if (context->allow_code_gen_from_strings()->IsFalse() &&
!CodeGenerationFromStringsAllowed(isolate, context)) { !CodeGenerationFromStringsAllowed(isolate, context)) {
return isolate->Throw(*isolate->factory()->NewError( Handle<Object> error_message =
"code_gen_from_strings", HandleVector<Object>(NULL, 0))); context->ErrorMessageForCodeGenerationFromStrings();
return isolate->Throw(*isolate->factory()->NewEvalError(
"code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
} }
// Compile source string in the native context. // Compile source string in the native context.
...@@ -9089,8 +9091,10 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, ...@@ -9089,8 +9091,10 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
// strings. Throw an exception if it doesn't. // strings. Throw an exception if it doesn't.
if (native_context->allow_code_gen_from_strings()->IsFalse() && if (native_context->allow_code_gen_from_strings()->IsFalse() &&
!CodeGenerationFromStringsAllowed(isolate, native_context)) { !CodeGenerationFromStringsAllowed(isolate, native_context)) {
isolate->Throw(*isolate->factory()->NewError( Handle<Object> error_message =
"code_gen_from_strings", HandleVector<Object>(NULL, 0))); context->ErrorMessageForCodeGenerationFromStrings();
isolate->Throw(*isolate->factory()->NewEvalError(
"code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
return MakePair(Failure::Exception(), NULL); return MakePair(Failure::Exception(), NULL);
} }
......
...@@ -16524,6 +16524,24 @@ THREADED_TEST(AllowCodeGenFromStrings) { ...@@ -16524,6 +16524,24 @@ THREADED_TEST(AllowCodeGenFromStrings) {
} }
TEST(SetErrorMessageForCodeGenFromStrings) {
v8::HandleScope scope;
LocalContext context;
TryCatch try_catch;
Handle<String> message = v8_str("Message") ;
Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
context->AllowCodeGenerationFromStrings(false);
context->SetErrorMessageForCodeGenerationFromStrings(message);
Handle<Value> result = CompileRun("eval('42')");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
Handle<String> actual_message = try_catch.Message()->Get();
CHECK(expected_message->Equals(actual_message));
}
static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) { static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
return v8::Undefined(); return v8::Undefined();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment