| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 6645)
|
| +++ src/runtime.cc (working copy)
|
| @@ -644,6 +644,90 @@
|
| }
|
|
|
|
|
| +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;
|
| +}
|
| +
|
| +
|
| +// TODO(1095): we should traverse hidden prototype hierachy as well.
|
| +static bool CheckElementAccess(JSObject* obj,
|
| + uint32_t index,
|
| + v8::AccessType access_type) {
|
| + if (obj->IsAccessCheckNeeded() &&
|
| + !Top::MayIndexedAccess(obj, index, access_type)) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +
|
| // Enumerator used as indices into the array returned from GetOwnProperty
|
| enum PropertyDescriptorIndices {
|
| IS_ACCESSOR_INDEX,
|
| @@ -686,7 +770,7 @@
|
| // subsequent cases.
|
| Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
|
| Handle<String> str(String::cast(js_value->value()));
|
| - Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
|
| + Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
|
|
|
| elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
|
| elms->set(VALUE_INDEX, *substr);
|
| @@ -699,8 +783,7 @@
|
| case JSObject::INTERCEPTED_ELEMENT:
|
| case JSObject::FAST_ELEMENT: {
|
| elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
|
| - Handle<Object> element = GetElement(Handle<Object>(obj), index);
|
| - elms->set(VALUE_INDEX, *element);
|
| + elms->set(VALUE_INDEX, *GetElement(obj, index));
|
| elms->set(WRITABLE_INDEX, Heap::true_value());
|
| elms->set(ENUMERABLE_INDEX, Heap::true_value());
|
| elms->set(CONFIGURABLE_INDEX, Heap::true_value());
|
| @@ -708,7 +791,14 @@
|
| }
|
|
|
| case JSObject::DICTIONARY_ELEMENT: {
|
| - NumberDictionary* dictionary = obj->element_dictionary();
|
| + Handle<JSObject> holder = obj;
|
| + if (obj->IsJSGlobalProxy()) {
|
| + Object* proto = obj->GetPrototype();
|
| + if (proto->IsNull()) return Heap::undefined_value();
|
| + ASSERT(proto->IsJSGlobalObject());
|
| + holder = Handle<JSObject>(JSObject::cast(proto));
|
| + }
|
| + NumberDictionary* dictionary = holder->element_dictionary();
|
| int entry = dictionary->FindEntry(index);
|
| ASSERT(entry != NumberDictionary::kNotFound);
|
| PropertyDetails details = dictionary->DetailsAt(entry);
|
| @@ -718,14 +808,18 @@
|
| FixedArray* callbacks =
|
| FixedArray::cast(dictionary->ValueAt(entry));
|
| elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
|
| - elms->set(GETTER_INDEX, callbacks->get(0));
|
| - elms->set(SETTER_INDEX, callbacks->get(1));
|
| + if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
|
| + elms->set(GETTER_INDEX, callbacks->get(0));
|
| + }
|
| + if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
|
| + elms->set(SETTER_INDEX, callbacks->get(1));
|
| + }
|
| break;
|
| }
|
| case NORMAL:
|
| // This is a data property.
|
| elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
|
| - elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
|
| + elms->set(VALUE_INDEX, *GetElement(obj, index));
|
| elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
|
| break;
|
| default:
|
| @@ -746,6 +840,10 @@
|
| return Heap::undefined_value();
|
| }
|
|
|
| + if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
|
| + return Heap::false_value();
|
| + }
|
| +
|
| elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
|
| elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
|
|
|
| @@ -754,16 +852,22 @@
|
|
|
| if (is_js_accessor) {
|
| // __defineGetter__/__defineSetter__ callback.
|
| + elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
|
| +
|
| 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));
|
| + 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;
|
| }
|
|
|