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.