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 void NamedGetter(v8::Local<v8::Name> property, 14 const v8::PropertyCallbackInfo<v8::Value>& info) { 15 v8::Isolate* isolate = info.GetIsolate(); 16 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 17 if (property->Equals(context, v8_str("cross_context_int")).FromJust()) 18 info.GetReturnValue().Set(g_cross_context_int); 19 } 20 21 void NamedSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value, 22 const v8::PropertyCallbackInfo<v8::Value>& info) { 23 v8::Isolate* isolate = info.GetIsolate(); 24 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 25 if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) 26 return; 27 if (value->IsInt32()) { 28 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value(); 29 } 30 info.GetReturnValue().Set(value); 31 } 32 33 void NamedQuery(v8::Local<v8::Name> property, 34 const v8::PropertyCallbackInfo<v8::Integer>& info) { 35 v8::Isolate* isolate = info.GetIsolate(); 36 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 37 if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) 38 return; 39 info.GetReturnValue().Set(v8::DontDelete); 40 } 41 42 void NamedDeleter(v8::Local<v8::Name> property, 43 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 44 v8::Isolate* isolate = info.GetIsolate(); 45 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 46 if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) 47 return; 48 info.GetReturnValue().Set(false); 49 } 50 51 void NamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 52 v8::Isolate* isolate = info.GetIsolate(); 53 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 54 v8::Local<v8::Array> names = v8::Array::New(isolate, 1); 55 names->Set(context, 0, v8_str("cross_context_int")).FromJust(); 56 info.GetReturnValue().Set(names); 57 } 58 59 void IndexedGetter(uint32_t index, 60 const v8::PropertyCallbackInfo<v8::Value>& info) { 61 if (index == 7) info.GetReturnValue().Set(g_cross_context_int); 62 } 63 64 void IndexedSetter(uint32_t index, v8::Local<v8::Value> value, 65 const v8::PropertyCallbackInfo<v8::Value>& info) { 66 v8::Isolate* isolate = info.GetIsolate(); 67 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 68 if (index != 7) return; 69 if (value->IsInt32()) { 70 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value(); 71 } 72 info.GetReturnValue().Set(value); 73 } 74 75 void IndexedQuery(uint32_t index, 76 const v8::PropertyCallbackInfo<v8::Integer>& info) { 77 if (index == 7) info.GetReturnValue().Set(v8::DontDelete); 78 } 79 80 void IndexedDeleter(uint32_t index, 81 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 82 if (index == 7) info.GetReturnValue().Set(false); 83 } 84 85 void IndexedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 86 v8::Isolate* isolate = info.GetIsolate(); 87 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 88 v8::Local<v8::Array> names = v8::Array::New(isolate, 1); 89 names->Set(context, 0, v8_str("7")).FromJust(); 90 info.GetReturnValue().Set(names); 91 } 92 93 bool AccessCheck(v8::Local<v8::Context> accessing_context, 94 v8::Local<v8::Object> accessed_object, 95 v8::Local<v8::Value> data) { 96 return false; 97 } 98 99 void GetCrossContextInt(v8::Local<v8::String> property, 100 const v8::PropertyCallbackInfo<v8::Value>& info) { 101 info.GetReturnValue().Set(g_cross_context_int); 102 } 103 104 void SetCrossContextInt(v8::Local<v8::String> property, 105 v8::Local<v8::Value> value, 106 const v8::PropertyCallbackInfo<void>& info) { 107 v8::Isolate* isolate = info.GetIsolate(); 108 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 109 if (value->IsInt32()) { 110 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value(); 111 } 112 } 113 114 void Return42(v8::Local<v8::String> property, 115 const v8::PropertyCallbackInfo<v8::Value>& info) { 116 info.GetReturnValue().Set(42); 117 } 118 119 } // namespace 120 121 TEST(AccessCheckWithInterceptor) { 122 v8::Isolate* isolate = CcTest::isolate(); 123 v8::HandleScope scope(isolate); 124 v8::Local<v8::ObjectTemplate> global_template = 125 v8::ObjectTemplate::New(isolate); 126 global_template->SetAccessCheckCallbackAndHandler( 127 AccessCheck, 128 v8::NamedPropertyHandlerConfiguration( 129 NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator), 130 v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter, 131 IndexedQuery, IndexedDeleter, 132 IndexedEnumerator)); 133 global_template->SetNativeDataProperty( 134 v8_str("cross_context_int"), GetCrossContextInt, SetCrossContextInt); 135 global_template->SetNativeDataProperty( 136 v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(), 137 v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ); 138 139 v8::Local<v8::Context> context0 = 140 v8::Context::New(isolate, nullptr, global_template); 141 context0->Enter(); 142 143 // Running script in this context should work. 144 CompileRunChecked(isolate, "this.foo = 42; this[23] = true;"); 145 ExpectInt32("this.all_can_read", 42); 146 CompileRunChecked(isolate, "this.cross_context_int = 23"); 147 CHECK_EQ(g_cross_context_int, 23); 148 ExpectInt32("this.cross_context_int", 23); 149 150 // Create another context. 151 { 152 v8::HandleScope other_scope(isolate); 153 v8::Local<v8::Context> context1 = 154 v8::Context::New(isolate, nullptr, global_template); 155 context1->Global() 156 ->Set(context1, v8_str("other"), context0->Global()) 157 .FromJust(); 158 v8::Context::Scope context_scope(context1); 159 160 { 161 v8::TryCatch try_catch(isolate); 162 CHECK(CompileRun(context1, "this.other.foo").IsEmpty()); 163 } 164 { 165 v8::TryCatch try_catch(isolate); 166 CHECK(CompileRun(context1, "this.other[23]").IsEmpty()); 167 } 168 169 // AllCanRead properties are also inaccessible. 170 { 171 v8::TryCatch try_catch(isolate); 172 CHECK(CompileRun(context1, "this.other.all_can_read").IsEmpty()); 173 } 174 175 // Intercepted properties are accessible, however. 176 ExpectInt32("this.other.cross_context_int", 23); 177 CompileRunChecked(isolate, "this.other.cross_context_int = 42"); 178 ExpectInt32("this.other[7]", 42); 179 ExpectString("JSON.stringify(Object.getOwnPropertyNames(this.other))", 180 "[\"7\",\"cross_context_int\"]"); 181 } 182 } 183