filter cross context eval
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 08:28:19 +0000 (08:28 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 08:28:19 +0000 (08:28 +0000)
R=verwaest@chromium.org

BUG=

Review URL: https://codereview.chromium.org/294073002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21793 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/generator.js
src/runtime.cc
src/v8natives.js
test/cctest/test-api.cc
test/mjsunit/cross-realm-filtering.js

index c152e3a..1ca3fd4 100644 (file)
@@ -43,7 +43,9 @@ function GeneratorFunctionConstructor(arg1) {  // length == 1
   var global_receiver = %GlobalReceiver(global);
   // Compile the string in the constructor and not a helper so that errors
   // appear to come from here.
-  var f = %_CallFunction(global_receiver, %CompileString(source, true));
+  var f = %CompileString(source, true);
+  if (!IS_FUNCTION(f)) return f;
+  f = %_CallFunction(global_receiver, f);
   %FunctionMarkNameShouldPrintAsAnonymous(f);
   return f;
 }
index 7eb753a..0f8d794 100644 (file)
@@ -9782,6 +9782,59 @@ bool CodeGenerationFromStringsAllowed(Isolate* isolate,
 }
 
 
+// Walk up the stack expecting:
+//  - Runtime_CompileString
+//  - JSFunction callee (eval, Function constructor, etc)
+//  - call() (maybe)
+//  - apply() (maybe)
+//  - bind() (maybe)
+// - JSFunction caller (maybe)
+//
+// return true if the caller has the same security token as the callee
+// or if an exit frame was hit, in which case allow it through, as it could
+// have come through the api.
+static bool TokensMatchForCompileString(Isolate* isolate) {
+  MaybeHandle<JSFunction> callee;
+  bool exit_handled = true;
+  bool tokens_match = true;
+  bool done = false;
+  for (StackFrameIterator it(isolate); !it.done() && !done; it.Advance()) {
+    StackFrame* raw_frame = it.frame();
+    if (!raw_frame->is_java_script()) {
+      if (raw_frame->is_exit()) exit_handled = false;
+      continue;
+    }
+    JavaScriptFrame* outer_frame = JavaScriptFrame::cast(raw_frame);
+    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+    outer_frame->Summarize(&frames);
+    for (int i = frames.length() - 1; i >= 0 && !done; --i) {
+      FrameSummary& frame = frames[i];
+      Handle<JSFunction> fun = frame.function();
+      // Capture the callee function.
+      if (callee.is_null()) {
+        callee = fun;
+        exit_handled = true;
+        continue;
+      }
+      // Exit condition.
+      Handle<Context> context(callee.ToHandleChecked()->context());
+      if (!fun->context()->HasSameSecurityTokenAs(*context)) {
+        tokens_match = false;
+        done = true;
+        continue;
+      }
+      // Skip bound functions in correct origin.
+      if (fun->shared()->bound()) {
+        exit_handled = true;
+        continue;
+      }
+      done = true;
+    }
+  }
+  return !exit_handled || tokens_match;
+}
+
+
 RUNTIME_FUNCTION(Runtime_CompileString) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 2);
@@ -9791,6 +9844,11 @@ RUNTIME_FUNCTION(Runtime_CompileString) {
   // Extract native context.
   Handle<Context> context(isolate->context()->native_context());
 
+  // Filter cross security context calls.
+  if (!TokensMatchForCompileString(isolate)) {
+    return isolate->heap()->undefined_value();
+  }
+
   // Check if native context allows code generation from
   // strings. Throw an exception if it doesn't.
   if (context->allow_code_gen_from_strings()->IsFalse() &&
index 602d75b..68ca900 100644 (file)
@@ -1840,7 +1840,9 @@ function FunctionConstructor(arg1) {  // length == 1
   var global_receiver = %GlobalReceiver(global);
   // Compile the string in the constructor and not a helper so that errors
   // appear to come from here.
-  var f = %_CallFunction(global_receiver, %CompileString(source, true));
+  var f = %CompileString(source, true);
+  if (!IS_FUNCTION(f)) return f;
+  f = %_CallFunction(global_receiver, f);
   %FunctionMarkNameShouldPrintAsAnonymous(f);
   return f;
 }
index 89255f2..bdda382 100644 (file)
@@ -22714,3 +22714,29 @@ TEST(ScriptNameAndLineNumber) {
   int line_number = script->GetUnboundScript()->GetLineNumber(0);
   CHECK_EQ(13, line_number);
 }
+
+
+Local<v8::Context> call_eval_context;
+Local<v8::Function> call_eval_bound_function;
+static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::Context::Scope scope(call_eval_context);
+  args.GetReturnValue().Set(
+      call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL));
+}
+
+
+TEST(CrossActivationEval) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  {
+    call_eval_context = v8::Context::New(isolate);
+    v8::Context::Scope scope(call_eval_context);
+    call_eval_bound_function =
+        Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
+  }
+  env->Global()->Set(v8_str("CallEval"),
+      v8::FunctionTemplate::New(isolate, CallEval)->GetFunction());
+  Local<Value> result = CompileRun("CallEval();");
+  CHECK_EQ(result, v8::Integer::New(isolate, 1));
+}
index 9523e8c..902cceb 100644 (file)
@@ -70,3 +70,72 @@ assertSame(Realm.shared.caller_1, Realm.shared.result_1);
 Realm.eval(realms[0], script);
 assertSame(Realm.shared.caller_0, Realm.shared.result_0);
 assertSame(null, Realm.shared.result_1);
+
+
+// Check function constructor.
+var ctor_script = "Function.constructor";
+var ctor_a_script =
+    "(function() { return Function.constructor.apply(this, ['return 1;']); })";
+var ctor_b_script = "Function.constructor.bind(this, 'return 1;')";
+var ctor_c_script =
+    "(function() { return Function.constructor.call(this, 'return 1;'); })";
+Realm.shared = {
+  ctor_0 : Realm.eval(realms[0], ctor_script),
+  ctor_1 : Realm.eval(realms[1], ctor_script),
+  ctor_a_0 : Realm.eval(realms[0], ctor_a_script),
+  ctor_a_1 : Realm.eval(realms[1], ctor_a_script),
+  ctor_b_0 : Realm.eval(realms[0], ctor_b_script),
+  ctor_b_1 : Realm.eval(realms[1], ctor_b_script),
+  ctor_c_0 : Realm.eval(realms[0], ctor_c_script),
+  ctor_c_1 : Realm.eval(realms[1], ctor_c_script),
+}
+
+var script_0 = "                                                               \
+  var ctor_0 = Realm.shared.ctor_0;                                            \
+  Realm.shared.direct_0 = ctor_0('return 1');                                  \
+  Realm.shared.indirect_0 = (function() { return ctor_0('return 1;'); })();    \
+  Realm.shared.apply_0 = ctor_0.apply(this, ['return 1']);                     \
+  Realm.shared.bind_0 = ctor_0.bind(this, 'return 1')();                       \
+  Realm.shared.call_0 = ctor_0.call(this, 'return 1');                         \
+  Realm.shared.a_0 = Realm.shared.ctor_a_0();                                  \
+  Realm.shared.b_0 = Realm.shared.ctor_b_0();                                  \
+  Realm.shared.c_0 = Realm.shared.ctor_c_0();                                  \
+";
+
+script = script_0 + script_0.replace(/_0/g, "_1");
+
+Realm.eval(realms[0], script);
+assertSame(1, Realm.shared.direct_0());
+assertSame(1, Realm.shared.indirect_0());
+assertSame(1, Realm.shared.apply_0());
+assertSame(1, Realm.shared.bind_0());
+assertSame(1, Realm.shared.call_0());
+assertSame(1, Realm.shared.a_0());
+assertSame(1, Realm.shared.b_0());
+assertSame(1, Realm.shared.c_0());
+assertSame(undefined, Realm.shared.direct_1);
+assertSame(undefined, Realm.shared.indirect_1);
+assertSame(undefined, Realm.shared.apply_1);
+assertSame(undefined, Realm.shared.bind_1);
+assertSame(undefined, Realm.shared.call_1);
+assertSame(1, Realm.shared.a_1());
+assertSame(undefined, Realm.shared.b_1);
+assertSame(1, Realm.shared.c_1());
+
+Realm.eval(realms[1], script);
+assertSame(undefined, Realm.shared.direct_0);
+assertSame(undefined, Realm.shared.indirect_0);
+assertSame(undefined, Realm.shared.apply_0);
+assertSame(undefined, Realm.shared.bind_0);
+assertSame(undefined, Realm.shared.call_0);
+assertSame(1, Realm.shared.a_0());
+assertSame(undefined, Realm.shared.b_0);
+assertSame(1, Realm.shared.c_1());
+assertSame(1, Realm.shared.direct_1());
+assertSame(1, Realm.shared.indirect_1());
+assertSame(1, Realm.shared.apply_1());
+assertSame(1, Realm.shared.bind_1());
+assertSame(1, Realm.shared.call_1());
+assertSame(1, Realm.shared.a_1());
+assertSame(1, Realm.shared.b_1());
+assertSame(1, Realm.shared.c_1());