src: ensure that file descriptors 0-2 are valid
authorBen Noordhuis <info@bnoordhuis.nl>
Wed, 18 Feb 2015 02:43:29 +0000 (03:43 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Wed, 18 Feb 2015 14:15:14 +0000 (15:15 +0100)
Check that stdin, stdout and stderr map to open file descriptors and
remap them to /dev/null if that isn't the case.  Protects against
information leaks or worse when io.js is started with closed stdio
file descriptors.

PR-URL: https://github.com/iojs/io.js/pull/875
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Vladimir Kurchatkin <vladimir.kurchatkin@gmail.com>
src/node.cc
test/parallel/test-stdio-closed.js [new file with mode: 0644]

index 48c93b8..e060304 100644 (file)
@@ -3366,7 +3366,22 @@ inline void PlatformInit() {
   sigset_t sigmask;
   sigemptyset(&sigmask);
   sigaddset(&sigmask, SIGUSR1);
-  CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr));
+  const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
+
+  // Make sure file descriptors 0-2 are valid before we start logging anything.
+  for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
+    struct stat ignored;
+    if (fstat(fd, &ignored) == 0)
+      continue;
+    // Anything but EBADF means something is seriously wrong.  We don't
+    // have to special-case EINTR, fstat() is not interruptible.
+    if (errno != EBADF)
+      abort();
+    if (fd != open("/dev/null", O_RDWR))
+      abort();
+  }
+
+  CHECK_EQ(err, 0);
 
   // Restore signal dispositions, the parent process may have changed them.
   struct sigaction act;
diff --git a/test/parallel/test-stdio-closed.js b/test/parallel/test-stdio-closed.js
new file mode 100644 (file)
index 0000000..fd081b8
--- /dev/null
@@ -0,0 +1,24 @@
+var common = require('../common');
+var assert = require('assert');
+var spawn = require('child_process').spawn;
+
+if (process.platform === 'win32') {
+  console.log('Skipping test, platform not supported.');
+  return;
+}
+
+if (process.argv[2] === 'child') {
+  process.stdout.write('stdout', function() {
+    process.stderr.write('stderr', function() {
+      process.exit(42);
+    });
+  });
+}
+
+// Run the script in a shell but close stdout and stderr.
+var cmd = '"' + process.execPath + '" "' + __filename + '" child 1>&- 2>&-';
+var proc = spawn('/bin/sh', ['-c', cmd], { stdio: 'inherit' });
+
+proc.on('exit', common.mustCall(function(exitCode) {
+  assert.equal(exitCode, 42);
+}));