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;
}
// --- W e a k H a n d l e s
// --- Weak Handles ---
/**
......@@ -131,7 +131,7 @@ typedef void (*WeakReferenceCallback)(Persistent<Value> object,
void* parameter);
// --- H a n d l e s ---
// --- Handles ---
#define TYPE_CHECK(T, S) \
while (false) { \
......@@ -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 {
};
// --- V a l u e ---
// --- 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 {
};
// --- E x t e n s i o n s ---
// --- Extensions ---
/**
......@@ -2369,7 +2369,7 @@ class V8EXPORT DeclareExtension {
};
// --- S t a t i c s ---
// --- Statics ---
Handle<Primitive> V8EXPORT Undefined();
......@@ -2410,7 +2410,7 @@ class V8EXPORT ResourceConstraints {
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);
......@@ -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);
......@@ -2452,7 +2452,7 @@ typedef void* (*CreateHistogramCallback)(const char* name,
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 {
kObjectSpaceNewSpace = 1 << 0,
kObjectSpaceOldPointerSpace = 1 << 1,
......@@ -2476,12 +2476,20 @@ typedef void (*MemoryAllocationCallback)(ObjectSpace space,
AllocationAction action,
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,
AccessType type,
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
......@@ -2661,6 +2669,13 @@ class V8EXPORT V8 {
/** Set the callback to invoke in case of fatal errors. */
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.
*
......@@ -3189,7 +3204,7 @@ class V8EXPORT TryCatch {
};
// --- C o n t e x t ---
// --- Context ---
/**
......@@ -3324,6 +3339,21 @@ class V8EXPORT Context {
void SetData(Handle<String> data);
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
* operations executed within a local scope.
......@@ -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 {
......
......@@ -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
void ImplementationUtilities::ZapHandleRange(i::Object** begin,
i::Object** end) {
......@@ -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) {
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
// modification, are permitted provided that the following conditions are
// met:
......@@ -106,7 +106,8 @@ enum ContextLookupFlags {
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
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
// closures. A Context object is used to represent function contexts and
......@@ -236,6 +237,7 @@ class Context: public FixedArray {
OUT_OF_MEMORY_INDEX,
MAP_CACHE_INDEX,
CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
......
......@@ -345,6 +345,7 @@ typedef List<HeapObject*, PreallocatedStorage> DebugObjectCache;
/* A previously allocated buffer of kMinimalBufferSize bytes, or NULL. */ \
V(byte*, assembler_spare_buffer, NULL) \
V(FatalErrorCallback, exception_behavior, NULL) \
V(AllowCodeGenerationFromStringsCallback, allow_code_gen_callback, NULL) \
V(v8::Debug::MessageHandler, message_handler, NULL) \
/* To distinguish the function templates, so that we can find them in the */ \
/* function cache of the global context. */ \
......
......@@ -142,6 +142,7 @@ function FormatMessage(message) {
kMessages = {
// Error
cyclic_proto: ["Cyclic __proto__ value"],
code_gen_from_strings: ["Code generation from strings disallowed for this context"],
// TypeError
unexpected_token: ["Unexpected token ", "%0"],
unexpected_token_number: ["Unexpected number"],
......
......@@ -50,9 +50,10 @@
#include "runtime-profiler.h"
#include "scopeinfo.h"
#include "smart-pointer.h"
#include "string-search.h"
#include "stub-cache.h"
#include "v8threads.h"
#include "string-search.h"
#include "vm-state-inl.h"
namespace v8 {
namespace internal {
......@@ -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) {
HandleScope scope(isolate);
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
// Compile source string in the global context.
// Extract 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,
context,
true,
......@@ -8309,17 +8338,28 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
Handle<String> source,
Handle<Object> receiver,
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
// and return the compiled function bound in the local context.
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source,
Handle<Context>(isolate->context()),
isolate->context()->IsGlobalContext(),
context->IsGlobalContext(),
strict_mode);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, Handle<Context>(isolate->context()), NOT_TENURED);
shared, context, NOT_TENURED);
return MakePair(*compiled, *receiver);
}
......
......@@ -14023,3 +14023,77 @@ TEST(HasOwnProperty) {
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