diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2015-03-23 00:26:59 +0100 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2015-03-23 10:40:12 +0100 |
commit | 7e88a9322c8f1b5393723d6f99590d750b097569 (patch) | |
tree | ef3f4d358d11d2db3b8c4a0ca75ad27e97e61ebe /src | |
parent | 20c4498e76af9bd639a752aae3e36571251c3c2d (diff) | |
download | node-new-7e88a9322c8f1b5393723d6f99590d750b097569.tar.gz |
src: make accessors immune to context confusion
It's possible for an accessor or named interceptor to get called with
a different execution context than the one it lives in, see the test
case for an example using the debug API.
This commit fortifies against that by passing the environment as a
data property instead of looking it up through the current context.
Fixes: https://github.com/iojs/io.js/issues/1190 (again)
PR-URL: https://github.com/iojs/io.js/pull/1238
Reviewed-By: Fedor Indutny <fedor@indutny.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/env-inl.h | 17 | ||||
-rw-r--r-- | src/env.h | 7 | ||||
-rw-r--r-- | src/node.cc | 38 | ||||
-rw-r--r-- | src/node_crypto.cc | 33 | ||||
-rw-r--r-- | src/node_internals.h | 15 | ||||
-rw-r--r-- | src/stream_base-inl.h | 2 | ||||
-rw-r--r-- | src/udp_wrap.cc | 2 |
7 files changed, 54 insertions, 60 deletions
diff --git a/src/env-inl.h b/src/env-inl.h index d3a723a0c2..237da7159d 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -153,10 +153,14 @@ inline Environment* Environment::GetCurrent( return static_cast<Environment*>(info.Data().As<v8::External>()->Value()); } +template <typename T> inline Environment* Environment::GetCurrent( - const v8::PropertyCallbackInfo<v8::Value>& info) { + const v8::PropertyCallbackInfo<T>& info) { ASSERT(info.Data()->IsExternal()); - return static_cast<Environment*>(info.Data().As<v8::External>()->Value()); + // XXX(bnoordhuis) Work around a g++ 4.9.2 template type inferrer bug + // when the expression is written as info.Data().As<v8::External>(). + v8::Local<v8::Value> data = info.Data(); + return static_cast<Environment*>(data.As<v8::External>()->Value()); } inline Environment::Environment(v8::Local<v8::Context> context, @@ -173,6 +177,7 @@ inline Environment::Environment(v8::Local<v8::Context> context, // We'll be creating new objects so make sure we've entered the context. v8::HandleScope handle_scope(isolate()); v8::Context::Scope context_scope(context); + set_as_external(v8::External::New(isolate(), this)); set_binding_cache_object(v8::Object::New(isolate())); set_module_load_list_array(v8::Array::New(isolate())); RB_INIT(&cares_task_list_); @@ -396,13 +401,7 @@ inline void Environment::ThrowUVException(int errorno, inline v8::Local<v8::FunctionTemplate> Environment::NewFunctionTemplate(v8::FunctionCallback callback, v8::Local<v8::Signature> signature) { - v8::Local<v8::External> external; - if (external_.IsEmpty()) { - external = v8::External::New(isolate(), this); - external_.Reset(isolate(), external); - } else { - external = StrongPersistentToLocal(external_); - } + v8::Local<v8::External> external = as_external(); return v8::FunctionTemplate::New(isolate(), callback, external, signature); } @@ -224,6 +224,7 @@ namespace node { V(zero_return_string, "ZERO_RETURN") \ #define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ + V(as_external, v8::External) \ V(async_hooks_init_function, v8::Function) \ V(async_hooks_pre_function, v8::Function) \ V(async_hooks_post_function, v8::Function) \ @@ -357,8 +358,10 @@ class Environment { static inline Environment* GetCurrent(v8::Local<v8::Context> context); static inline Environment* GetCurrent( const v8::FunctionCallbackInfo<v8::Value>& info); + + template <typename T> static inline Environment* GetCurrent( - const v8::PropertyCallbackInfo<v8::Value>& info); + const v8::PropertyCallbackInfo<T>& info); // See CreateEnvironment() in src/node.cc. static inline Environment* New(v8::Local<v8::Context> context, @@ -509,8 +512,6 @@ class Environment { &HandleCleanup::handle_cleanup_queue_> handle_cleanup_queue_; int handle_cleanup_waiting_; - v8::Persistent<v8::External> external_; - #define V(PropertyName, TypeName) \ v8::Persistent<TypeName> PropertyName ## _; ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) diff --git a/src/node.cc b/src/node.cc index b8decf8c39..f47f31ab1f 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2280,7 +2280,7 @@ static void LinkedBinding(const FunctionCallbackInfo<Value>& args) { static void ProcessTitleGetter(Local<String> property, const PropertyCallbackInfo<Value>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); char buffer[512]; uv_get_process_title(buffer, sizeof(buffer)); @@ -2291,7 +2291,7 @@ static void ProcessTitleGetter(Local<String> property, static void ProcessTitleSetter(Local<String> property, Local<Value> value, const PropertyCallbackInfo<void>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); node::Utf8Value title(env->isolate(), value); // TODO(piscisaureus): protect with a lock @@ -2301,7 +2301,7 @@ static void ProcessTitleSetter(Local<String> property, static void EnvGetter(Local<String> property, const PropertyCallbackInfo<Value>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); #ifdef __POSIX__ node::Utf8Value key(env->isolate(), property); @@ -2325,16 +2325,13 @@ static void EnvGetter(Local<String> property, return info.GetReturnValue().Set(rc); } #endif - // Not found. Fetch from prototype. - info.GetReturnValue().Set( - info.Data().As<Object>()->Get(property)); } static void EnvSetter(Local<String> property, Local<Value> value, const PropertyCallbackInfo<Value>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); #ifdef __POSIX__ node::Utf8Value key(env->isolate(), property); @@ -2356,7 +2353,7 @@ static void EnvSetter(Local<String> property, static void EnvQuery(Local<String> property, const PropertyCallbackInfo<Integer>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); int32_t rc = -1; // Not found unless proven otherwise. #ifdef __POSIX__ @@ -2384,7 +2381,7 @@ static void EnvQuery(Local<String> property, static void EnvDeleter(Local<String> property, const PropertyCallbackInfo<Boolean>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); bool rc = true; #ifdef __POSIX__ @@ -2407,7 +2404,7 @@ static void EnvDeleter(Local<String> property, static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); #ifdef __POSIX__ int size = 0; @@ -2508,7 +2505,7 @@ static Handle<Object> GetFeatures(Environment* env) { static void DebugPortGetter(Local<String> property, const PropertyCallbackInfo<Value>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); info.GetReturnValue().Set(debug_port); } @@ -2517,7 +2514,7 @@ static void DebugPortGetter(Local<String> property, static void DebugPortSetter(Local<String> property, Local<Value> value, const PropertyCallbackInfo<void>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); HandleScope scope(env->isolate()); debug_port = value->Int32Value(); } @@ -2530,7 +2527,7 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args); void NeedImmediateCallbackGetter(Local<String> property, const PropertyCallbackInfo<Value>& info) { - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); const uv_check_t* immediate_check_handle = env->immediate_check_handle(); bool active = uv_is_active( reinterpret_cast<const uv_handle_t*>(immediate_check_handle)); @@ -2543,7 +2540,7 @@ static void NeedImmediateCallbackSetter( Local<Value> value, const PropertyCallbackInfo<void>& info) { HandleScope handle_scope(info.GetIsolate()); - Environment* env = Environment::GetCurrent(info.GetIsolate()); + Environment* env = Environment::GetCurrent(info); uv_check_t* immediate_check_handle = env->immediate_check_handle(); bool active = uv_is_active( @@ -2626,7 +2623,8 @@ void SetupProcessObject(Environment* env, process->SetAccessor(env->title_string(), ProcessTitleGetter, - ProcessTitleSetter); + ProcessTitleSetter, + env->as_external()); // process.version READONLY_PROPERTY(process, @@ -2741,15 +2739,16 @@ void SetupProcessObject(Environment* env, EnvQuery, EnvDeleter, EnvEnumerator, - Object::New(env->isolate())); + env->as_external()); Local<Object> process_env = process_env_template->NewInstance(); process->Set(env->env_string(), process_env); READONLY_PROPERTY(process, "pid", Integer::New(env->isolate(), getpid())); READONLY_PROPERTY(process, "features", GetFeatures(env)); process->SetAccessor(env->need_imm_cb_string(), - NeedImmediateCallbackGetter, - NeedImmediateCallbackSetter); + NeedImmediateCallbackGetter, + NeedImmediateCallbackSetter, + env->as_external()); // -e, --eval if (eval_string) { @@ -2812,7 +2811,8 @@ void SetupProcessObject(Environment* env, process->SetAccessor(env->debug_port_string(), DebugPortGetter, - DebugPortSetter); + DebugPortSetter, + env->as_external()); // define various internal methods env->SetMethod(process, diff --git a/src/node_crypto.cc b/src/node_crypto.cc index a650d4fef7..b6cb4f10e5 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -60,6 +60,8 @@ namespace crypto { using v8::Array; using v8::Boolean; using v8::Context; +using v8::DEFAULT; +using v8::DontDelete; using v8::EscapableHandleScope; using v8::Exception; using v8::External; @@ -76,6 +78,7 @@ using v8::Object; using v8::Persistent; using v8::PropertyAttribute; using v8::PropertyCallbackInfo; +using v8::ReadOnly; using v8::String; using v8::V8; using v8::Value; @@ -264,10 +267,13 @@ void SecureContext::Initialize(Environment* env, Handle<Object> target) { env->SetProtoMethod(t, "getCertificate", SecureContext::GetCertificate<true>); env->SetProtoMethod(t, "getIssuer", SecureContext::GetCertificate<false>); - NODE_SET_EXTERNAL( - t->PrototypeTemplate(), - "_external", - CtxGetter); + t->PrototypeTemplate()->SetAccessor( + FIXED_ONE_BYTE_STRING(env->isolate(), "_external"), + CtxGetter, + nullptr, + env->as_external(), + DEFAULT, + static_cast<PropertyAttribute>(ReadOnly | DontDelete)); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "SecureContext"), t->GetFunction()); @@ -991,10 +997,13 @@ void SSLWrap<Base>::AddMethods(Environment* env, Handle<FunctionTemplate> t) { env->SetProtoMethod(t, "setNPNProtocols", SetNPNProtocols); #endif - NODE_SET_EXTERNAL( - t->PrototypeTemplate(), - "_external", - SSLGetter); + t->PrototypeTemplate()->SetAccessor( + FIXED_ONE_BYTE_STRING(env->isolate(), "_external"), + SSLGetter, + nullptr, + env->as_external(), + DEFAULT, + static_cast<PropertyAttribute>(ReadOnly | DontDelete)); } @@ -3652,8 +3661,8 @@ void DiffieHellman::Initialize(Environment* env, Handle<Object> target) { t->InstanceTemplate()->SetAccessor(env->verify_error_string(), DiffieHellman::VerifyErrorGetter, nullptr, - Handle<Value>(), - v8::DEFAULT, + env->as_external(), + DEFAULT, attributes); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), @@ -3672,8 +3681,8 @@ void DiffieHellman::Initialize(Environment* env, Handle<Object> target) { t2->InstanceTemplate()->SetAccessor(env->verify_error_string(), DiffieHellman::VerifyErrorGetter, nullptr, - Handle<Value>(), - v8::DEFAULT, + env->as_external(), + DEFAULT, attributes); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"), diff --git a/src/node_internals.h b/src/node_internals.h index 9141355df6..c99b2feeb0 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -195,21 +195,6 @@ NODE_DEPRECATED("Use ThrowUVException(isolate)", return ThrowUVException(isolate, errorno, syscall, message, path); }) -inline void NODE_SET_EXTERNAL(v8::Handle<v8::ObjectTemplate> target, - const char* key, - v8::AccessorGetterCallback getter) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::String> prop = v8::String::NewFromUtf8(isolate, key); - target->SetAccessor(prop, - getter, - nullptr, - v8::Handle<v8::Value>(), - v8::DEFAULT, - static_cast<v8::PropertyAttribute>(v8::ReadOnly | - v8::DontDelete)); -} - enum NodeInstanceType { MAIN, WORKER }; class NodeInstanceData { diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index 8f7f5fea41..26ba54b376 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -32,7 +32,7 @@ void StreamBase::AddMethods(Environment* env, t->InstanceTemplate()->SetAccessor(env->fd_string(), GetFD<Base>, nullptr, - Handle<Value>(), + env->as_external(), v8::DEFAULT, attributes); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index d57809cb1b..3183d1f9f5 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -84,7 +84,7 @@ void UDPWrap::Initialize(Handle<Object> target, t->InstanceTemplate()->SetAccessor(env->fd_string(), UDPWrap::GetFD, nullptr, - Handle<Value>(), + env->as_external(), v8::DEFAULT, attributes); |