Skip to content

ssl: raise ArgumentError for a negative length in SSLSocket#sysread - #1123

Merged
rhenium merged 1 commit into
ruby:masterfrom
Shaisolaris:sysread-negative-length
Oct 16, 2026
Merged

rhenium merged 1 commit into
ruby:masterfrom
Shaisolaris:sysread-negative-length

Conversation

@Shaisolaris

@Shaisolaris Shaisolaris commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Since bf1a419 ("ssl: implement blocking SSLSocket methods in Ruby"), a negative length passed to SSLSocket#sysread or #read_nonblock reaches SSL_read():

ssl.sysread(-1)
# master:      OpenSSL::SSL::SSLError: SSL_read: bad length
# before:      ArgumentError: negative string size (or size too big)

The new string_new_capacity clamps the capacity to 0, so the old ArgumentError from rb_str_new() no longer happens. With a caller-provided buffer the negative length already reached SSL_read() before that commit.

This adds a check in ssl_read that raises ArgumentError for a negative length, like IO#sysread, in all of these paths. The change has not been released yet (it is not in v4.0.2).

Tests:

  • Added test_sysread_negative_length to test/openssl/test_pair.rb. It fails on master and passes with this change.
  • test_pair.rb (33 tests), test_ssl.rb (92), test_ssl_session.rb (11) and test_buffering.rb (5) pass locally on Ruby 3.3.8 with the system OpenSSL. I did not run the full rake test or the CI matrix of OpenSSL/LibreSSL/AWS-LC versions.

Follow-up validation — October 16

Follow-up validation (October 16): independently detect rb_len2long rather than assuming that HAVE_RB_LEN_T implies the conversion helper exists. A syntax-only compile probe with a present length type and absent helper fails before and passes after the guard repair. The negative-length regression now lives in the SSL test class rather than the shared native Socket mixin. Built on Ruby 3.4.8/OpenSSL 3.6.2; full socket-pair file: 103 tests, 531 assertions, no failures. Windows/Ruby-head CI remains to be verified.

@Shaisolaris
Shaisolaris force-pushed the sysread-negative-length branch from 2de20a6 to 6499911 Compare October 16, 2026 13:16
@rhenium

rhenium commented Oct 16, 2026

Copy link
Copy Markdown
Member

We should make #read, #readpartial, and #read_nonblock reject this error as well, not just #sysread.

(As a bonus - IO#sysread also handled this inconsistently when an output buffer is passed. I ran into that a few days ago and filed https://bugs.ruby-lang.org/issues/22433.)

The second commit doesn't look necessary. defined HAVE_RB_LEN_T is indeed supposed to imply that rb_len2long() is available. Both currently exist only in Ruby's master branch.

@rhenium
rhenium force-pushed the sysread-negative-length branch from 6499911 to bafa498 Compare October 16, 2026 16:21
@rhenium

rhenium commented Oct 16, 2026

Copy link
Copy Markdown
Member

windows mingw head looks outdated:

ruby 4.1.0dev (2026-10-10 master 17aeb89200) +PRISM [x64-mingw-ucrt]

Ruby < 3.2 on Windows appears to be failing due to https://bugs.ruby-lang.org/issues/18880

@rhenium
rhenium force-pushed the sysread-negative-length branch from bafa498 to 087ef40 Compare October 16, 2026 16:37
Check the length so that #sysread, #read_nonblock and the buffer
variants raise ArgumentError.

Co-authored-by: Kazuki Yamaguchi <k@rhe.jp>
@rhenium
rhenium force-pushed the sysread-negative-length branch from 087ef40 to 9443e67 Compare October 16, 2026 16:50
@rhenium
rhenium merged commit 1592f72 into ruby:master Oct 16, 2026
47 of 48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants