From 893b8320b80f85f57cd89a1482d6dc065a915e94 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Thu, 25 Aug 2011 13:22:55 +0000 Subject: [PATCH] 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 --- src/runtime.cc | 12 +++++- src/v8natives.js | 32 -------------- test/cctest/test-api.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 33 deletions(-) diff --git a/src/runtime.cc b/src/runtime.cc index fd866bf..d49cb10 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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()); diff --git a/src/v8natives.js b/src/v8natives.js index c8359fa..035fd2e 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -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); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index aeb4cbe..def80fd 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -14937,3 +14937,112 @@ THREADED_TEST(Regress1516) { } } } + + +static bool BlockProtoNamedSecurityTestCallback(Local global, + Local name, + v8::AccessType type, + Local 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 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 hidden_proto_template = v8::FunctionTemplate::New(); + hidden_proto_template->SetHiddenPrototype(true); + + Local 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 = v8::Context::New(); + context->Enter(); + + // Plain object, no security check. + Local simple_object = Object::New(); + + // Object with explicit security check. + Local protected_object = + no_proto_template->NewInstance(); + + // JSGlobalProxy object, always have security check. + Local proxy_object = + context->Global(); + + // Global object, the prototype of proxy_object. No security checks. + Local global_object = + proxy_object->GetPrototype()->ToObject(); + + // Hidden prototype without security check. + Local hidden_prototype = + hidden_proto_template->GetFunction()->NewInstance(); + Local object_with_hidden = + Object::New(); + object_with_hidden->SetPrototype(hidden_prototype); + + // Hidden prototype with security check on the hidden prototype. + Local protected_hidden_prototype = + protected_hidden_proto_template->GetFunction()->NewInstance(); + Local 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 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 result1 = CompileRun("Object.getPrototypeOf(simple)"); + CHECK(result1->Equals(simple_object->GetPrototype())); + + Local result2 = CompileRun("Object.getPrototypeOf(protected)"); + CHECK(result2->Equals(Undefined())); + + Local result3 = CompileRun("Object.getPrototypeOf(global)"); + CHECK(result3->Equals(global_object->GetPrototype())); + + Local result4 = CompileRun("Object.getPrototypeOf(proxy)"); + CHECK(result4->Equals(Undefined())); + + Local result5 = CompileRun("Object.getPrototypeOf(hidden)"); + CHECK(result5->Equals( + object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); + + Local result6 = CompileRun("Object.getPrototypeOf(phidden)"); + CHECK(result6->Equals(Undefined())); + + context.Dispose(); +} -- 2.7.4