Commit 8aeaa5e9 authored by ager@chromium.org's avatar ager@chromium.org

Implement API to disallow code generation from strings for a context.

R=sgjesse@chromium.org
BUG=v8:1258
TEST=test-api/AllowCodeGenFromStrings

Review URL: http://codereview.chromium.org/6905167

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7753 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent be15ea86
...@@ -115,7 +115,7 @@ class Isolate; ...@@ -115,7 +115,7 @@ class Isolate;
} }
// --- W e a k H a n d l e s // --- Weak Handles ---
/** /**
...@@ -131,7 +131,7 @@ typedef void (*WeakReferenceCallback)(Persistent<Value> object, ...@@ -131,7 +131,7 @@ typedef void (*WeakReferenceCallback)(Persistent<Value> object,
void* parameter); void* parameter);
// --- H a n d l e s --- // --- Handles ---
#define TYPE_CHECK(T, S) \ #define TYPE_CHECK(T, S) \
while (false) { \ while (false) { \
...@@ -483,7 +483,7 @@ class V8EXPORT HandleScope { ...@@ -483,7 +483,7 @@ class V8EXPORT HandleScope {
}; };
// --- S p e c i a l o b j e c t s --- // --- Special objects ---
/** /**
...@@ -841,7 +841,7 @@ class V8EXPORT StackFrame { ...@@ -841,7 +841,7 @@ class V8EXPORT StackFrame {
}; };
// --- V a l u e --- // --- Value ---
/** /**
...@@ -1783,7 +1783,7 @@ class External : public Value { ...@@ -1783,7 +1783,7 @@ class External : public Value {
}; };
// --- T e m p l a t e s --- // --- Templates ---
/** /**
...@@ -2317,7 +2317,7 @@ class V8EXPORT TypeSwitch : public Data { ...@@ -2317,7 +2317,7 @@ class V8EXPORT TypeSwitch : public Data {
}; };
// --- E x t e n s i o n s --- // --- Extensions ---
/** /**
...@@ -2369,7 +2369,7 @@ class V8EXPORT DeclareExtension { ...@@ -2369,7 +2369,7 @@ class V8EXPORT DeclareExtension {
}; };
// --- S t a t i c s --- // --- Statics ---
Handle<Primitive> V8EXPORT Undefined(); Handle<Primitive> V8EXPORT Undefined();
...@@ -2410,7 +2410,7 @@ class V8EXPORT ResourceConstraints { ...@@ -2410,7 +2410,7 @@ class V8EXPORT ResourceConstraints {
bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints); bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints);
// --- E x c e p t i o n s --- // --- Exceptions ---
typedef void (*FatalErrorCallback)(const char* location, const char* message); typedef void (*FatalErrorCallback)(const char* location, const char* message);
...@@ -2441,7 +2441,7 @@ class V8EXPORT Exception { ...@@ -2441,7 +2441,7 @@ class V8EXPORT Exception {
}; };
// --- C o u n t e r s C a l l b a c k s --- // --- Counters Callbacks ---
typedef int* (*CounterLookupCallback)(const char* name); typedef int* (*CounterLookupCallback)(const char* name);
...@@ -2452,7 +2452,7 @@ typedef void* (*CreateHistogramCallback)(const char* name, ...@@ -2452,7 +2452,7 @@ typedef void* (*CreateHistogramCallback)(const char* name,
typedef void (*AddHistogramSampleCallback)(void* histogram, int sample); typedef void (*AddHistogramSampleCallback)(void* histogram, int sample);
// --- M e m o r y A l l o c a t i o n C a l l b a c k --- // --- Memory Allocation Callback ---
enum ObjectSpace { enum ObjectSpace {
kObjectSpaceNewSpace = 1 << 0, kObjectSpaceNewSpace = 1 << 0,
kObjectSpaceOldPointerSpace = 1 << 1, kObjectSpaceOldPointerSpace = 1 << 1,
...@@ -2476,12 +2476,20 @@ typedef void (*MemoryAllocationCallback)(ObjectSpace space, ...@@ -2476,12 +2476,20 @@ typedef void (*MemoryAllocationCallback)(ObjectSpace space,
AllocationAction action, AllocationAction action,
int size); int size);
// --- F a i l e d A c c e s s C h e c k C a l l b a c k --- // --- Failed Access Check Callback ---
typedef void (*FailedAccessCheckCallback)(Local<Object> target, typedef void (*FailedAccessCheckCallback)(Local<Object> target,
AccessType type, AccessType type,
Local<Value> data); Local<Value> data);
// --- G a r b a g e C o l l e c t i o n C a l l b a c k s // --- AllowCodeGenerationFromStrings callbacks ---
/**
* Callback to check if code generation from strings is allowed. See
* Context::AllowCodeGenerationFromStrings.
*/
typedef bool (*AllowCodeGenerationFromStringsCallback)(Local<Context> context);
// --- Garbage Collection Callbacks ---
/** /**
* Applications can register callback functions which will be called * Applications can register callback functions which will be called
...@@ -2661,6 +2669,13 @@ class V8EXPORT V8 { ...@@ -2661,6 +2669,13 @@ class V8EXPORT V8 {
/** Set the callback to invoke in case of fatal errors. */ /** Set the callback to invoke in case of fatal errors. */
static void SetFatalErrorHandler(FatalErrorCallback that); static void SetFatalErrorHandler(FatalErrorCallback that);
/**
* Set the callback to invoke to check if code generation from
* strings should be allowed.
*/
static void SetAllowCodeGenerationFromStringsCallback(
AllowCodeGenerationFromStringsCallback that);
/** /**
* Ignore out-of-memory exceptions. * Ignore out-of-memory exceptions.
* *
...@@ -3189,7 +3204,7 @@ class V8EXPORT TryCatch { ...@@ -3189,7 +3204,7 @@ class V8EXPORT TryCatch {
}; };
// --- C o n t e x t --- // --- Context ---
/** /**
...@@ -3324,6 +3339,21 @@ class V8EXPORT Context { ...@@ -3324,6 +3339,21 @@ class V8EXPORT Context {
void SetData(Handle<String> data); void SetData(Handle<String> data);
Local<Value> GetData(); Local<Value> GetData();
/**
* Control whether code generation from strings is allowed. Calling
* this method with false will disable 'eval' and the 'Function'
* constructor for code running in this context. If 'eval' or the
* 'Function' constructor are used an exception will be thrown.
*
* If code generation from strings is not allowed the
* V8::AllowCodeGenerationFromStrings callback will be invoked if
* set before blocking the call to 'eval' or the 'Function'
* constructor. If that callback returns true, the call will be
* allowed, otherwise an exception will be thrown. If no callback is
* set an exception will be thrown.
*/
void AllowCodeGenerationFromStrings(bool allow);
/** /**
* 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.
...@@ -3520,7 +3550,7 @@ class V8EXPORT ActivityControl { // NOLINT ...@@ -3520,7 +3550,7 @@ class V8EXPORT ActivityControl { // NOLINT
}; };
// --- I m p l e m e n t a t i o n --- // --- Implementation ---
namespace internal { namespace internal {
......
...@@ -372,6 +372,13 @@ void V8::SetFatalErrorHandler(FatalErrorCallback that) { ...@@ -372,6 +372,13 @@ void V8::SetFatalErrorHandler(FatalErrorCallback that) {
} }
void V8::SetAllowCodeGenerationFromStringsCallback(
AllowCodeGenerationFromStringsCallback callback) {
i::Isolate* isolate = EnterIsolateIfNeeded();
isolate->set_allow_code_gen_callback(callback);
}
#ifdef DEBUG #ifdef DEBUG
void ImplementationUtilities::ZapHandleRange(i::Object** begin, void ImplementationUtilities::ZapHandleRange(i::Object** begin,
i::Object** end) { i::Object** end) {
...@@ -3918,6 +3925,20 @@ void Context::ReattachGlobal(Handle<Object> global_object) { ...@@ -3918,6 +3925,20 @@ void Context::ReattachGlobal(Handle<Object> global_object) {
} }
void Context::AllowCodeGenerationFromStrings(bool allow) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Context::AllowCodeGenerationFromStrings()")) {
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));
context->set_allow_code_gen_from_strings(
allow ? isolate->heap()->true_value() : isolate->heap()->false_value());
}
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);
} }
......
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -106,7 +106,8 @@ enum ContextLookupFlags { ...@@ -106,7 +106,8 @@ enum ContextLookupFlags {
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \ V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \ V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
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)
// JSFunctions are pairs (context, function code), sometimes also called // JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and // closures. A Context object is used to represent function contexts and
...@@ -236,6 +237,7 @@ class Context: public FixedArray { ...@@ -236,6 +237,7 @@ class Context: public FixedArray {
OUT_OF_MEMORY_INDEX, OUT_OF_MEMORY_INDEX,
MAP_CACHE_INDEX, MAP_CACHE_INDEX,
CONTEXT_DATA_INDEX, CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
// Properties from here are treated as weak references by the full GC. // Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references. // Scavenge treats them as strong references.
......
...@@ -345,6 +345,7 @@ typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache; ...@@ -345,6 +345,7 @@ typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache;
/* A previously allocated buffer of kMinimalBufferSize bytes, or NULL. */ \ /* A previously allocated buffer of kMinimalBufferSize bytes, or NULL. */ \
V(byte*, assembler_spare_buffer, NULL) \ V(byte*, assembler_spare_buffer, NULL) \
V(FatalErrorCallback, exception_behavior, NULL) \ V(FatalErrorCallback, exception_behavior, NULL) \
V(AllowCodeGenerationFromStringsCallback, allow_code_gen_callback, NULL) \
V(v8::Debug::MessageHandler, message_handler, NULL) \ V(v8::Debug::MessageHandler, message_handler, NULL) \
/* To distinguish the function templates, so that we can find them in the */ \ /* To distinguish the function templates, so that we can find them in the */ \
/* function cache of the global context. */ \ /* function cache of the global context. */ \
......
...@@ -142,6 +142,7 @@ function FormatMessage(message) { ...@@ -142,6 +142,7 @@ function FormatMessage(message) {
kMessages = { kMessages = {
// Error // Error
cyclic_proto: ["Cyclic __proto__ value"], cyclic_proto: ["Cyclic __proto__ value"],
code_gen_from_strings: ["Code generation from strings disallowed for this context"],
// TypeError // TypeError
unexpected_token: ["Unexpected token ", "%0"], unexpected_token: ["Unexpected token ", "%0"],
unexpected_token_number: ["Unexpected number"], unexpected_token_number: ["Unexpected number"],
......
...@@ -50,9 +50,10 @@ ...@@ -50,9 +50,10 @@
#include "runtime-profiler.h" #include "runtime-profiler.h"
#include "scopeinfo.h" #include "scopeinfo.h"
#include "smart-pointer.h" #include "smart-pointer.h"
#include "string-search.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "v8threads.h" #include "v8threads.h"
#include "string-search.h" #include "vm-state-inl.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -8285,13 +8286,41 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { ...@@ -8285,13 +8286,41 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
} }
bool CodeGenerationFromStringsAllowed(Isolate* isolate,
Handle<Context> context) {
if (context->allow_code_gen_from_strings()->IsFalse()) {
// Check with callback if set.
AllowCodeGenerationFromStringsCallback callback =
isolate->allow_code_gen_callback();
if (callback == NULL) {
// No callback set and code generation disallowed.
return false;
} else {
// Callback set. Let it decide if code generation is allowed.
VMState state(isolate, EXTERNAL);
return callback(v8::Utils::ToLocal(context));
}
}
return true;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT_EQ(1, args.length()); ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0); CONVERT_ARG_CHECKED(String, source, 0);
// Compile source string in the global context. // Extract global context.
Handle<Context> context(isolate->context()->global_context()); Handle<Context> context(isolate->context()->global_context());
// Check if global context allows code generation from
// strings. Throw an exception if it doesn't.
if (!CodeGenerationFromStringsAllowed(isolate, context)) {
return isolate->Throw(*isolate->factory()->NewError(
"code_gen_from_strings", HandleVector<Object>(NULL, 0)));
}
// Compile source string in the global context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
context, context,
true, true,
...@@ -8309,17 +8338,28 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, ...@@ -8309,17 +8338,28 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
Handle<String> source, Handle<String> source,
Handle<Object> receiver, Handle<Object> receiver,
StrictModeFlag strict_mode) { StrictModeFlag strict_mode) {
Handle<Context> context = Handle<Context>(isolate->context());
Handle<Context> global_context = Handle<Context>(context->global_context());
// Check if global context allows code generation from
// strings. Throw an exception if it doesn't.
if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
isolate->Throw(*isolate->factory()->NewError(
"code_gen_from_strings", HandleVector<Object>(NULL, 0)));
return MakePair(Failure::Exception(), NULL);
}
// Deal with a normal eval call with a string argument. Compile it // Deal with a normal eval call with a string argument. Compile it
// and return the compiled function bound in the local context. // and return the compiled function bound in the local context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval( Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source, source,
Handle<Context>(isolate->context()), Handle<Context>(isolate->context()),
isolate->context()->IsGlobalContext(), context->IsGlobalContext(),
strict_mode); strict_mode);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL); if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled = Handle<JSFunction> compiled =
isolate->factory()->NewFunctionFromSharedFunctionInfo( isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, Handle<Context>(isolate->context()), NOT_TENURED); shared, context, NOT_TENURED);
return MakePair(*compiled, *receiver); return MakePair(*compiled, *receiver);
} }
......
...@@ -14023,3 +14023,77 @@ TEST(HasOwnProperty) { ...@@ -14023,3 +14023,77 @@ TEST(HasOwnProperty) {
CHECK(instance->HasOwnProperty(v8_str("bar"))); CHECK(instance->HasOwnProperty(v8_str("bar")));
} }
} }
void CheckCodeGenerationAllowed() {
Handle<Value> result = CompileRun("eval('42')");
CHECK_EQ(42, result->Int32Value());
result = CompileRun("(function(e) { return e('42'); })(eval)");
CHECK_EQ(42, result->Int32Value());
result = CompileRun("execScript('42')");
CHECK(!result.IsEmpty());
result = CompileRun("var f = new Function('return 42'); f()");
CHECK_EQ(42, result->Int32Value());
}
void CheckCodeGenerationDisallowed() {
TryCatch try_catch;
Handle<Value> result = CompileRun("eval('42')");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
try_catch.Reset();
result = CompileRun("(function(e) { return e('42'); })(eval)");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
try_catch.Reset();
result = CompileRun("execScript('42')");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
try_catch.Reset();
result = CompileRun("var f = new Function('return 42'); f()");
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
}
bool CodeGenerationAllowed(Local<Context> context) {
ApiTestFuzzer::Fuzz();
return true;
}
bool CodeGenerationDisallowed(Local<Context> context) {
ApiTestFuzzer::Fuzz();
return false;
}
THREADED_TEST(AllowCodeGenFromStrings) {
v8::HandleScope scope;
LocalContext context;
// eval, execScript and the Function constructor allowed by default.
CheckCodeGenerationAllowed();
// Disallow eval, execScript and the Function constructor.
context->AllowCodeGenerationFromStrings(false);
CheckCodeGenerationDisallowed();
// Allow again.
context->AllowCodeGenerationFromStrings(true);
CheckCodeGenerationAllowed();
// Disallow but setting a global callback that will allow the calls.
context->AllowCodeGenerationFromStrings(false);
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
CheckCodeGenerationAllowed();
// Set a callback that disallows the code generation.
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
CheckCodeGenerationDisallowed();
}
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