public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/rubygems] rawhide: Update to RubyGems 4.0.20
@ 2026-09-10  7:13 Mamoru TASAKA
  0 siblings, 0 replies; only message in thread
From: Mamoru TASAKA @ 2026-09-10  7:13 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/rubygems
            Branch : rawhide
            Commit : 57adcecd3c079dada37ec29de970b071906901cf
            Author : Mamoru TASAKA <mtasaka@fedoraproject.org>
            Date   : 2026-09-03T23:46:39+09:00
            Stats  : +240/-6 in 4 file(s)
            URL    : https://src.fedoraproject.org/rpms/rubygems/c/57adcecd3c079dada37ec29de970b071906901cf?branch=rawhide

            Log:
            Update to RubyGems 4.0.20

Backport ruby upstream patch to update resolv to 0.7.2
Resolves: CVE-2026-80212 (rhbz#2527309)
Resolves: CVE-2026-80213 (rhbz#2527311)

---
diff --git a/rubygem-4.0.20-update-resolv-0_7_2.patch b/rubygem-4.0.20-update-resolv-0_7_2.patch
new file mode 100644
index 0000000..ff928cf
--- /dev/null
+++ b/rubygem-4.0.20-update-resolv-0_7_2.patch
@@ -0,0 +1,224 @@
+--- rubygems-4.0.20.orig/lib/rubygems/vendor/resolv/lib/resolv.rb	2026-07-14 09:22:10.000000000 +0900
++++ rubygems-4.0.20/lib/rubygems/vendor/resolv/lib/resolv.rb	2026-09-03 17:16:18.543025164 +0900
+@@ -35,7 +35,7 @@
+ class Gem::Resolv
+ 
+   # The version string
+-  VERSION = "0.7.0"
++  VERSION = "0.7.2"
+ 
+   ##
+   # Looks up the first IP address for +name+.
+@@ -487,13 +487,18 @@ def each_name(address)
+     # * Gem::Resolv::DNS::Resource::IN::A
+     # * Gem::Resolv::DNS::Resource::IN::AAAA
+     # * Gem::Resolv::DNS::Resource::IN::ANY
++    # * Gem::Resolv::DNS::Resource::IN::CAA
+     # * Gem::Resolv::DNS::Resource::IN::CNAME
+     # * Gem::Resolv::DNS::Resource::IN::HINFO
++    # * Gem::Resolv::DNS::Resource::IN::HTTPS
++    # * Gem::Resolv::DNS::Resource::IN::LOC
+     # * Gem::Resolv::DNS::Resource::IN::MINFO
+     # * Gem::Resolv::DNS::Resource::IN::MX
+     # * Gem::Resolv::DNS::Resource::IN::NS
+     # * Gem::Resolv::DNS::Resource::IN::PTR
+     # * Gem::Resolv::DNS::Resource::IN::SOA
++    # * Gem::Resolv::DNS::Resource::IN::SRV
++    # * Gem::Resolv::DNS::Resource::IN::SVCB
+     # * Gem::Resolv::DNS::Resource::IN::TXT
+     # * Gem::Resolv::DNS::Resource::IN::WKS
+     #
+@@ -721,7 +726,8 @@ def request(sender, tout)
+           begin
+             reply, from = recv_reply(select_result[0])
+           rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
+-                 Errno::ECONNRESET # Windows
++                 Errno::ECONNRESET, # Windows
++                 EOFError
+             # No name server running on the server?
+             # Don't wait anymore.
+             raise ResolvTimeout
+@@ -930,8 +936,11 @@ def initialize(host, port=Port)
+         end
+ 
+         def recv_reply(readable_socks)
+-          len = readable_socks[0].read(2).unpack('n')[0]
++          len_data = readable_socks[0].read(2)
++          raise EOFError if len_data.nil? || len_data.bytesize != 2
++          len = len_data.unpack('n')[0]
+           reply = @socks[0].read(len)
++          raise EOFError if reply.nil? || reply.bytesize != len
+           return reply, nil
+         end
+ 
+@@ -1244,6 +1253,13 @@ def self.split(arg)
+ 
+       class Str # :nodoc:
+         def initialize(string)
++          # A label is limited to 63 octets. [RFC 1035 2.3.4] Checking it here
++          # makes it an invariant of the object: every label, however it was
++          # built, fits in its length octet and cannot wrap it. Callers turn
++          # this into the error their own contract promises.
++          if string.bytesize > 63
++            raise ArgumentError, "DNS label is too long (#{string.bytesize} bytes, max 63): #{string.inspect}"
++          end
+           @string = string
+           # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
+           # This assumes @string is given in ASCII compatible encoding.
+@@ -1289,7 +1305,26 @@ def self.create(arg)
+         when Name
+           return arg
+         when String
+-          return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
++          # A hostname is runtime data rather than a programming mistake, so
++          # both size limits surface as ResolvError to stay rescuable alongside
++          # the rest of name resolution. The type check below is a caller
++          # mistake and keeps raising ArgumentError.
++          begin
++            labels = Label.split(arg)
++          rescue ArgumentError => e
++            raise ResolvError.new(e.message)
++          end
++          # Label::Str enforces the per-label limit. Only the total is knowable
++          # here, and it counts the encoded form, so size starts at 1 for the
++          # root label's terminating zero octet. [RFC 1035 2.3.4, 3.1]
++          size = 1
++          labels.each do |label|
++            size += 1 + label.string.bytesize
++            if size > 255
++              raise ResolvError.new("DNS name is too long (#{size} octets, max 255): #{arg.inspect}")
++            end
++          end
++          return Name.new(labels, /\.\z/ =~ arg ? true : false)
+         else
+           raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
+         end
+@@ -1411,12 +1446,24 @@ def ==(other)
+                @rd == other.rd &&
+                @ra == other.ra &&
+                @rcode == other.rcode &&
+-               @question == other.question &&
++               question_equal?(other.question) &&
+                @answer == other.answer &&
+                @authority == other.authority &&
+                @additional == other.additional
+       end
+ 
++      # A question holds the resource class itself, and decoding creates a fresh
++      # class for each unknown type, so the classes cannot be compared by
++      # identity alone.
++      private def question_equal?(other_question) # :nodoc:
++        return false unless @question.length == other_question.length
++        @question.zip(other_question) {|(name, typeclass), (o_name, o_typeclass)|
++          return false unless name == o_name &&
++                              Resource::Generic.type_class_equal?(typeclass, o_typeclass)
++        }
++        return true
++      end
++
+       def add_question(name, typeclass)
+         @question << [Name.create(name), typeclass]
+       end
+@@ -1523,8 +1570,15 @@ def put_length16
+         end
+ 
+         def put_string(d)
+-          self.put_pack("C", d.length)
+-          @data << d
++          s = d.to_s
++          # A character-string is prefixed by a single length octet, so it can
++          # hold at most 255 octets. [RFC 1035 3.3] Reject anything longer to
++          # avoid silently truncating the length to its low 8 bits (mod 256).
++          if s.bytesize > 255
++            raise ArgumentError, "character-string is too long (#{s.bytesize} bytes, max 255): #{s.inspect}"
++          end
++          self.put_pack("C", s.bytesize)
++          @data << s
+         end
+ 
+         def put_string_list(ds)
+@@ -1554,7 +1608,17 @@ def put_labels(d, compress: true)
+         end
+ 
+         def put_label(d)
+-          self.put_string(d.to_s)
++          s = d.to_s
++          # Label::Str applies this limit when a label is built, so what is left
++          # for here is a raw string handed straight to put_labels. The two ways
++          # an over-long label goes wrong differ: 64 to 255 octets write a length
++          # octet in the reserved or compression pointer range, and 256 or more
++          # wrap it mod 256. Either way the encoded name stops being the name the
++          # caller asked for. [RFC 1035 2.3.4, 4.1.4]
++          if s.bytesize > 63
++            raise ArgumentError, "DNS label is too long (#{s.bytesize} bytes, max 63): #{s.inspect}"
++          end
++          self.put_string(s)
+         end
+       end
+ 
+@@ -1680,7 +1744,9 @@ def get_labels
+           prev_index = @index
+           save_index = nil
+           d = []
+-          size = -1
++          # size counts the encoded form, so it starts at 1 for the root
++          # label's terminating zero octet. [RFC 1035 3.1]
++          size = 1
+           while true
+             raise DecodeError.new("limit exceeded") if @limit <= @index
+             case @data.getbyte(@index)
+@@ -1711,6 +1777,11 @@ def get_labels
+ 
+         def get_label
+           return Label::Str.new(self.get_string)
++        rescue ArgumentError => e
++          # A length octet of 64..191 is reserved rather than a label length,
++          # but this decoder used to read it as one. [RFC 1035 4.1.4] Report it
++          # the way the rest of a malformed message is reported.
++          raise DecodeError.new(e.message)
+         end
+ 
+         def get_question
+@@ -1898,8 +1969,9 @@ def self.create(key_number)
+           key_name = :"key#{key_number}"
+           c.const_set(:KeyName, key_name)
+           c.const_set(:KeyNumber, key_number)
+-          self.const_set(:"Key#{key_number}", c)
+-          ClassHash[key_name] = ClassHash[key_number] = c
++          # Not registered in a constant or in ClassHash. ClassHash creates a
++          # class for every unknown SvcParamKey, so registering them
++          # permanently would let a malicious response exhaust memory.
+           return c
+         end
+       end
+@@ -2206,12 +2278,28 @@ def self.decode_rdata(msg) # :nodoc:
+           return self.new(msg.get_bytes)
+         end
+ 
++        # create makes a fresh class for each decoded resource, so the type and
++        # class values have to be compared instead of the class itself.
++        def self.type_class_equal?(klass, other) # :nodoc:
++          return true if klass.equal?(other)
++          Generic > klass && Generic > other &&
++            klass::TypeValue == other::TypeValue &&
++            klass::ClassValue == other::ClassValue
++        end
++
++        def ==(other) # :nodoc:
++          return other.is_a?(Generic) &&
++                 Generic.type_class_equal?(self.class, other.class) &&
++                 @data == other.data
++        end
++
+         def self.create(type_value, class_value) # :nodoc:
+           c = Class.new(Generic)
+           c.const_set(:TypeValue, type_value)
+           c.const_set(:ClassValue, class_value)
+-          Generic.const_set("Type#{type_value}_Class#{class_value}", c)
+-          ClassHash[[type_value, class_value]] = c
++          # Not registered in a constant or in ClassHash. get_class creates a
++          # class for every unknown (type, class) pair, so registering them
++          # permanently would let a malicious response exhaust memory.
+           return c
+         end
+       end

diff --git a/rubygems-create-missing-test-files.sh b/rubygems-create-missing-test-files.sh
index ec598a0..7566ab9 100644
--- a/rubygems-create-missing-test-files.sh
+++ b/rubygems-create-missing-test-files.sh
@@ -29,6 +29,7 @@ cd ..
 
 tar czf $CURDIR/${PKGNAME}-${VERSION}-test-missing-files.tar.gz \
 	${GITTOPDIR}/test/ \
+	${GITTOPDIR}/bundler/spec/support/*.rb \
 
 popd
 rm -rf $TMPDIR

diff --git a/rubygems.spec b/rubygems.spec
index f8859e5..bc7c1a9 100644
--- a/rubygems.spec
+++ b/rubygems.spec
@@ -7,14 +7,14 @@
 %global rubygems_net_http_version 0.7.0
 %global rubygems_net_protocol_version 0.2.2
 %global rubygems_optparse_version 0.8.0
-%global rubygems_resolv_version 0.7.0
+%global rubygems_resolv_version 0.7.2
 %global rubygems_securerandom_version 0.4.1
 %global rubygems_timeout_version 0.4.4
 %global rubygems_tsort_version 0.2.0
 %global rubygems_uri_version 1.1.1
 
 # Requires versions
-%global bundler_version 4.0.19
+%global bundler_version 4.0.20
 %global psych_version 5.3.1
 %global rdoc_version 7.0.3
 
@@ -38,7 +38,7 @@
 
 Summary: The Ruby standard for packaging ruby libraries
 Name: rubygems
-Version: 4.0.19
+Version: 4.0.20
 Release: 1%{?dist}
 # BSD-2-Clause OR Ruby:
 #   lib/rubygems/net-http/
@@ -79,7 +79,9 @@ Source12: check_CVE-2013-4363.rb
 # https://bugs.ruby-lang.org/issues/11002
 # NOTE: Keep this patch in sync with ruby.spec.
 Patch0: ruby-2.3.0-ruby_version.patch
-
+# Backport from ruby/ruby_4_0 branch to update resolv to 0.7.2 (fixes CVE-2026-80212 CVE-2026-80213)
+# https://github.com/ruby/ruby/pull/18528
+Patch1: rubygem-4.0.20-update-resolv-0_7_2.patch
 
 Requires:   ruby(release)
 Recommends: rubygem(bundler) >= 4.0
@@ -132,6 +134,7 @@ Documentation for %{name}.
 %setup -q -b 2
 
 %patch 0 -p1
+%patch 1 -p1
 
 %build
 # Nothing
@@ -334,6 +337,12 @@ ruby %{SOURCE12}
 
 
 %changelog
+* Thu Sep 03 2026 Mamoru TASAKA <mtasaka@fedoraproject.org> - 4.0.20-1
+- Update to RubyGems 4.0.20
+- Backport ruby upstream patch to update resolv to 0.7.2
+- Resolves: CVE-2026-80212 (rhbz#2527309)
+- Resolves: CVE-2026-80213 (rhbz#2527311)
+
 * Sat Aug 22 2026 Mamoru TASAKA <mtasaka@fedoraproject.org> - 4.0.19-1
 - Update to RubyGems 4.0.19
 

diff --git a/sources b/sources
index abebe88..5866189 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (rubygems-4.0.19.tgz) = a35400cee5cfb4ce662bbbd7d31cc12f5fe2ab6bf2c7f3bb6d5c3035a9566b82b4fbaeeb8dbdde63ec030da1207e4af41fad423ef8efacc0adbf45927b4631df
-SHA512 (rubygems-4.0.19-test-missing-files.tar.gz) = 3d43998c985e3824cf75cd330f86f10f7f1aeb32a0540a03f7809b014f50588489c028ca29d75b9ed4b36e8eb468cc503c88b15e7844c2206e311f0d921b65ac
+SHA512 (rubygems-4.0.20.tgz) = 224c8feb43dc6d8713c911db07fa4c6a888ed1cc01ca87f1b63e8c70afa728596be329f95add09d5e09d985f741f306911900238c93b67a245be3c69583f0cd9
+SHA512 (rubygems-4.0.20-test-missing-files.tar.gz) = 302964d038c239e38c40c949c887d0daaa108259598d63130a41fb46c7f77ebd13d1c10f78a6ceb0e09c5d11bc12045f659f555a52d8ad5b5ebeae0240cd4f6b

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-10  7:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-10  7:13 [rpms/rubygems] rawhide: Update to RubyGems 4.0.20 Mamoru TASAKA

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox