import UBI ruby-2.5.9-115.module+el8.10.0+24408+7ffaaa88

This commit is contained in:
AlmaLinux RelEng Bot 2026-07-02 14:28:27 -04:00
parent b4a187f265
commit 6bc5e278e1
3 changed files with 596 additions and 1 deletions

View File

@ -0,0 +1,332 @@
From ac248b06de768b68120b910b2977d55320871b0e Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Sun, 29 Mar 2026 12:26:48 -0400
Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=8D=92=20pick=20257ede0df:=20?=
=?UTF-8?q?=F0=9F=A5=85=20Re-raise=20`#starttls`=20error=20from=20receiver?=
=?UTF-8?q?=20thread=20[backports=20#395]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Backports #395 to `v0.3-stable`. The tests required an additional
rescue-and-ignore for the server thread in `starttls_test`, which was
already present in all later branches.
---------
When `start_tls_session` raises an exception, that's caught in the
receiver thread, but not re-raised. Fortunately, `@sock` will now be
a permanently broken SSLSocket, so I don't think this can lead to
accidentally using an insecure connection.
Even so, `#starttls` should disconnect the socket and re-raise the error
immediately.
Failing test case was provided by @rhenium in #394.
Co-authored-by: Kazuki Yamaguchi <k@rhe.jp>
---
lib/net/imap.rb | 10 +++++++++-
test/net/imap/test_imap.rb | 15 +++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index eedcb4f5cf..7a3cd68e81 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -376,7 +376,8 @@ def logout
# Sends a STARTTLS command to start TLS session.
def starttls(options = {}, verify = true)
- send_command("STARTTLS") do |resp|
+ error = nil
+ ok = send_command("STARTTLS") do |resp|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
begin
# for backward compatibility
@@ -386,7 +387,14 @@ def starttls(options = {}, verify = true)
end
start_tls_session(options)
end
+ rescue Exception => error
+ raise # note that the error backtrace is in the receiver_thread
end
+ if error
+ disconnect
+ raise error
+ end
+ ok
end
# Sends an AUTHENTICATE command to authenticate the client.
diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb
index 2a9447c0e1..b35b3ff52e 100644
--- a/test/net/imap/test_imap.rb
+++ b/test/net/imap/test_imap.rb
@@ -113,6 +113,20 @@ def test_imaps_post_connection_check
end
if defined?(OpenSSL::SSL)
+ def test_starttls_unknown_ca
+ imap = nil
+ ex = nil
+ starttls_test do |port|
+ imap = Net::IMAP.new("localhost", port: port)
+ begin
+ imap.starttls
+ rescue => ex
+ end
+ imap
+ end
+ assert_kind_of(OpenSSL::SSL::SSLError, ex)
+ end
+
def test_starttls
imap = nil
starttls_test do |port|
@@ -765,6 +779,7 @@ def starttls_test
sock.gets
sock.print("* BYE terminating connection\r\n")
sock.print("RUBY0002 OK LOGOUT completed\r\n")
+ rescue OpenSSL::SSL::SSLError
ensure
sock.close
server.close
From 28d2087a097aab75b2d41fddc6dd457a94f657a2 Mon Sep 17 00:00:00 2001
From: nick evans <nicholas.evans@gmail.com>
Date: Tue, 14 Feb 2023 00:13:11 -0500
Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8D=92=20pick=20609acd9fa:=20?=
=?UTF-8?q?=F0=9F=A5=85=20Add=20new=20`InvalidResponseError`=20exception?=
=?UTF-8?q?=20class=20[backport=20#198]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This copies the InvalidResponseError from #198 and the rdoc update to
UnknownResponseError. The behavioral changes from that PR have _not_
been copied.
===
The UnknownResponseError is brought into Ruby 2.5 by
ruby-2.6.8-net-imap-startls-stripping-vulnerability.patch,
The errors.rb file does not exist for net-imap on Ruby 2.5, so move the
InvalidResponseError into approximately similar location to be used by
follow-up commits.
---
lib/net/imap.rb | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 7a3cd68e81..fee094c46d 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -3724,7 +3724,27 @@ class BadResponseError < ResponseError
class ByeResponseError < ResponseError
end
+ # Error raised when the server sends an invalid response.
+ #
+ # This is different from UnknownResponseError: the response has been
+ # rejected. Although it may be parsable, the server is forbidden from
+ # sending it in the current context. The client should automatically
+ # disconnect, abruptly (without logout).
+ #
+ # Note that InvalidResponseError does not inherit from ResponseError: it
+ # can be raised before the response is fully parsed. A related
+ # ResponseParseError or ResponseError may be the #cause.
+ class InvalidResponseError < Error
+ end
+
# Error raised upon an unknown response from the server.
+ #
+ # This is different from InvalidResponseError: the response may be a
+ # valid extension response and the server may be allowed to send it in
+ # this context, but Net::IMAP either does not know how to parse it or
+ # how to handle it. This could result from enabling unknown or
+ # unhandled extensions. The connection may still be usable,
+ # but—depending on context—it may be prudent to disconnect.
class UnknownResponseError < ResponseError
end
From 9f4030066f7ede86b986ef87ed1610f242edc4ca Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Fri, 27 Mar 2026 17:16:25 -0400
Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=8D=92=20pick=2046636cae8:=20?=
=?UTF-8?q?=E2=9D=8C=F0=9F=94=92=20Add=20failing=20test=20for=20STARTTLS?=
=?UTF-8?q?=20stripping=20[backport=20#664]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
I'm putting this in its own commit to simplify testing across backports.
Also, I'm taking a "belt-and-suspenders" approach, and I'm going to test
that either of the two fixes passes the tests.
---
test/net/imap/test_imap.rb | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb
index b35b3ff52e..33606f400b 100644
--- a/test/net/imap/test_imap.rb
+++ b/test/net/imap/test_imap.rb
@@ -151,6 +151,40 @@ def test_starttls_stripping
imap
end
end
+
+ def test_starttls_stripping_ok_sent_before_response
+ # to coordinate between threads (better than sleep)
+ server_to_client, client_to_server = Queue.new, Queue.new
+ imap = nil
+ server = create_tcp_server
+ port = server.addr[1]
+ start_server do
+ sock = server.accept
+ begin
+ sock.print("* OK test server\r\n")
+ assert_equal :send_malicious_response, client_to_server.pop
+ sock.print("RUBY0001 OK hahaha, fooled you!\r\n")
+ server_to_client << :malicious_response_sent
+ sock.gets
+ ensure
+ sock.close
+ server.close
+ end
+ end
+ begin
+ imap = Net::IMAP.new("localhost", :port => port)
+ client_to_server << :send_malicious_response
+ assert_equal :malicious_response_sent, server_to_client.pop
+ sleep 0.010 # to be sure the network buffers have flushed, etc
+ assert_raise(Net::IMAP::InvalidResponseError) do
+ imap.starttls(:ca_file => CA_FILE)
+ end
+ assert imap.disconnected?
+ ensure
+ imap.disconnect if imap && !imap.disconnected?
+ end
+ assert imap.disconnected?
+ end
end
def start_server
From eff739307c73c371769769ca183a0e66baac1e2b Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Fri, 27 Mar 2026 17:31:11 -0400
Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=8D=92=20pick=2062eea6ffe:=20?=
=?UTF-8?q?=F0=9F=94=92=F0=9F=A5=85=20Ensure=20STARTTLS=20tagged=20respons?=
=?UTF-8?q?e=20was=20handled=20[backport=20#664]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Taking a "belt-and-suspenders" approach to a STARTTLS stripping attack:
This handles `STARTTLS` as a special-case: if the `STARTTLS` handler
did not run, for _whatever_ reason, an exception _must_ be raised and
the connection dropped.
_No_ command should ever receive a tagged `OK` prior to completely
sending the command. But `STARTTLS` is security-sensitive enough to
warrant this special-case handler.
---
lib/net/imap.rb | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index fee094c46d..e57f96a464 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -376,9 +376,11 @@ def logout
# Sends a STARTTLS command to start TLS session.
def starttls(options = {}, verify = true)
+ handled = false
error = nil
ok = send_command("STARTTLS") do |resp|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
+ handled = true
begin
# for backward compatibility
certs = options.to_str
@@ -394,6 +396,13 @@ def starttls(options = {}, verify = true)
disconnect
raise error
end
+ unless handled
+ disconnect
+ raise InvalidResponseError,
+ "STARTTLS handler was bypassed, although server responded %p" % [
+ ok.raw_data.chomp
+ ]
+ end
ok
end
From 2cbdd94ad824721797a17436f60027fb781e8bac Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Fri, 27 Mar 2026 18:00:09 -0400
Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=8D=92=20pick=2024d5c773d:=20?=
=?UTF-8?q?=F0=9F=94=92=F0=9F=A5=85=20Handle=20tagged=20"OK"=20to=20incomp?=
=?UTF-8?q?lete=20command=20[backport=20#664]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Taking a "belt-and-suspenders" approach:
This is a potential problem for any command which registers a response
handler: a malicious server can easily guess what the next tag will be,
and send an `OK` response _before_ the client the response handler is
attached.
`STARTTLS` is an extreme example of this issue: if the `STARTTLS`
handler does not run, then `#starttls` will not start the TLS session,
and the connection is not secured, _but no error is raised._
We should _also_ attach the response handler before sending the `CRLF`,
but that is neither necessary (the response handler will added before
the `synchronize` mutex is unlocked) nor sufficient (the fake `OK` can
be sent _much_ earlier).
On the other hand, it _is_ okay for the server to send an error tagged
response (`NO` or `BAD`), before the sending the command has completed.
---
lib/net/imap.rb | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index e57f96a464..692d6e297a 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -1279,6 +1279,7 @@ def send_command(cmd, *args, &block)
put_string(" ")
send_data(i, tag)
end
+ guard_against_tagged_response_skipping_handler!(tag)
put_string(CRLF)
if cmd == "LOGOUT"
@logout_command_tag = tag
@@ -1294,6 +1295,17 @@ def send_command(cmd, *args, &block)
end
end
end
+ rescue InvalidResponseError
+ disconnect
+ raise
+ end
+
+ def guard_against_tagged_response_skipping_handler!(tag)
+ return unless (resp = @tagged_responses[tag])&.name&.upcase == "OK"
+ raise(InvalidResponseError,
+ "Server sent tagged 'OK' before command was finished: %p. " \
+ "This could indicate a malicious server or client-side " \
+ "command injection. Disconnecting." % [resp.raw_data.chomp])
end
def generate_tag

View File

@ -0,0 +1,242 @@
From 20814a27978725dfcbce7f1b149d4cb44e634653 Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Wed, 22 Apr 2026 11:25:06 -0400
Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=8D=92=20edit=20ca72ac45:=20=E2=99=BB?=
=?UTF-8?q?=EF=B8=8F=20Extract=20superclass=20for=20(internal)=20command?=
=?UTF-8?q?=20data?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Unlike the cherry-picked commit (ca72ac45), this _only_ makes
`CommandData` the superclass for `Literal` and `Atom`. Because those
are the classes that will be modified by later cherry-picked commits.
This allows those other commits to merge more cleanly, and work with
fewer modifications.
---
lib/net/imap.rb | 44 ++++++++++++++++++++++++++++----------------
1 file changed, 28 insertions(+), 16 deletions(-)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 692d6e297a..ba44d21956 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -1566,22 +1566,43 @@ def start_tls_session(params = {})
end
end
- class RawData # :nodoc:
+ # simplistic emulation of CommandData = Data.define(:data)
+ class CommandData
+ class << self
+ def new(arg = nil, data: arg) super(data: data) end
+ alias :[] :new
+ end
+
+ def initialize(data:)
+ @data = data
+ freeze
+ end
+
+ attr_reader :data
+
+ def to_h(&block) block ? to_h.to_h(&block) : { data: data } end
+ def ==(other) self.class === other && to_h == other.to_h end
+ def eql?(other) self.class === other && to_h.eql?(other.to_h) end
+
+ # following class definition goes beyond the basic Data.define(:data)
+ ##
+
def send_data(imap, tag)
- imap.send(:put_string, @data)
+ raise NoMethodError, "#{self.class} must implement #{__method__}"
end
def validate
end
+ end
- private
- def initialize(data)
- @data = data
+ class RawData < CommandData # :nodoc:
+ def send_data(imap, tag)
+ imap.send(:put_string, @data)
end
end
- class Atom # :nodoc:
+ class Atom < CommandData # :nodoc:
def send_data(imap, tag)
imap.send(:put_string, @data)
end
@@ -1611,19 +1632,10 @@ def initialize(data)
end
end
- class Literal # :nodoc:
+ class Literal < CommandData # :nodoc:
def send_data(imap, tag)
imap.send(:send_literal, @data, tag)
end
-
- def validate
- end
-
- private
-
- def initialize(data)
- @data = data
- end
end
class MessageSet # :nodoc:
From 5c6f3ce364478fd8fde9fe8c9fc47cad34ac4ba7 Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Thu, 19 Feb 2026 15:06:08 -0500
Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8D=92=20pick=209db3e9d60:=20?=
=?UTF-8?q?=F0=9F=A5=85=20Strictly=20validate=20symbol=20(\flag)=20argumen?=
=?UTF-8?q?ts=20[backports=20#657]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Flags should not allow `atom-specials`.
Previously, no validation was done on symbol data. Sending atom or flag
args which contain atom specials could lead to various errors.
Although this could theoretically include injection attacks, this is not
considered to be a critical vulnerability in `net-imap`, for the
following reason: Valid "system flag" inputs are restricted to an
enumerated set of RFC-defined flag types. User-defined "keyword" flags
are sent as atoms, not flags, which use string inputs (strings which
can't be sent as an atom will be quoted or sent as a literal). `\Seen`
as a flag (symbol argument) is semantically different from `Seen` as a
keyword (string argument). So there is no scenario where it is
appropriate to call `#to_sym` on unvetted user input. Any code which
calls `#to_sym` indiscriminately on user-input is already buggy.
Nevertheless, users should reasonably be able to rely on `net-imap` to
do very basic input validation on its basic input types.
===
Tests were not backported, they use a much newer style that does not
make sense to backport, when we can run the tests elsewhere instead of
trying to essentially write some portions anew.
---
lib/net/imap.rb | 32 ++++++++++++++++++++++----------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index ba44d21956..4354731f13 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -1344,6 +1344,7 @@ def validate_data(data)
end
when Time
when Symbol
+ Flag.validate(data)
else
data.validate
end
@@ -1362,7 +1363,7 @@ def send_data(data, tag = nil)
when Time
send_time_data(data)
when Symbol
- send_symbol_data(data)
+ Flag[data].send_data(self, tag)
else
data.send_data(self, tag)
end
@@ -1432,10 +1433,6 @@ def send_time_data(time)
put_string(s)
end
- def send_symbol_data(symbol)
- put_string("\\" + symbol.to_s)
- end
-
def search_internal(cmd, keys, charset)
if keys.instance_of?(String)
keys = [RawData.new(keys)]
@@ -1587,6 +1584,12 @@ def eql?(other) self.class === other && to_h.eql?(other.to_h) end
# following class definition goes beyond the basic Data.define(:data)
##
+ def self.validate(*args)
+ data = new(*args)
+ data.validate
+ data
+ end
+
def send_data(imap, tag)
raise NoMethodError, "#{self.class} must implement #{__method__}"
end
@@ -1603,17 +1606,26 @@ def send_data(imap, tag)
end
class Atom < CommandData # :nodoc:
- def send_data(imap, tag)
- imap.send(:put_string, @data)
+ def initialize(**)
+ super
+ validate
end
def validate
+ data.to_s.ascii_only? \
+ or raise DataFormatError, "#{self.class} must be ASCII only"
+ data.match?(ResponseParser::Patterns::ATOM_SPECIALS) \
+ and raise DataFormatError, "#{self.class} must not contain atom-specials"
end
- private
+ def send_data(imap, tag)
+ imap.send(:put_string, data.to_s)
+ end
+ end
- def initialize(data)
- @data = data
+ class Flag < Atom # :nodoc:
+ def send_data(imap, tag)
+ imap.send(:put_string, "\\#{data}")
end
end
From 1f8a99c432f748dfccb275cc696d8ac58c2255e6 Mon Sep 17 00:00:00 2001
From: Jarek Prokop <jprokop@redhat.com>
Date: Tue, 9 Jun 2026 18:14:51 +0200
Subject: [PATCH 3/3] Cherry-pick ATOM_SPECIALS for validation regex.
The previous commit relies on ResponseParsers::Patterns::ATOM_SPECIALS
to be available. We could either hardcode the regex in the line where
the matching happens, but instead have it live in its own constant for
easier reference and less edits to the actual commit backport.
The line ported from:
https://github.com/ruby/net-imap/commit/92db350b24c388d2a2104f36cac9caa49a1044df
---
lib/net/imap.rb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 4354731f13..2af43806bb 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -2218,6 +2218,10 @@ def multipart?
end
class ResponseParser # :nodoc:
+ module Patterns
+ ATOM_SPECIALS = /[(){ \x00-\x1f\x7f%*"\\\]]/n
+ end
+
def initialize
@str = nil
@pos = nil

View File

@ -21,7 +21,7 @@
%endif
%global release 114
%global release 115
%{!?release_string:%global release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}}
@ -275,6 +275,18 @@ Patch50: rubygem-rexml-3.3.9-Fix-ReDoS-CVE-2024-49761.patch
# https://github.com/kkos/oniguruma/issues/164#issuecomment-558134827
# https://issues.redhat.com/browse/RHEL-87505
Patch51: ruby-3.5.0-fix-164-Integer-overflow-related-to-reg-dmax-in-sear.patch
# Fix CVE-2026-42246 Information disclosure via man-in-the-middle attack bypassing TLS.
# Backport https://github.com/ruby/net-imap/pull/667 for net-imap 0.3.10,
# it is closest to Ruby 2.5.9's net-imap.
# For details, see commit notes 3 equal signs `===` in the patch.
Patch52: rubygem-net-imap-0.3.10-Fix-Information-disclosure-via-man-in-the-middle-attack-bypassing-TLS-CVE-2026-42246.patch
# Fix CVE-2026-42258 IMAP Command Injection via Symbol Arguments.
# https://github.com/ruby/net-imap/commit/1eb27278a601be1135910dae6ab6e517559a2e4a
# https://github.com/ruby/net-imap/commit/bbd9eb7ecca506fa43b656368f7aebef8ac09182
# Additionally, backport validation regex ATOM_SPECIALS that's needed, from
# https://github.com/ruby/net-imap/commit/92db350b24c388d2a2104f36cac9caa49a1044df
# For details, see commit notes 3 equal signs `===` in the patch.
Patch53: rubygem-net-imap-0.4.24-Fix-IMAP-Command-Injection-via-Symbol-Arguments-CVE-2026-42258.patch
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
@ -697,6 +709,8 @@ sed -i 's/"evaluation\/incorrect_words.yaml"\.freeze, //' \
%patch49 -p1
%patch50 -p1
%patch51 -p1
%patch52 -p1
%patch53 -p1
# Provide an example of usage of the tapset:
cp -a %{SOURCE3} .
@ -1261,6 +1275,13 @@ OPENSSL_SYSTEM_CIPHERS_OVERRIDE=xyz_nonexistent_file OPENSSL_CONF='' \
%{gem_dir}/specifications/xmlrpc-%{xmlrpc_version}.gemspec
%changelog
* Thu Jun 11 2026 Jarek Prokop <jprokop@redhat.com> - 2.5.9-115
- Fix information disclosure via MITM attack bypassing TLS in net-imap.
(CVE-2026-42246)
Resolves: RHEL-181772
- Fix command injection via Symbol arguments in net-imap. (CVE-2026-42258)
Resolves: RHEL-181792
* Mon May 05 2025 Vít Ondruch <vondruch@redhat.com> - 2.5.9-114
- Fix integer overflow in search_in_range function in regexec.c (CVE-2019-19012).
Resolves: RHEL-87505