Skip to content

Commit 5a30674

Browse files
addaleaxtargos
authored andcommitted
process: allow reading from stdout/stderr sockets
Allow reading from stdio streams that are conventionally associated with process output, since this is only convention. This involves disabling the oddness around closing stdio streams. Its purpose is to prevent the file descriptors 0 through 2 from being closed, since doing so can lead to information leaks when new file descriptors are being opened; instead, not doing anything seems like a more reasonable choice. Fixes: #21203 PR-URL: #23053 Reviewed-By: James M Snell <[email protected]>
1 parent d7031df commit 5a30674

8 files changed

+45
-33
lines changed

doc/api/errors.md

+31-12
Original file line numberDiff line numberDiff line change
@@ -1555,18 +1555,6 @@ An attempt was made to operate on an already closed socket.
15551555

15561556
A call was made and the UDP subsystem was not running.
15571557

1558-
<a id="ERR_STDERR_CLOSE"></a>
1559-
### ERR_STDERR_CLOSE
1560-
1561-
An attempt was made to close the `process.stderr` stream. By design, Node.js
1562-
does not allow `stdout` or `stderr` streams to be closed by user code.
1563-
1564-
<a id="ERR_STDOUT_CLOSE"></a>
1565-
### ERR_STDOUT_CLOSE
1566-
1567-
An attempt was made to close the `process.stdout` stream. By design, Node.js
1568-
does not allow `stdout` or `stderr` streams to be closed by user code.
1569-
15701558
<a id="ERR_STREAM_CANNOT_PIPE"></a>
15711559
### ERR_STREAM_CANNOT_PIPE
15721560

@@ -1952,6 +1940,37 @@ removed: v10.0.0
19521940

19531941
The `repl` module was unable to parse data from the REPL history file.
19541942

1943+
1944+
<a id="ERR_STDERR_CLOSE"></a>
1945+
### ERR_STDERR_CLOSE
1946+
<!-- YAML
1947+
removed: REPLACEME
1948+
changes:
1949+
- version: REPLACEME
1950+
pr-url: https://github.com/nodejs/node/pull/23053
1951+
description: Rather than emitting an error, `process.stderr.end()` now
1952+
only closes the stream side but not the underlying resource,
1953+
making this error obsolete.
1954+
-->
1955+
1956+
An attempt was made to close the `process.stderr` stream. By design, Node.js
1957+
does not allow `stdout` or `stderr` streams to be closed by user code.
1958+
1959+
<a id="ERR_STDOUT_CLOSE"></a>
1960+
### ERR_STDOUT_CLOSE
1961+
<!-- YAML
1962+
removed: REPLACEME
1963+
changes:
1964+
- version: REPLACEME
1965+
pr-url: https://github.com/nodejs/node/pull/23053
1966+
description: Rather than emitting an error, `process.stderr.end()` now
1967+
only closes the stream side but not the underlying resource,
1968+
making this error obsolete.
1969+
-->
1970+
1971+
An attempt was made to close the `process.stdout` stream. By design, Node.js
1972+
does not allow `stdout` or `stderr` streams to be closed by user code.
1973+
19551974
<a id="ERR_STREAM_READ_NOT_IMPLEMENTED"></a>
19561975
### ERR_STREAM_READ_NOT_IMPLEMENTED
19571976
<!-- YAML

doc/api/process.md

+1-5
Original file line numberDiff line numberDiff line change
@@ -1907,9 +1907,7 @@ important ways:
19071907

19081908
1. They are used internally by [`console.log()`][] and [`console.error()`][],
19091909
respectively.
1910-
2. They cannot be closed ([`end()`][] will throw).
1911-
3. They will never emit the [`'finish'`][] event.
1912-
4. Writes may be synchronous depending on what the stream is connected to
1910+
2. Writes may be synchronous depending on what the stream is connected to
19131911
and whether the system is Windows or POSIX:
19141912
- Files: *synchronous* on Windows and POSIX
19151913
- TTYs (Terminals): *asynchronous* on Windows, *synchronous* on POSIX
@@ -2134,7 +2132,6 @@ cases:
21342132
code will be `128` + `6`, or `134`.
21352133

21362134
[`'exit'`]: #process_event_exit
2137-
[`'finish'`]: stream.html#stream_event_finish
21382135
[`'message'`]: child_process.html#child_process_event_message
21392136
[`'rejectionHandled'`]: #process_event_rejectionhandled
21402137
[`'uncaughtException'`]: #process_event_uncaughtexception
@@ -2148,7 +2145,6 @@ cases:
21482145
[`console.error()`]: console.html#console_console_error_data_args
21492146
[`console.log()`]: console.html#console_console_log_data_args
21502147
[`domain`]: domain.html
2151-
[`end()`]: stream.html#stream_writable_end_chunk_encoding_callback
21522148
[`net.Server`]: net.html#net_class_net_server
21532149
[`net.Socket`]: net.html#net_class_net_socket
21542150
[`NODE_OPTIONS`]: cli.html#cli_node_options_options

lib/internal/errors.js

-2
Original file line numberDiff line numberDiff line change
@@ -817,8 +817,6 @@ E('ERR_SOCKET_BUFFER_SIZE',
817817
E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data', Error);
818818
E('ERR_SOCKET_CLOSED', 'Socket is closed', Error);
819819
E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running', Error);
820-
E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed', Error);
821-
E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed', Error);
822820
E('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable', Error);
823821
E('ERR_STREAM_DESTROYED', 'Cannot call %s after a stream was destroyed', Error);
824822
E('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);

lib/internal/process/stdio.js

+6-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
'use strict';
22

33
const {
4-
ERR_STDERR_CLOSE,
5-
ERR_STDOUT_CLOSE,
64
ERR_UNKNOWN_STDIN_TYPE,
75
ERR_UNKNOWN_STREAM_TYPE
86
} = require('internal/errors').codes;
97

108
exports.setupProcessStdio = setupProcessStdio;
119
exports.getMainThreadStdio = getMainThreadStdio;
1210

11+
function dummyDestroy(err, cb) { cb(err); }
12+
1313
function getMainThreadStdio() {
1414
var stdin;
1515
var stdout;
@@ -19,11 +19,8 @@ function getMainThreadStdio() {
1919
if (stdout) return stdout;
2020
stdout = createWritableStdioStream(1);
2121
stdout.destroySoon = stdout.destroy;
22-
stdout._destroy = function(er, cb) {
23-
// Avoid errors if we already emitted
24-
er = er || new ERR_STDOUT_CLOSE();
25-
cb(er);
26-
};
22+
// Override _destroy so that the fd is never actually closed.
23+
stdout._destroy = dummyDestroy;
2724
if (stdout.isTTY) {
2825
process.on('SIGWINCH', () => stdout._refreshSize());
2926
}
@@ -34,11 +31,8 @@ function getMainThreadStdio() {
3431
if (stderr) return stderr;
3532
stderr = createWritableStdioStream(2);
3633
stderr.destroySoon = stderr.destroy;
37-
stderr._destroy = function(er, cb) {
38-
// Avoid errors if we already emitted
39-
er = er || new ERR_STDERR_CLOSE();
40-
cb(er);
41-
};
34+
// Override _destroy so that the fd is never actually closed.
35+
stdout._destroy = dummyDestroy;
4236
if (stderr.isTTY) {
4337
process.on('SIGWINCH', () => stderr._refreshSize());
4438
}

test/parallel/test-stdout-cannot-be-closed-child-process-pipe.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ function parent() {
2424
});
2525

2626
child.on('close', function(code, signal) {
27-
assert(code);
27+
assert.strictEqual(code, 0);
28+
assert.strictEqual(err, '');
2829
assert.strictEqual(out, 'foo');
29-
assert(/process\.stdout cannot be closed/.test(err));
3030
console.log('ok');
3131
});
3232
}

test/pseudo-tty/test-stdout-read.in

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello!

test/pseudo-tty/test-stdout-read.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
'use strict';
2+
const common = require('../common');
3+
process.stderr.on('data', common.mustCall(console.log));

test/pseudo-tty/test-stdout-read.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<Buffer 48 65 6c 6c 6f 21 0a>

0 commit comments

Comments
 (0)