Skip to content

Integer overflow/UB when writing large buffers to TLS streams #38049

Open
@zbjornson

Description

@zbjornson

What steps will reproduce the bug?

const https = require("https");
  
const req = https.request({
        hostname: "httpbin.org",
        port: 443,
        path: "/post",
        method: "POST"
});
req.on("error", console.error);
req.on("response", r => console.log("response", r.statusCode))
req.write(Buffer.alloc(2147483616));
req.end();

How often does it reproduce? Is there a required condition?

Consistently.

What is the expected behavior?

Either a nice error saying that stream chunks can only be up to INT_MAX, or for the stream to automatically slice up large chunks.

edit the limit isn't INT_MAX actually ... in the above test case it's around 2,147,483,540 bytes, which I'm guessing is body + about 107 bytes of some overhead that sums to INT_MAX.

What do you see instead?

Error: write EPROTO 139931020609408:error:140D010F:SSL routines:SSL_write:bad length:../deps/openssl/openssl/ssl/ssl_lib.c:1962:

    at afterWriteDispatched (internal/stream_base_commons.js:156:25)
    at writevGeneric (internal/stream_base_commons.js:139:3)
    at TLSSocket.Socket._writeGeneric (net.js:783:11)
    at TLSSocket.connect (net.js:767:12)
    at Object.onceWrapper (events.js:421:28)
    at TLSSocket.emit (events.js:327:22)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1132:10) {
  errno: -71,
  code: 'EPROTO',
  syscall: 'write'
}

Additional information

The error claims to be from the write syscall, but it looks to be in openssl upstream of the syscall:

int SSL_write(SSL *s, const void *buf, int num)
{
int ret;
size_t written;
if (num < 0) {
SSLerr(SSL_F_SSL_WRITE, SSL_R_BAD_LENGTH);

For comparison, an fs.WriteStream will properly write files exceeding Linux's write(2) limit of 2,147,479,552 bytes.

[pid  2112] write(17, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 2147483616) = 2147479552 <1.787290>
[pid  2112] write(17, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4064) = 4064 <0.000060>

#27861 looks like it would make this possible to hit in other scenarios also, maybe there should be a limit on the concatenated segment size.

Metadata

Metadata

Assignees

No one assigned

    Labels

    tlsIssues and PRs related to the tls subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions