Commit 893b8320 authored by lrn@chromium.org's avatar lrn@chromium.org

Added access check to Runtime_GetPrototype.

BUG=93759

Review URL: http://codereview.chromium.org/7701023

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9016 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2b024e3d
......@@ -683,8 +683,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Object* obj = args[0];
CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
Object* obj = input_obj;
// We don't expect access checks to be needed on JSProxy objects.
ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
do {
if (obj->IsAccessCheckNeeded() &&
!isolate->MayNamedAccess(JSObject::cast(obj),
isolate->heap()->Proto_symbol(),
v8::ACCESS_GET)) {
isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
return isolate->heap()->undefined_value();
}
obj = obj->GetPrototype();
} while (obj->IsJSObject() &&
JSObject::cast(obj)->map()->is_hidden_prototype());
......
......@@ -638,38 +638,6 @@ function CallTrap2(handler, name, defaultTrap, x, y) {
}
// ES5 section 8.12.2.
function GetProperty(obj, p) {
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
var descriptor = CallTrap1(obj, "getPropertyDescriptor", void 0, p);
if (IS_UNDEFINED(descriptor)) return descriptor;
var desc = ToCompletePropertyDescriptor(descriptor);
if (!desc.isConfigurable()) {
throw MakeTypeError("proxy_prop_not_configurable",
[handler, "getPropertyDescriptor", p, descriptor]);
}
return desc;
}
var prop = GetOwnProperty(obj);
if (!IS_UNDEFINED(prop)) return prop;
var proto = %GetPrototype(obj);
if (IS_NULL(proto)) return void 0;
return GetProperty(proto, p);
}
// ES5 section 8.12.6
function HasProperty(obj, p) {
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
return ToBoolean(CallTrap1(handler, "has", DerivedHasTrap, p));
}
var desc = GetProperty(obj, p);
return IS_UNDEFINED(desc) ? false : true;
}
// ES5 section 8.12.1.
function GetOwnProperty(obj, v) {
var p = ToString(v);
......
......@@ -14937,3 +14937,112 @@ THREADED_TEST(Regress1516) {
}
}
}
static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
Local<Value> name,
v8::AccessType type,
Local<Value> data) {
// Only block read access to __proto__.
if (type == v8::ACCESS_GET &&
name->IsString() &&
name->ToString()->Length() == 9 &&
name->ToString()->Utf8Length() == 9) {
char buffer[10];
CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
return strncmp(buffer, "__proto__", 9) != 0;
}
return true;
}
THREADED_TEST(Regress93759) {
HandleScope scope;
// Template for object with security check.
Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
// We don't do indexing, so any callback can be used for that.
no_proto_template->SetAccessCheckCallbacks(
BlockProtoNamedSecurityTestCallback,
IndexedSecurityTestCallback);
// Templates for objects with hidden prototypes and possibly security check.
Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
hidden_proto_template->SetHiddenPrototype(true);
Local<FunctionTemplate> protected_hidden_proto_template =
v8::FunctionTemplate::New();
protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
BlockProtoNamedSecurityTestCallback,
IndexedSecurityTestCallback);
protected_hidden_proto_template->SetHiddenPrototype(true);
// Context for "foreign" objects used in test.
Persistent<Context> context = v8::Context::New();
context->Enter();
// Plain object, no security check.
Local<Object> simple_object = Object::New();
// Object with explicit security check.
Local<Object> protected_object =
no_proto_template->NewInstance();
// JSGlobalProxy object, always have security check.
Local<Object> proxy_object =
context->Global();
// Global object, the prototype of proxy_object. No security checks.
Local<Object> global_object =
proxy_object->GetPrototype()->ToObject();
// Hidden prototype without security check.
Local<Object> hidden_prototype =
hidden_proto_template->GetFunction()->NewInstance();
Local<Object> object_with_hidden =
Object::New();
object_with_hidden->SetPrototype(hidden_prototype);
// Hidden prototype with security check on the hidden prototype.
Local<Object> protected_hidden_prototype =
protected_hidden_proto_template->GetFunction()->NewInstance();
Local<Object> object_with_protected_hidden =
Object::New();
object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
context->Exit();
// Template for object for second context. Values to test are put on it as
// properties.
Local<ObjectTemplate> global_template = ObjectTemplate::New();
global_template->Set(v8_str("simple"), simple_object);
global_template->Set(v8_str("protected"), protected_object);
global_template->Set(v8_str("global"), global_object);
global_template->Set(v8_str("proxy"), proxy_object);
global_template->Set(v8_str("hidden"), object_with_hidden);
global_template->Set(v8_str("phidden"), object_with_protected_hidden);
LocalContext context2(NULL, global_template);
Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
CHECK(result1->Equals(simple_object->GetPrototype()));
Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
CHECK(result2->Equals(Undefined()));
Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
CHECK(result3->Equals(global_object->GetPrototype()));
Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
CHECK(result4->Equals(Undefined()));
Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
CHECK(result5->Equals(
object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
CHECK(result6->Equals(Undefined()));
context.Dispose();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment