I think I can understand it a bit. Look at the following test case.

THREADED_TEST(SecurityChecks) {
  LocalContext env1;
  v8::HandleScope handle_scope(env1->GetIsolate());
  v8::Local<Context> env2 = Context::New(env1->GetIsolate());

  Local<Value> foo = v8_str("foo");
  Local<Value> bar = v8_str("bar");

  env1->SetSecurityToken(foo); 

  // Create a function accessing global objects.
  CompileRun("Array.prototype.x = 1; spy2=function(){return new 
this.Array();}");
  Local<Value> spy2 =
      env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked(); 
// Local<Value> spy2 is required from env1 global object when entering 
env1, and spy2 can be used in other context even if their tokens are not 
matched because only direct access to global object will be checked.  gain 
of spy2 has been checked, and the use of spy2 will not be checked again. 
but if we call spy2 explicitly specifing "this" to a different global 
object other than env1's global object , the call will be access checked.
  CHECK(spy2->IsFunction());  

  {
    env2->SetSecurityToken(bar); // set a different token
    Context::Scope scope_env2(env2);

    // Call cross_domain_call, it should throw an exception
    v8::TryCatch try_catch(env1->GetIsolate());
    CHECK_EQ(true, Function::Cast(*spy2)->Call(env2, env2->Global(), 0, 
NULL).IsEmpty()); // spy2 can not be called in a different token context if 
explicitly specifing the recv para to a different context global object as 
above mentioned
    CHECK(try_catch.HasCaught());

    Local<Value> myarray = Function::Cast(*spy2)->Call(env2, 
env1->Global(), 0, NULL).ToLocalChecked(); // spy2 can be called in a 
different token context if explicitly specifing the recv para to the 
context global object where spy2 is bound compiled, that is env1 global 
object
    CHECK(myarray->IsArray());
  }

  {
    env2->SetSecurityToken(bar); // set a different token
    Context::Scope scope_env2(env2);
    
    // Call cross_domain_call, it should throw an exception
    v8::TryCatch try_catch(env1->GetIsolate());
    env2->Global()->Set(v8_str("spy2"), spy2); // spy2 can be set to a 
different token context's global object
    Local<Value> myobj = CompileRun("spy2()"); // if running syp2 as 
scripts, "this" of spy2 is always bound to the context global object where 
it's bound compiled  
    CHECK(myobj->IsArray());
    Local<Value> myx = v8::Object::Cast(*myobj)->Get(v8_str("x")); 
    CHECK(myx->IsInt32());
    CHECK_EQ(1, myx->Int32Value()); // it's can be verified that "this" 
pointed to env1 global object when spy2 is called

    myobj = CompileRun("new this.Array()");
    CHECK(myobj->IsArray());
    myx = v8::Object::Cast(*myobj)->Get(v8_str("x"));
    CHECK(myx->IsUndefined()); // it's can be verified that "this" did not 
point to env2 global object when spy2 is called

    CHECK(!try_catch.HasCaught());
  }
  
  {
    env2->SetSecurityToken(bar); // set a different token
    Context::Scope scope_env2(env2);

    Local<Value> empty_spy = env1->Global()->Get(v8_str("spy2")); // spy 
can not be required when entering the context with a different token 
because direct access to global object will be checked
    CHECK(empty_spy.IsEmpty());

    Local<Value> not_empty_spy = env1->Global()->Get(env1.local(), 
v8_str("spy2")).ToLocalChecked(); // spy2 can be required in this way. 
Final Question: Is this because Object.Get enterned the env1 context 
internally by specifing context para to env1.local() ?
    CHECK(not_empty_spy->IsFunction());
  }
}

thanks to all of you !

在 2018年6月1日星期五 UTC+8下午4:20:05,Toon Verwaest写道:
>
> If you have two contacts with different security tokens you're only 
> allowed, as an embedder, to leak explicitly access checked objects between 
> the two. Hence only objects that are backed by object templates with access 
> checks.
>
> The reason is that we don't check whether you have access for all objects. 
> That would be quite expensive especially in the generic case.
>
> Since we've had bugs in the past with objects accidentally leaking anyway, 
> we've tied down our compiler to check who is trying to compile where. 
> Otherwise leaking a single object easily leads to full access to the 
> context of the leaked object through code injection.
>
> Hth
>
> On Fri, Jun 1, 2018 at 9:46 AM Ben Noordhuis <in...@bnoordhuis.nl 
> <javascript:>> wrote:
>
>> On Thu, May 31, 2018 at 3:52 AM,  <fengx...@gmail.com <javascript:>> 
>> wrote:
>> > ur... I still can not get it.  In the following modification, I changed
>> > object x by scripts.
>> >
>> > Modification Three:
>> >
>> > TEST(EvalInAccessCheckedContext) {
>> >   v8::Isolate* isolate = CcTest::isolate();
>> >   v8::HandleScope scope(isolate);
>> >
>> >   v8::Local<v8::ObjectTemplate> obj_template =
>> > v8::ObjectTemplate::New(isolate);
>> >
>> >   //obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
>> >
>> >   v8::Local<Context> context0 = Context::New(isolate, NULL, 
>> obj_template);
>> >   v8::Local<Context> context1 = Context::New(isolate, NULL, 
>> obj_template);
>> >
>> >   Local<Value> foo = v8_str("foo");
>> >   Local<Value> bar = v8_str("bar");
>> >
>> >   // Set to different domains.
>> >   context0->SetSecurityToken(foo);
>> >   context1->SetSecurityToken(bar);
>> >
>> >   // Set up function in context0 that uses eval from context0.
>> >   context0->Enter();
>> >   v8::Local<v8::Value> fun = CompileRun(
>> >       "var x = {a:42};"
>> >       "(function() {"
>> >       "  var e = eval;"
>> >       "  return function(s) { return x; }"
>> >       "})()");
>> >   context0->Exit();
>> >
>> >   // Put the function into context1 and call it. Since the access check
>> >   // callback always returns true, the call succeeds even though the 
>> tokens
>> >   // are different.
>> >   context1->Enter();
>> >   context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
>> >   v8::Local<v8::Value> x_value = CompileRun("var c = fun('x'); c.a = 
>> 43; c.b
>> > = 45;"); //change x object by scripts
>> >   CHECK_EQ(45, x_value->Int32Value(context1).FromJust());
>> >   context1->Exit();
>> >
>> >   context0->Enter();
>> >   x_value = CompileRun("x.a");
>> >   CHECK_EQ(43, x_value->Int32Value(context0).FromJust()); // change is
>> > allowed
>> >
>> >   x_value = CompileRun("x.b");
>> >   CHECK_EQ(45, x_value->Int32Value(context0).FromJust()); // change is
>> > allowed
>> >   context0->Exit();
>> > }
>> >
>> > Modification Four :
>> >
>> > TEST(EvalInAccessCheckedContext) {
>> >   v8::Isolate* isolate = CcTest::isolate();
>> >   v8::HandleScope scope(isolate);
>> >
>> >   v8::Local<v8::ObjectTemplate> obj_template =
>> > v8::ObjectTemplate::New(isolate);
>> >
>> >   //obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
>> >
>> >   v8::Local<Context> context0 = Context::New(isolate, NULL, 
>> obj_template);
>> >   v8::Local<Context> context1 = Context::New(isolate, NULL, 
>> obj_template);
>> >
>> >   Local<Value> foo = v8_str("foo");
>> >   Local<Value> bar = v8_str("bar");
>> >
>> >   // Set to different domains.
>> >   context0->SetSecurityToken(foo);
>> >   context1->SetSecurityToken(bar);
>> >
>> >   // Set up function in context0 that uses eval from context0.
>> >   context0->Enter();
>> >   v8::Local<v8::Value> fun = CompileRun(
>> >       "var x = 42;"
>> >       "var y = function() {return x;};" // y is a function which is set 
>> up
>> > in context0.
>> >       "(function() {"
>> >       //"  var e = eval;" // this line will fail test
>> >       "  var e = y;"  // this line will pass test
>> >       "  return function(s) { return e(s); }"
>> >       "})()");
>> >   context0->Exit();
>> >
>> >   // Put the function into context1 and call it. Since the access check
>> >   // callback always returns true, the call succeeds even though the 
>> tokens
>> >   // are different.
>> >   context1->Enter();
>> >   context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
>> >   v8::Local<v8::Value> x_value = CompileRun("fun('x');");
>> >   CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
>> >   context1->Exit();
>> > }
>> >
>> > I also find another test case. In the test case, all operations are 
>> write by
>> > c++ code, and SetSecurityToken can control access.
>> >
>> > Another test case:
>> >
>> > THREADED_TEST(MultiContexts) {
>> >   v8::Isolate* isolate = CcTest::isolate();
>> >   v8::HandleScope scope(isolate);
>> >   v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
>> >   templ->Set(v8_str("dummy"),
>> >              v8::FunctionTemplate::New(isolate, DummyCallHandler));
>> >
>> >   Local<String> password = v8_str("Password");
>> >   Local<String> password2 = v8_str("Password2"); // another token
>> >   // Create an environment
>> >   LocalContext context0(0, templ);
>> >   context0->SetSecurityToken(password);
>> >   v8::Local<v8::Object> global0 = context0->Global();
>> >   CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
>> >             .FromJust());
>> >   CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
>> >                      .ToLocalChecked()
>> >                      ->Int32Value(context0.local())
>> >                      .FromJust());
>> >
>> >   // Create an independent environment
>> >   LocalContext context1(0, templ);
>> >   context1->SetSecurityToken(password2);// set another token
>> >   v8::Local<v8::Object> global1 = context1->Global();
>> >   CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
>> >             .FromJust());
>> >   CHECK(!global0->Equals(context1.local(), global1).FromJust());
>> >   CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom")) // 
>> this
>> > line will fail if tokens are not matched
>> >                      .ToLocalChecked()
>> >                      ->Int32Value(context0.local())
>> >                      .FromJust());
>> >
>> > //skip some codes below
>> > ...
>> > }
>>
>> Note that you need to set an access check callback to enable access
>> checks.  Since you commented out the SetAccessCheckCallback calls,
>> they aren't enabled.
>>
>> -- 
>> -- 
>> v8-users mailing list
>> v8-u...@googlegroups.com <javascript:>
>> http://groups.google.com/group/v8-users
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "v8-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to v8-users+u...@googlegroups.com <javascript:>.
>> For more options, visit https://groups.google.com/d/optout.
>>
> -- 
>
> Toon Verwaest |  Software Engineer, V8 |  Google Germany GmbH |  Erika-Mann 
> Str. 33, 80636 München 
>
> Registergericht und -nummer: Hamburg, HRB 86891 | Sitz der Gesellschaft: 
> Hamburg | Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to