Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Error: write EBADF" when sending a TLSSocket to the parent process #4037

Closed
timkuijsten opened this issue Nov 26, 2015 · 7 comments
Closed
Labels
child_process Issues and PRs related to the child_process subsystem. tls Issues and PRs related to the tls subsystem.

Comments

@timkuijsten
Copy link
Contributor

When sending a tls.TLSSocket to the parent process, the parent crashes with the following message: "Error: write EBADF".

Steps to reproduce:
$ cat bug_parent.js

var cp = require('child_process');

var child = cp.fork('./bug_child.js');

console.log('master: child forked');

child.on('message', function(msg, handle) {
  console.log('parent: incoming handle %s %j', msg, handle);
});

$ cat bug_child.js

var fs = require('fs');
var tls = require('tls');

var opts = {
  key: fs.readFileSync('private.pem'),
  cert: fs.readFileSync('server.crt')
};

var tlsServer = tls.createServer(opts, function(conn) {
  console.log('child: incoming connection, send to parent...');
  process.send('socket', conn);
});

tlsServer.listen(8001, '127.0.0.1');
console.log('child: server started');

$ cat bug_client.js

var fs = require('fs');
var tls = require('tls');

var opts = {
  host: 'localhost',
  port: 8001,
  ca: fs.readFileSync('server.crt'),
};

var conn = tls.connect(opts, function() {
  console.log('connected');
});

Start the server in a terminal.

$ node bug_parent.js

master: child forked
child: server started

Now start the client in another terminal.

$ node bug_client.js

events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: socket hang up
    at TLSSocket.onHangUp (_tls_wrap.js:1089:19)
    at TLSSocket.g (events.js:260:16)
    at emitNone (events.js:72:20)
    at TLSSocket.emit (events.js:166:7)
    at endReadableNT (_stream_readable.js:905:12)
    at doNTCallback2 (node.js:452:9)
    at process._tickCallback (node.js:366:17)

Server terminal prints:

child: incoming connection, send to parent...
events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: write EBADF
    at exports._errnoException (util.js:856:11)
    at process.target._send (internal/child_process.js:606:18)
    at process.target.send (internal/child_process.js:507:19)
    at Server.<anonymous> (/Users/tim/code/persdb/bug_child.js:11:11)
    at emitOne (events.js:77:13)
    at Server.emit (events.js:169:7)
    at TLSSocket.<anonymous> (_tls_wrap.js:813:14)
    at emitNone (events.js:67:13)
    at TLSSocket.emit (events.js:166:7)
    at TLSSocket._finishInit (_tls_wrap.js:596:8)

Tested with Node 5.1.0, the problem exists in Node 4.2.2 as well, albeit with a different message: "listener must be a function". It all works when requiring net instead of tls.

@bnoordhuis
Copy link
Member

You can't do that (sending TLS sockets to another process, that is.) The TLS state machine can't be transferred to another process.

@bnoordhuis bnoordhuis added tls Issues and PRs related to the tls subsystem. child_process Issues and PRs related to the child_process subsystem. labels Nov 26, 2015
@timkuijsten
Copy link
Contributor Author

Is it advisable to get the unencrypted socket out of it before sending it to the parent (I guess not)? Or is there another way to leave the encryption wrapper in the child. Maybe signal the parent from the child and let the parent create a new net.Socket that can be sent/piped to the child?

@bnoordhuis
Copy link
Member

You can do either but in the second scenario the parent process can become a bottleneck because that's where all encryption/decryption takes place.

@timkuijsten
Copy link
Contributor Author

I like to leave most code it in the unprivileged child, so in this case the one holding OpenSSL etc. But either way, one process should hold a net.Socket and the other one the tls.TLSSocket and then the net.Socket can be shared between processes and piped, right?

@bnoordhuis
Copy link
Member

That will work, yes.

@timkuijsten
Copy link
Contributor Author

thanks!

@yuchonghua
Copy link

The official is no better solution for it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants