LCOV - code coverage report
Current view: top level - test/cctest - test-access-checks.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 194 224 86.6 %
Date: 2019-04-17 Functions: 25 33 75.8 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : 
       7             : #include "test/cctest/cctest.h"
       8             : 
       9             : namespace {
      10             : 
      11             : int32_t g_cross_context_int = 0;
      12             : 
      13             : bool g_expect_interceptor_call = false;
      14             : 
      15          60 : void NamedGetter(v8::Local<v8::Name> property,
      16             :                  const v8::PropertyCallbackInfo<v8::Value>& info) {
      17          60 :   CHECK(g_expect_interceptor_call);
      18             :   v8::Isolate* isolate = info.GetIsolate();
      19          60 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      20         180 :   if (property->Equals(context, v8_str("cross_context_int")).FromJust())
      21          20 :     info.GetReturnValue().Set(g_cross_context_int);
      22          60 : }
      23             : 
      24          20 : void NamedSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value,
      25             :                  const v8::PropertyCallbackInfo<v8::Value>& info) {
      26          20 :   CHECK(g_expect_interceptor_call);
      27             :   v8::Isolate* isolate = info.GetIsolate();
      28          20 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      29          60 :   if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
      30           0 :     return;
      31          20 :   if (value->IsInt32()) {
      32          40 :     g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
      33             :   }
      34             :   info.GetReturnValue().Set(value);
      35             : }
      36             : 
      37           0 : void NamedQuery(v8::Local<v8::Name> property,
      38             :                 const v8::PropertyCallbackInfo<v8::Integer>& info) {
      39           0 :   CHECK(g_expect_interceptor_call);
      40             :   v8::Isolate* isolate = info.GetIsolate();
      41           0 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      42           0 :   if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
      43           0 :     return;
      44             :   info.GetReturnValue().Set(v8::DontDelete);
      45             : }
      46             : 
      47           0 : void NamedDeleter(v8::Local<v8::Name> property,
      48             :                   const v8::PropertyCallbackInfo<v8::Boolean>& info) {
      49           0 :   CHECK(g_expect_interceptor_call);
      50             :   v8::Isolate* isolate = info.GetIsolate();
      51           0 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      52           0 :   if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
      53           0 :     return;
      54             :   info.GetReturnValue().Set(false);
      55             : }
      56             : 
      57          20 : void NamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
      58          20 :   CHECK(g_expect_interceptor_call);
      59             :   v8::Isolate* isolate = info.GetIsolate();
      60          20 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      61          20 :   v8::Local<v8::Array> names = v8::Array::New(isolate, 1);
      62          60 :   names->Set(context, 0, v8_str("cross_context_int")).FromJust();
      63             :   info.GetReturnValue().Set(names);
      64          20 : }
      65             : 
      66          40 : void IndexedGetter(uint32_t index,
      67             :                    const v8::PropertyCallbackInfo<v8::Value>& info) {
      68          40 :   CHECK(g_expect_interceptor_call);
      69          40 :   if (index == 7) info.GetReturnValue().Set(g_cross_context_int);
      70          40 : }
      71             : 
      72           0 : void IndexedSetter(uint32_t index, v8::Local<v8::Value> value,
      73             :                    const v8::PropertyCallbackInfo<v8::Value>& info) {
      74           0 :   CHECK(g_expect_interceptor_call);
      75             :   v8::Isolate* isolate = info.GetIsolate();
      76           0 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
      77           0 :   if (index != 7) return;
      78           0 :   if (value->IsInt32()) {
      79           0 :     g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
      80             :   }
      81             :   info.GetReturnValue().Set(value);
      82             : }
      83             : 
      84           0 : void IndexedQuery(uint32_t index,
      85             :                   const v8::PropertyCallbackInfo<v8::Integer>& info) {
      86           0 :   CHECK(g_expect_interceptor_call);
      87           0 :   if (index == 7) info.GetReturnValue().Set(v8::DontDelete);
      88           0 : }
      89             : 
      90           0 : void IndexedDeleter(uint32_t index,
      91             :                     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
      92           0 :   CHECK(g_expect_interceptor_call);
      93           0 :   if (index == 7) info.GetReturnValue().Set(false);
      94           0 : }
      95             : 
      96          20 : void IndexedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
      97          20 :   CHECK(g_expect_interceptor_call);
      98             :   v8::Isolate* isolate = info.GetIsolate();
      99          20 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     100          20 :   v8::Local<v8::Array> names = v8::Array::New(isolate, 1);
     101          60 :   names->Set(context, 0, v8_str("7")).FromJust();
     102             :   info.GetReturnValue().Set(names);
     103          20 : }
     104             : 
     105           5 : void MethodGetter(v8::Local<v8::Name> property,
     106             :                   const v8::PropertyCallbackInfo<v8::Value>& info) {
     107             :   v8::Isolate* isolate = info.GetIsolate();
     108           5 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     109             : 
     110             :   v8::Local<v8::External> data = info.Data().As<v8::External>();
     111             :   v8::Local<v8::FunctionTemplate>& function_template =
     112           5 :       *reinterpret_cast<v8::Local<v8::FunctionTemplate>*>(data->Value());
     113             : 
     114             :   info.GetReturnValue().Set(
     115           5 :       function_template->GetFunction(context).ToLocalChecked());
     116           5 : }
     117             : 
     118           5 : void MethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     119             :   info.GetReturnValue().Set(8);
     120           5 : }
     121             : 
     122           5 : void NamedGetterThrowsException(
     123             :     v8::Local<v8::Name> property,
     124             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     125          10 :   info.GetIsolate()->ThrowException(v8_str("exception"));
     126           5 : }
     127             : 
     128           5 : void NamedSetterThrowsException(
     129             :     v8::Local<v8::Name> property, v8::Local<v8::Value> value,
     130             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     131          10 :   info.GetIsolate()->ThrowException(v8_str("exception"));
     132           5 : }
     133             : 
     134           5 : void IndexedGetterThrowsException(
     135             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
     136          10 :   info.GetIsolate()->ThrowException(v8_str("exception"));
     137           5 : }
     138             : 
     139           5 : void IndexedSetterThrowsException(
     140             :     uint32_t index, v8::Local<v8::Value> value,
     141             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     142          10 :   info.GetIsolate()->ThrowException(v8_str("exception"));
     143           5 : }
     144             : 
     145          90 : bool AccessCheck(v8::Local<v8::Context> accessing_context,
     146             :                  v8::Local<v8::Object> accessed_object,
     147             :                  v8::Local<v8::Value> data) {
     148          90 :   return false;
     149             : }
     150             : 
     151          20 : void GetCrossContextInt(v8::Local<v8::String> property,
     152             :                         const v8::PropertyCallbackInfo<v8::Value>& info) {
     153          20 :   CHECK(!g_expect_interceptor_call);
     154          20 :   info.GetReturnValue().Set(g_cross_context_int);
     155          20 : }
     156             : 
     157          20 : void SetCrossContextInt(v8::Local<v8::String> property,
     158             :                         v8::Local<v8::Value> value,
     159             :                         const v8::PropertyCallbackInfo<void>& info) {
     160          20 :   CHECK(!g_expect_interceptor_call);
     161             :   v8::Isolate* isolate = info.GetIsolate();
     162          20 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     163          20 :   if (value->IsInt32()) {
     164          40 :     g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
     165             :   }
     166          20 : }
     167             : 
     168          20 : void Return42(v8::Local<v8::String> property,
     169             :               const v8::PropertyCallbackInfo<v8::Value>& info) {
     170             :   info.GetReturnValue().Set(42);
     171          20 : }
     172             : 
     173          20 : void CheckCanRunScriptInContext(v8::Isolate* isolate,
     174             :                                 v8::Local<v8::Context> context) {
     175          40 :   v8::HandleScope handle_scope(isolate);
     176             :   v8::Context::Scope context_scope(context);
     177             : 
     178          20 :   g_expect_interceptor_call = false;
     179          20 :   g_cross_context_int = 0;
     180             : 
     181             :   // Running script in this context should work.
     182          20 :   CompileRunChecked(isolate, "this.foo = 42; this[23] = true;");
     183          20 :   ExpectInt32("this.all_can_read", 42);
     184          20 :   CompileRunChecked(isolate, "this.cross_context_int = 23");
     185          20 :   CHECK_EQ(g_cross_context_int, 23);
     186          20 :   ExpectInt32("this.cross_context_int", 23);
     187          20 : }
     188             : 
     189          20 : void CheckCrossContextAccess(v8::Isolate* isolate,
     190             :                              v8::Local<v8::Context> accessing_context,
     191             :                              v8::Local<v8::Object> accessed_object) {
     192          40 :   v8::HandleScope handle_scope(isolate);
     193          40 :   accessing_context->Global()
     194          80 :       ->Set(accessing_context, v8_str("other"), accessed_object)
     195             :       .FromJust();
     196             :   v8::Context::Scope context_scope(accessing_context);
     197             : 
     198          20 :   g_expect_interceptor_call = true;
     199          20 :   g_cross_context_int = 23;
     200             : 
     201             :   {
     202          40 :     v8::TryCatch try_catch(isolate);
     203          40 :     CHECK(CompileRun(accessing_context, "this.other.foo").IsEmpty());
     204             :   }
     205             :   {
     206          40 :     v8::TryCatch try_catch(isolate);
     207          40 :     CHECK(CompileRun(accessing_context, "this.other[23]").IsEmpty());
     208             :   }
     209             : 
     210             :   // AllCanRead properties are also inaccessible.
     211             :   {
     212          40 :     v8::TryCatch try_catch(isolate);
     213          40 :     CHECK(CompileRun(accessing_context, "this.other.all_can_read").IsEmpty());
     214             :   }
     215             : 
     216             :   // Intercepted properties are accessible, however.
     217          20 :   ExpectInt32("this.other.cross_context_int", 23);
     218          20 :   CompileRunChecked(isolate, "this.other.cross_context_int = 42");
     219          20 :   ExpectInt32("this.other[7]", 42);
     220             :   ExpectString("JSON.stringify(Object.getOwnPropertyNames(this.other))",
     221          20 :                "[\"7\",\"cross_context_int\"]");
     222          20 : }
     223             : 
     224           5 : void CheckCrossContextAccessWithException(
     225             :     v8::Isolate* isolate, v8::Local<v8::Context> accessing_context,
     226             :     v8::Local<v8::Object> accessed_object) {
     227          10 :   v8::HandleScope handle_scope(isolate);
     228          10 :   accessing_context->Global()
     229          20 :       ->Set(accessing_context, v8_str("other"), accessed_object)
     230             :       .FromJust();
     231             :   v8::Context::Scope context_scope(accessing_context);
     232             : 
     233             :   {
     234          10 :     v8::TryCatch try_catch(isolate);
     235             :     CompileRun("this.other.should_throw");
     236           5 :     CHECK(try_catch.HasCaught());
     237          10 :     CHECK(try_catch.Exception()->IsString());
     238          15 :     CHECK(v8_str("exception")
     239             :               ->Equals(accessing_context, try_catch.Exception())
     240             :               .FromJust());
     241             :   }
     242             : 
     243             :   {
     244          10 :     v8::TryCatch try_catch(isolate);
     245             :     CompileRun("this.other.should_throw = 8");
     246           5 :     CHECK(try_catch.HasCaught());
     247          10 :     CHECK(try_catch.Exception()->IsString());
     248          15 :     CHECK(v8_str("exception")
     249             :               ->Equals(accessing_context, try_catch.Exception())
     250             :               .FromJust());
     251             :   }
     252             : 
     253             :   {
     254          10 :     v8::TryCatch try_catch(isolate);
     255             :     CompileRun("this.other[42]");
     256           5 :     CHECK(try_catch.HasCaught());
     257          10 :     CHECK(try_catch.Exception()->IsString());
     258          15 :     CHECK(v8_str("exception")
     259             :               ->Equals(accessing_context, try_catch.Exception())
     260             :               .FromJust());
     261             :   }
     262             : 
     263             :   {
     264          10 :     v8::TryCatch try_catch(isolate);
     265             :     CompileRun("this.other[42] = 8");
     266           5 :     CHECK(try_catch.HasCaught());
     267          10 :     CHECK(try_catch.Exception()->IsString());
     268          15 :     CHECK(v8_str("exception")
     269             :               ->Equals(accessing_context, try_catch.Exception())
     270             :               .FromJust());
     271             :   }
     272           5 : }
     273             : 
     274           0 : void Ctor(const v8::FunctionCallbackInfo<v8::Value>& info) {
     275           0 :   CHECK(info.IsConstructCall());
     276           0 : }
     277             : 
     278             : }  // namespace
     279             : 
     280       26644 : TEST(AccessCheckWithInterceptor) {
     281           5 :   v8::Isolate* isolate = CcTest::isolate();
     282          10 :   v8::HandleScope scope(isolate);
     283             :   v8::Local<v8::ObjectTemplate> global_template =
     284           5 :       v8::ObjectTemplate::New(isolate);
     285           5 :   global_template->SetAccessCheckCallbackAndHandler(
     286             :       AccessCheck,
     287             :       v8::NamedPropertyHandlerConfiguration(
     288             :           NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator),
     289             :       v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter,
     290             :                                               IndexedQuery, IndexedDeleter,
     291           5 :                                               IndexedEnumerator));
     292          10 :   global_template->SetNativeDataProperty(
     293           5 :       v8_str("cross_context_int"), GetCrossContextInt, SetCrossContextInt);
     294          10 :   global_template->SetNativeDataProperty(
     295             :       v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(),
     296           5 :       v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ);
     297             : 
     298             :   v8::Local<v8::Context> context0 =
     299           5 :       v8::Context::New(isolate, nullptr, global_template);
     300           5 :   CheckCanRunScriptInContext(isolate, context0);
     301             : 
     302             :   // Create another context.
     303             :   v8::Local<v8::Context> context1 =
     304           5 :       v8::Context::New(isolate, nullptr, global_template);
     305           5 :   CheckCrossContextAccess(isolate, context1, context0->Global());
     306           5 : }
     307             : 
     308       26644 : TEST(CallFunctionWithRemoteContextReceiver) {
     309           5 :   v8::Isolate* isolate = CcTest::isolate();
     310          10 :   v8::HandleScope scope(isolate);
     311             :   v8::Local<v8::FunctionTemplate> global_template =
     312           5 :       v8::FunctionTemplate::New(isolate);
     313             : 
     314             :   v8::Local<v8::Signature> signature =
     315           5 :       v8::Signature::New(isolate, global_template);
     316             :   v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(
     317             :       isolate, MethodCallback, v8::External::New(isolate, &function_template),
     318          10 :       signature);
     319             : 
     320          15 :   global_template->InstanceTemplate()->SetAccessCheckCallbackAndHandler(
     321             :       AccessCheck, v8::NamedPropertyHandlerConfiguration(
     322             :                        MethodGetter, nullptr, nullptr, nullptr, nullptr,
     323             :                        v8::External::New(isolate, &function_template)),
     324           5 :       v8::IndexedPropertyHandlerConfiguration());
     325             : 
     326             :   v8::Local<v8::Object> accessed_object =
     327           5 :       v8::Context::NewRemoteContext(isolate,
     328          10 :                                     global_template->InstanceTemplate())
     329             :           .ToLocalChecked();
     330             :   v8::Local<v8::Context> accessing_context =
     331          10 :       v8::Context::New(isolate, nullptr, global_template->InstanceTemplate());
     332             : 
     333          10 :   v8::HandleScope handle_scope(isolate);
     334          10 :   accessing_context->Global()
     335          20 :       ->Set(accessing_context, v8_str("other"), accessed_object)
     336             :       .FromJust();
     337             :   v8::Context::Scope context_scope(accessing_context);
     338             : 
     339             :   {
     340          10 :     v8::TryCatch try_catch(isolate);
     341           5 :     ExpectInt32("this.other.method()", 8);
     342           5 :     CHECK(!try_catch.HasCaught());
     343             :   }
     344           5 : }
     345             : 
     346       26644 : TEST(AccessCheckWithExceptionThrowingInterceptor) {
     347           5 :   v8::Isolate* isolate = CcTest::isolate();
     348             :   isolate->SetFailedAccessCheckCallbackFunction([](v8::Local<v8::Object> target,
     349             :                                                    v8::AccessType type,
     350           0 :                                                    v8::Local<v8::Value> data) {
     351           0 :     UNREACHABLE();  // This should never be called.
     352           5 :   });
     353             : 
     354          10 :   v8::HandleScope scope(isolate);
     355             :   v8::Local<v8::ObjectTemplate> global_template =
     356           5 :       v8::ObjectTemplate::New(isolate);
     357           5 :   global_template->SetAccessCheckCallbackAndHandler(
     358             :       AccessCheck, v8::NamedPropertyHandlerConfiguration(
     359             :                        NamedGetterThrowsException, NamedSetterThrowsException),
     360             :       v8::IndexedPropertyHandlerConfiguration(IndexedGetterThrowsException,
     361           5 :                                               IndexedSetterThrowsException));
     362             : 
     363             :   // Create two contexts.
     364             :   v8::Local<v8::Context> context0 =
     365           5 :       v8::Context::New(isolate, nullptr, global_template);
     366             :   v8::Local<v8::Context> context1 =
     367           5 :       v8::Context::New(isolate, nullptr, global_template);
     368             : 
     369           5 :   CheckCrossContextAccessWithException(isolate, context1, context0->Global());
     370           5 : }
     371             : 
     372       26644 : TEST(NewRemoteContext) {
     373           5 :   v8::Isolate* isolate = CcTest::isolate();
     374          10 :   v8::HandleScope scope(isolate);
     375             :   v8::Local<v8::ObjectTemplate> global_template =
     376           5 :       v8::ObjectTemplate::New(isolate);
     377           5 :   global_template->SetAccessCheckCallbackAndHandler(
     378             :       AccessCheck,
     379             :       v8::NamedPropertyHandlerConfiguration(
     380             :           NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator),
     381             :       v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter,
     382             :                                               IndexedQuery, IndexedDeleter,
     383           5 :                                               IndexedEnumerator));
     384          10 :   global_template->SetNativeDataProperty(
     385           5 :       v8_str("cross_context_int"), GetCrossContextInt, SetCrossContextInt);
     386          10 :   global_template->SetNativeDataProperty(
     387             :       v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(),
     388           5 :       v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ);
     389             : 
     390             :   v8::Local<v8::Object> global0 =
     391          10 :       v8::Context::NewRemoteContext(isolate, global_template).ToLocalChecked();
     392             : 
     393             :   // Create a real context.
     394             :   {
     395          10 :     v8::HandleScope other_scope(isolate);
     396             :     v8::Local<v8::Context> context1 =
     397           5 :         v8::Context::New(isolate, nullptr, global_template);
     398             : 
     399           5 :     CheckCrossContextAccess(isolate, context1, global0);
     400             :   }
     401             : 
     402             :   // Create a context using the detached global.
     403             :   {
     404          10 :     v8::HandleScope other_scope(isolate);
     405             :     v8::Local<v8::Context> context2 =
     406           5 :         v8::Context::New(isolate, nullptr, global_template, global0);
     407             : 
     408           5 :     CheckCanRunScriptInContext(isolate, context2);
     409             :   }
     410             : 
     411             :   // Turn a regular context into a remote context.
     412             :   {
     413          10 :     v8::HandleScope other_scope(isolate);
     414             :     v8::Local<v8::Context> context3 =
     415           5 :         v8::Context::New(isolate, nullptr, global_template);
     416             : 
     417           5 :     CheckCanRunScriptInContext(isolate, context3);
     418             : 
     419             :     // Turn the global object into a remote context, and try to access it.
     420           5 :     v8::Local<v8::Object> context3_global = context3->Global();
     421           5 :     context3->DetachGlobal();
     422             :     v8::Local<v8::Object> global3 =
     423          10 :         v8::Context::NewRemoteContext(isolate, global_template, context3_global)
     424             :             .ToLocalChecked();
     425             :     v8::Local<v8::Context> context4 =
     426           5 :         v8::Context::New(isolate, nullptr, global_template);
     427             : 
     428           5 :     CheckCrossContextAccess(isolate, context4, global3);
     429             : 
     430             :     // Turn it back into a regular context.
     431             :     v8::Local<v8::Context> context5 =
     432           5 :         v8::Context::New(isolate, nullptr, global_template, global3);
     433             : 
     434           5 :     CheckCanRunScriptInContext(isolate, context5);
     435             :   }
     436           5 : }
     437             : 
     438       26644 : TEST(NewRemoteInstance) {
     439           5 :   v8::Isolate* isolate = CcTest::isolate();
     440          10 :   v8::HandleScope scope(isolate);
     441             :   v8::Local<v8::FunctionTemplate> tmpl =
     442           5 :       v8::FunctionTemplate::New(isolate, Ctor);
     443           5 :   v8::Local<v8::ObjectTemplate> instance = tmpl->InstanceTemplate();
     444           5 :   instance->SetAccessCheckCallbackAndHandler(
     445             :       AccessCheck,
     446             :       v8::NamedPropertyHandlerConfiguration(
     447             :           NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator),
     448             :       v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter,
     449             :                                               IndexedQuery, IndexedDeleter,
     450           5 :                                               IndexedEnumerator));
     451          10 :   tmpl->SetNativeDataProperty(
     452             :       v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(),
     453           5 :       v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ);
     454             : 
     455          10 :   v8::Local<v8::Object> obj = tmpl->NewRemoteInstance().ToLocalChecked();
     456             : 
     457           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     458           5 :   CheckCrossContextAccess(isolate, context, obj);
     459       79922 : }

Generated by: LCOV version 1.10