On Wed, May 30, 2018 at 9:32 AM, <fengxing...@gmail.com> wrote: > I try to understand SetSecurityToken's function. So I modified > EvalInAccessCheckedContext test case in test-api.cc which is included in v8 > sourcecode. Follow is my modification. > > Modification One: > > 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); //comment > this line to ensure cross access only be controlled by SetSecurityToken > > 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;" > "(function() {" > " var e = eval;" > //" return function(s) { return e(s); }" // this line will fail test > because SecurityToken is not the same > " return function(s) { return eval(s); }" // this line will pass > test. but why? > "})()"); > 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(); > } > > > Modification Two: > > 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); //comment > this line to ensure cross access only be controlled by SetSecurityToken > > 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; }" // just return a object that's > defined in context0 > "})()"); > > v8::Local<v8::Value> x_value0 = CompileRun("x.a"); > CHECK_EQ(42, x_value0->Int32Value(context0).FromJust()); > > Local<v8::Object> obj = context0->Global()->Get(context0, > v8_str("x")).ToLocalChecked()->ToObject(); > obj->Set(context0, v8_str("a"), v8::Integer::New(context0->GetIsolate(), > 100)).FromJust(); > context0->Global()->Set(context0, v8_str("fun"), fun).FromJust(); > v8::Local<v8::Value> x_value00 = CompileRun("fun('x')"); > CHECK_EQ(100, x_value00->ToObject()->Get(context0, > v8_str("a")).ToLocalChecked()->Int32Value(context0).FromJust()); > > 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(100, x_value->ToObject()->Get(context1, > v8_str("a")).ToLocalChecked()->Int32Value(context1).FromJust()); > > x_value->ToObject()->Set(context1, v8_str("a"), > v8::Integer::New(context0->GetIsolate(), 102)).FromJust();// change x object > of context0 in context1 > context1->Exit(); > > context0->Enter(); > { > Local<v8::Object> obj = context0->Global()->Get(context0, > v8_str("x")).ToLocalChecked()->ToObject(); > CHECK_EQ(102, obj->Get(context0, > v8_str("a")).ToLocalChecked()->Int32Value(context0).FromJust()); // this > will pass. so why change is allowed? > > v8::Local<v8::Value> x_value00 = CompileRun("fun('x')"); > CHECK_EQ(102, x_value00->ToObject()->Get(context0, > v8_str("a")).ToLocalChecked()->Int32Value(context0).FromJust()); > } > context0->Exit(); > }
Is your question why direct eval() works but indirect eval() doesn't with different security tokens? It's because direct eval() isn't really a function, it's closer to a keyword. It has to be because of its runtime semantics of evaluating the string in the context of the surrounding code. Indirect eval() however is a regular function that is subject to access checks. Access checks are invoked when trying to access objects. Context A can pass on objects from context B as long as it doesn't access it, where access = read or write properties, invoke the [[Call]] operation of function objects, etc. -- -- 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.