diff --git a/lib/net.js b/lib/net.js index a7a8eb1fcc21a7..52d1ec4213eb51 100644 --- a/lib/net.js +++ b/lib/net.js @@ -26,6 +26,7 @@ const exceptionWithHostPort = util._exceptionWithHostPort; function noop() {} function createHandle(fd) { + if (TTYWrap.fdProtected(fd)) throw new Error('fd is being protected'); var type = TTYWrap.guessHandleType(fd); if (type === 'PIPE') return new Pipe(); if (type === 'TCP') return new TCP(); diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index a78d2311456c7c..b1b46d6e962252 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -45,6 +45,7 @@ void TTYWrap::Initialize(Local target, env->SetMethod(target, "isTTY", IsTTY); env->SetMethod(target, "guessHandleType", GuessHandleType); + env->SetMethod(target, "fdProtected", FdProtected); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TTY"), t->GetFunction()); env->set_tty_constructor_template(t); @@ -78,6 +79,20 @@ void TTYWrap::GuessHandleType(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(OneByteString(env->isolate(), type)); } +void TTYWrap::FdProtected(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + int32_t fd = args[0]->Int32Value(); + CHECK_GE(fd, 0); + + uv_loop_t* loop = env->event_loop(); + bool ret = false; + + if (static_cast(fd) < loop->nwatchers && + loop->watchers[fd] != NULL) + ret = true; + + args.GetReturnValue().Set(ret); +} void TTYWrap::IsTTY(const FunctionCallbackInfo& args) { int fd = args[0]->Int32Value(); diff --git a/src/tty_wrap.h b/src/tty_wrap.h index 581972a3b911a8..b9364a0281a4d3 100644 --- a/src/tty_wrap.h +++ b/src/tty_wrap.h @@ -24,6 +24,7 @@ class TTYWrap : public StreamWrap { bool readable); static void GuessHandleType(const v8::FunctionCallbackInfo& args); + static void FdProtected(const v8::FunctionCallbackInfo& args); static void IsTTY(const v8::FunctionCallbackInfo& args); static void GetWindowSize(const v8::FunctionCallbackInfo& args); static void SetRawMode(const v8::FunctionCallbackInfo& args); diff --git a/test/parallel/test-net-socket-fd-protection.js b/test/parallel/test-net-socket-fd-protection.js new file mode 100644 index 00000000000000..f803f08df344be --- /dev/null +++ b/test/parallel/test-net-socket-fd-protection.js @@ -0,0 +1,25 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +var will_throw = function() { + var errors = []; + [ 3, 4, 5, 6, 7, 8, 9 ].forEach(function(fd) { + try { + var stream = new net.Socket({ + fd: fd, + readable: false, + writable: true + }); + stream.on('error', function() {}); + stream.write('might crash'); + } catch (e) { + errors.push(e); + } + }); + throw errors; +}; + +// Should throw instead of crash +assert.throws(will_throw, /fd is being protected/);