head 1.3; access; symbols pkgsrc-2026Q3:1.3.0.2 pkgsrc-2026Q3-base:1.3 pkgsrc-2025Q2:1.1.0.2; locks; strict; comment @# @; 1.3 date 2026.09.16.15.00.10; author taca; state Exp; branches; next 1.2; commitid nMfza3mde1yQdRVG; 1.2 date 2025.07.26.06.17.00; author taca; state dead; branches; next 1.1; commitid NIgNHKXw6k2RId4G; 1.1 date 2025.07.13.15.39.54; author taca; state Exp; branches 1.1.2.1; next ; commitid FuRFPJE1pOkqgB2G; 1.1.2.1 date 2025.07.13.15.39.54; author maya; state dead; branches; next 1.1.2.2; commitid NZNQiOdOpcESQ23G; 1.1.2.2 date 2025.07.17.02.45.43; author maya; state Exp; branches; next ; commitid NZNQiOdOpcESQ23G; desc @@ 1.3 log @lang/ruby34: update resolv gem Update resolv gem to 0.7.2 to fix CVE-2026-80212 and CVE-2026-80213. Bump PKGREVISION. @ text @$NetBSD$ Update resolv gem to 0.7.2. --- lib/resolv.rb.orig 2026-06-30 10:54:35.000000000 +0000 +++ lib/resolv.rb @@@@ -35,7 +35,7 @@@@ require 'rbconfig' class Resolv # The version string - VERSION = "0.7.1" + VERSION = "0.7.2" ## # Looks up the first IP address for +name+. @@@@ -1253,6 +1253,13 @@@@ class Resolv 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. @@@@ -1298,7 +1305,26 @@@@ class Resolv 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 @@@@ -1420,12 +1446,24 @@@@ class Resolv @@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 @@@@ -1532,8 +1570,15 @@@@ class Resolv 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) @@@@ -1563,7 +1608,17 @@@@ class Resolv 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 @@@@ -1689,7 +1744,9 @@@@ class Resolv 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) @@@@ -1720,6 +1777,11 @@@@ class Resolv 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 @@@@ -1907,8 +1969,9 @@@@ class Resolv 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 @@@@ -2215,12 +2278,28 @@@@ class Resolv 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 @ 1.2 log @lang/ruby34: update to 3.4.5 pkgsrc change: * Enable sigaltstack(2) on NetBSD refering to PR pkg/59017. Ruby 3.4.5 (2025-07-15) * Bug #21340: Bump autoconf version to properly handle C23 bool/stdbool defines * Sync lockfile from rubygems/rubygems by deivid-rodriguez · Pull Request #13472 * Bug #21438: use-after-free when resizing exivars * Ensure that memory is not freed before calling free_fast_fallback_getaddrinfo_* by shioimm · Pull Request #12661 * Fix heap-use-after-free in free_fast_fallback_getaddrinfo_entry by shioimm Pull Request #13231 * Bug #21441: SEGV during thread cleanup if profiler calls thread_profiles_frames at wrong time * Bug #21255: Can't build Ruby with Windows SDK 10.0.26100 * Backport GH-13617 for s390x by hsbt · Pull Request #13757 * Bump up resolv-0.6.2 for Ruby 3.4 by hsbt · Pull Request #13818 * Bug #21197: Prism does not accept newline after defined? keyword * Bug #21333: heap-use-after-free caused by rehash during update * Bug #21357: Crash in Hash#merge! with ruby-dev in rubocop-rspec test suite * Bug #21383: Prism leaks memory with invalid yield * Bug #21394: Memory leak in Prism's RubyVM::InstructionSequence.new * Bug #21099: TestGc#test_gc_stress_at_startup assertion failure * Bug #21395: Please backport caa6ba1a46afa1bc696adc5fe91ee992f9570c89 * Bug #21439: Crash with PM_SPLAT_NODE compiler error (Prism) * Bug #21354: Symbol#to_proc is not ractor safe * Bug #20009: Marshal.load raises exception when load dumped class include non-ASCII * Bug #21380: Use-After-Free in String#split with In-Block String Modification * Bug #21447: Fix handling of PM_CONSTANT_PATH_NODE node in keyword arguments with ARGS_SPLAT * Bug #21448: Random.urandom may fail to fall back to reading /dev/urandom on Linux < 3.17 * Bug #21440: Cannot create instances of frozen Data subclasses * Bug #21437: Date#hash may return different values for equal dates with large years * Bug #21497: building issue when using gcc15, because C23 is default * Bug #21500: Backport gcc 15 support @ text @d1 1 a1 1 $NetBSD: patch-lib_resolv.rb,v 1.1 2025/07/13 15:39:54 taca Exp $ d3 1 a3 1 Update resolv gem to 0.6.2. d5 1 a5 1 --- lib/resolv.rb.orig 2025-05-14 03:11:06.000000000 +0000 d7 1 a7 2 @@@@ -33,7 +33,7 @@@@ require 'securerandom' d10 3 a12 2 - VERSION = "0.6.0" + VERSION = "0.6.2" d16 1 a16 1 @@@@ -173,13 +173,16 @@@@ class Resolv d18 50 a67 1 class ResolvTimeout < Timeout::Error; end d69 11 a79 2 + WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/ + private_constant :WINDOWS d81 19 a99 2 ## # Resolv::Hosts is a hostname resolver that uses the system hosts file. d101 3 a103 56 class Hosts - if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and + if WINDOWS begin - require 'win32/resolv' + require 'win32/resolv' unless defined?(Win32::Resolv) DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL rescue LoadError end @@@@ -659,8 +662,20 @@@@ class Resolv } end - def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: - begin + case RUBY_PLATFORM + when *[ + # https://www.rfc-editor.org/rfc/rfc6056.txt + # Appendix A. Survey of the Algorithms in Use by Some Popular Implementations + /freebsd/, /linux/, /netbsd/, /openbsd/, /solaris/, + /darwin/, # the same as FreeBSD + ] then + def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: + udpsock.bind(bind_host, 0) + end + else + # Sequential port assignment + def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: + # Ephemeral port number range recommended by RFC 6056 port = random(1024..65535) udpsock.bind(bind_host, port) rescue Errno::EADDRINUSE, # POSIX @@@@ -983,13 +998,13 @@@@ class Resolv next unless keyword case keyword when 'nameserver' - nameserver.concat(args) + nameserver.concat(args.each(&:freeze)) when 'domain' next if args.empty? - search = [args[0]] + search = [args[0].freeze] when 'search' next if args.empty? - search = args + search = args.each(&:freeze) when 'options' args.each {|arg| case arg @@@@ -1000,22 +1015,22 @@@@ class Resolv end } } - return { :nameserver => nameserver, :search => search, :ndots => ndots } + return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze end d105 13 a117 20 def Config.default_config_hash(filename="/etc/resolv.conf") if File.exist? filename - config_hash = Config.parse_resolv_conf(filename) + Config.parse_resolv_conf(filename) + elsif WINDOWS + require 'win32/resolv' unless defined?(Win32::Resolv) + search, nameserver = Win32::Resolv.get_resolv_info + config_hash = {} + config_hash[:nameserver] = nameserver if nameserver + config_hash[:search] = [search].flatten if search + config_hash else - if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM - require 'win32/resolv' - search, nameserver = Win32::Resolv.get_resolv_info - config_hash = {} - config_hash[:nameserver] = nameserver if nameserver - config_hash[:search] = [search].flatten if search - end + {} a118 1 - config_hash || {} d121 1 a121 2 def lazy_initialize @@@@ -1664,6 +1679,7 @@@@ class Resolv d125 4 a128 1 + size = -1 d132 10 a141 25 @@@@ -1684,7 +1700,10 @@@@ class Resolv end @@index = idx else - d << self.get_label + l = self.get_label + d << l + size += 1 + l.string.bytesize + raise DecodeError.new("name label data exceed 255 octets") if size > 255 end end end @@@@ -2110,7 +2129,14 @@@@ class Resolv attr_reader :ttl - ClassHash = {} # :nodoc: + ClassHash = Module.new do + module_function + + def []=(type_class_value, klass) + type_value, class_value = type_class_value + Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass) + end + end d143 12 a154 3 def encode_rdata(msg) # :nodoc: raise NotImplementedError.new @@@@ -2148,7 +2174,9 @@@@ class Resolv d156 3 d160 8 a167 3 def self.get_class(type_value, class_value) # :nodoc: - return ClassHash[[type_value, class_value]] || + cache = :"Type#{type_value}_Class#{class_value}" d169 17 a185 2 + return (const_defined?(cache) && const_get(cache)) || Generic.create(type_value, class_value) a186 10 @@@@ -2577,7 +2605,7 @@@@ class Resolv end ## - # Flags for this proprty: + # Flags for this property: # - Bit 0 : 0 = not critical, 1 = critical attr_reader :flags @ 1.1 log @lang/ruby34: update resolv gem Update resolve gem to 0.6.2 to fix security problem of CVE-2025-24294. Bump PKGREVISION. @ text @d1 1 a1 1 $NetBSD$ @ 1.1.2.1 log @file patch-lib_resolv.rb was added on branch pkgsrc-2025Q2 on 2025-07-17 02:45:43 +0000 @ text @d1 163 @ 1.1.2.2 log @Pullup ticket #6988 - requested by taca lang/ruby34: Security fix Revisions pulled up: - lang/ruby/rubyversion.mk 1.301 - lang/ruby34/Makefile 1.6 - lang/ruby34/distinfo 1.8 - lang/ruby34/patches/patch-ext_win32_lib_win32_resolv.rb 1.1 - lang/ruby34/patches/patch-ext_win32_resolv_resolv.c 1.1 - lang/ruby34/patches/patch-lib_resolv.rb 1.1 - lang/ruby34/patches/patch-test_resolv_test__dns.rb 1.1 --- Module Name: pkgsrc Committed By: taca Date: Sun Jul 13 15:39:55 UTC 2025 Modified Files: pkgsrc/lang/ruby: rubyversion.mk pkgsrc/lang/ruby34: Makefile distinfo Added Files: pkgsrc/lang/ruby34/patches: patch-ext_win32_lib_win32_resolv.rb patch-ext_win32_resolv_resolv.c patch-lib_resolv.rb patch-test_resolv_test__dns.rb Log Message: lang/ruby34: update resolv gem Update resolve gem to 0.6.2 to fix security problem of CVE-2025-24294. Bump PKGREVISION. @ text @a0 163 $NetBSD: patch-lib_resolv.rb,v 1.1 2025/07/13 15:39:54 taca Exp $ Update resolv gem to 0.6.2. --- lib/resolv.rb.orig 2025-05-14 03:11:06.000000000 +0000 +++ lib/resolv.rb @@@@ -33,7 +33,7 @@@@ require 'securerandom' class Resolv - VERSION = "0.6.0" + VERSION = "0.6.2" ## # Looks up the first IP address for +name+. @@@@ -173,13 +173,16 @@@@ class Resolv class ResolvTimeout < Timeout::Error; end + WINDOWS = /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::RbConfig::CONFIG['host_os'] =~ /mswin/ + private_constant :WINDOWS + ## # Resolv::Hosts is a hostname resolver that uses the system hosts file. class Hosts - if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and + if WINDOWS begin - require 'win32/resolv' + require 'win32/resolv' unless defined?(Win32::Resolv) DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL rescue LoadError end @@@@ -659,8 +662,20 @@@@ class Resolv } end - def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: - begin + case RUBY_PLATFORM + when *[ + # https://www.rfc-editor.org/rfc/rfc6056.txt + # Appendix A. Survey of the Algorithms in Use by Some Popular Implementations + /freebsd/, /linux/, /netbsd/, /openbsd/, /solaris/, + /darwin/, # the same as FreeBSD + ] then + def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: + udpsock.bind(bind_host, 0) + end + else + # Sequential port assignment + def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: + # Ephemeral port number range recommended by RFC 6056 port = random(1024..65535) udpsock.bind(bind_host, port) rescue Errno::EADDRINUSE, # POSIX @@@@ -983,13 +998,13 @@@@ class Resolv next unless keyword case keyword when 'nameserver' - nameserver.concat(args) + nameserver.concat(args.each(&:freeze)) when 'domain' next if args.empty? - search = [args[0]] + search = [args[0].freeze] when 'search' next if args.empty? - search = args + search = args.each(&:freeze) when 'options' args.each {|arg| case arg @@@@ -1000,22 +1015,22 @@@@ class Resolv end } } - return { :nameserver => nameserver, :search => search, :ndots => ndots } + return { :nameserver => nameserver.freeze, :search => search.freeze, :ndots => ndots.freeze }.freeze end def Config.default_config_hash(filename="/etc/resolv.conf") if File.exist? filename - config_hash = Config.parse_resolv_conf(filename) + Config.parse_resolv_conf(filename) + elsif WINDOWS + require 'win32/resolv' unless defined?(Win32::Resolv) + search, nameserver = Win32::Resolv.get_resolv_info + config_hash = {} + config_hash[:nameserver] = nameserver if nameserver + config_hash[:search] = [search].flatten if search + config_hash else - if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM - require 'win32/resolv' - search, nameserver = Win32::Resolv.get_resolv_info - config_hash = {} - config_hash[:nameserver] = nameserver if nameserver - config_hash[:search] = [search].flatten if search - end + {} end - config_hash || {} end def lazy_initialize @@@@ -1664,6 +1679,7 @@@@ class Resolv prev_index = @@index save_index = nil d = [] + size = -1 while true raise DecodeError.new("limit exceeded") if @@limit <= @@index case @@data.getbyte(@@index) @@@@ -1684,7 +1700,10 @@@@ class Resolv end @@index = idx else - d << self.get_label + l = self.get_label + d << l + size += 1 + l.string.bytesize + raise DecodeError.new("name label data exceed 255 octets") if size > 255 end end end @@@@ -2110,7 +2129,14 @@@@ class Resolv attr_reader :ttl - ClassHash = {} # :nodoc: + ClassHash = Module.new do + module_function + + def []=(type_class_value, klass) + type_value, class_value = type_class_value + Resource.const_set(:"Type#{type_value}_Class#{class_value}", klass) + end + end def encode_rdata(msg) # :nodoc: raise NotImplementedError.new @@@@ -2148,7 +2174,9 @@@@ class Resolv end def self.get_class(type_value, class_value) # :nodoc: - return ClassHash[[type_value, class_value]] || + cache = :"Type#{type_value}_Class#{class_value}" + + return (const_defined?(cache) && const_get(cache)) || Generic.create(type_value, class_value) end @@@@ -2577,7 +2605,7 @@@@ class Resolv end ## - # Flags for this proprty: + # Flags for this property: # - Bit 0 : 0 = not critical, 1 = critical attr_reader :flags @