diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 1d8de8985..e58764a26 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1901,6 +1901,8 @@ ossl_ssl_read(VALUE self, VALUE len, VALUE str) rb_raise(eSSLError, "SSL session is not started yet"); ilen = NUM2INT(len); + if (ilen < 0) + rb_raise(rb_eArgError, "negative length %d given", ilen); StringValue(str); if ((rb_len_t)rb_str_capacity(str) >= ilen) rb_str_modify(str); diff --git a/lib/openssl/buffering.rb b/lib/openssl/buffering.rb index 3578c3ca9..f611f2899 100644 --- a/lib/openssl/buffering.rb +++ b/lib/openssl/buffering.rb @@ -111,13 +111,9 @@ def readbyte # See IO#read for full details. def read(size=nil, buf=nil) - if size == 0 - if buf - buf.clear - return buf - else - return String.new - end + if size + return buf&.clear || String.new if size == 0 + raise ArgumentError, "negative length #{size} given" if size < 0 end until @eof break if size && size <= @rbuffer.size @@ -139,13 +135,9 @@ def read(size=nil, buf=nil) # See IO#readpartial for full details. def readpartial(maxlen, buf=nil) - if maxlen == 0 - if buf - buf.clear - return buf - else - return String.new - end + if maxlen + return buf&.clear || String.new if maxlen == 0 + raise ArgumentError, "negative length #{maxlen} given" if maxlen < 0 end if @rbuffer.empty? return sysread(maxlen, buf) @@ -193,13 +185,9 @@ def readpartial(maxlen, buf=nil) # it will return +nil+ instead of raising EOFError. def read_nonblock(maxlen, buf=nil, exception: true) - if maxlen == 0 - if buf - buf.clear - return buf - else - return String.new - end + if maxlen + return buf&.clear || String.new if maxlen == 0 + raise ArgumentError, "negative length #{maxlen} given" if maxlen < 0 end if @rbuffer.empty? return sysread_nonblock(maxlen, buf, exception: exception) diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index a19a60b50..c51002125 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -339,6 +339,7 @@ def test_readpartial assert_raise(EOFError) { s1.readpartial(10) } assert_raise(EOFError) { s1.readpartial(10) } assert_equal("", s1.readpartial(0)) + assert_raise(ArgumentError) { s1.readpartial(-1) } } end @@ -440,6 +441,10 @@ def test_sysread_and_syswrite obj.define_singleton_method(:to_s) { str } s1.syswrite(obj) assert_equal(str, s2.sysread(str.bytesize)) + + # https://bugs.ruby-lang.org/issues/18880 + next if !s2.is_a?(OpenSSL::SSL::SSLSocket) && RUBY_VERSION < "3.2" + assert_raise(ArgumentError) { s2.sysread(-1) } } end @@ -461,6 +466,8 @@ def test_read_nonblock s1.close IO.select([s2]) assert_raise(EOFError) { s2.read_nonblock(10) } + + assert_raise(ArgumentError) { s2.read_nonblock(-1) } } end @@ -506,6 +513,9 @@ def test_read_with_outbuf ret = s2.read(0, buf) assert_same buf, ret assert_equal "", ret + + buf = +"garbage" + assert_raise(ArgumentError) { s2.read(-1, buf) } } end