Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 96d07a859b296b5223d7355f56d1fbb591535b17..c8d9da209b692f89a04814583c13b6e1315bb507 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -644,6 +644,77 @@ static void GetOwnPropertyImplementation(JSObject* obj, |
} |
+static bool CheckAccessException(LookupResult* result, |
+ v8::AccessType access_type) { |
+ if (result->type() == CALLBACKS) { |
+ Object* callback = result->GetCallbackObject(); |
+ if (callback->IsAccessorInfo()) { |
+ AccessorInfo* info = AccessorInfo::cast(callback); |
+ bool can_access = |
+ (access_type == v8::ACCESS_HAS && |
+ (info->all_can_read() || info->all_can_write())) || |
+ (access_type == v8::ACCESS_GET && info->all_can_read()) || |
+ (access_type == v8::ACCESS_SET && info->all_can_write()); |
+ return can_access; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
+static bool CheckAccess(JSObject* obj, |
+ String* name, |
+ LookupResult* result, |
+ v8::AccessType access_type) { |
+ ASSERT(result->IsProperty()); |
+ |
+ JSObject* holder = result->holder(); |
+ JSObject* current = obj; |
+ while (true) { |
+ if (current->IsAccessCheckNeeded() && |
+ !Top::MayNamedAccess(current, name, access_type)) { |
+ // Access check callback denied the access, but some properties |
+ // can have a special permissions which override callbacks descision |
+ // (currently see v8::AccessControl). |
+ break; |
+ } |
+ |
+ if (current == holder) { |
+ return true; |
+ } |
+ |
+ current = JSObject::cast(current->GetPrototype()); |
+ } |
+ |
+ // API callbacks can have per callback access exceptions. |
+ switch (result->type()) { |
+ case CALLBACKS: { |
+ if (CheckAccessException(result, access_type)) { |
+ return true; |
+ } |
+ break; |
+ } |
+ case INTERCEPTOR: { |
+ // If the object has an interceptor, try real named properties. |
+ // Overwrite the result to fetch the correct property later. |
+ holder->LookupRealNamedProperty(name, result); |
+ if (result->IsProperty()) { |
+ if (CheckAccessException(result, access_type)) { |
+ return true; |
+ } |
+ } |
+ break; |
+ } |
+ default: |
+ break; |
+ } |
+ |
+ Top::ReportFailedAccessCheck(current, access_type); |
+ return false; |
+} |
+ |
+ |
// Enumerator used as indices into the array returned from GetOwnProperty |
enum PropertyDescriptorIndices { |
IS_ACCESSOR_INDEX, |
@@ -746,6 +817,10 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) { |
return Heap::undefined_value(); |
} |
+ if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) { |
+ return Heap::undefined_value(); |
+ } |
+ |
elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum())); |
elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete())); |
@@ -754,16 +829,22 @@ static MaybeObject* Runtime_GetOwnProperty(Arguments args) { |
if (is_js_accessor) { |
// __defineGetter__/__defineSetter__ callback. |
- FixedArray* structure = FixedArray::cast(result.GetCallbackObject()); |
elms->set(IS_ACCESSOR_INDEX, Heap::true_value()); |
- elms->set(GETTER_INDEX, structure->get(0)); |
- elms->set(SETTER_INDEX, structure->get(1)); |
+ |
+ FixedArray* structure = FixedArray::cast(result.GetCallbackObject()); |
+ if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) { |
+ elms->set(GETTER_INDEX, structure->get(0)); |
+ } |
+ if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) { |
+ elms->set(SETTER_INDEX, structure->get(1)); |
+ } |
} else { |
elms->set(IS_ACCESSOR_INDEX, Heap::false_value()); |
elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly())); |
PropertyAttributes attrs; |
Object* value; |
+ // GetProperty will check access and report any violations. |
{ MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); |
if (!maybe_value->ToObject(&value)) return maybe_value; |
} |