diff --git a/configs/components/ruby-2.7.8.rb b/configs/components/ruby-2.7.8.rb index cf1df8999..e1f396753 100644 --- a/configs/components/ruby-2.7.8.rb +++ b/configs/components/ruby-2.7.8.rb @@ -42,6 +42,9 @@ pkg.apply_patch "#{base}/uri-redos-cve-2023-36617.patch" + # This patch is not required for ruby >= 3.3.3 + pkg.apply_patch "#{base}/rexml_for_CVE-2024-35176.patch" + if platform.is_cross_compiled? unless platform.is_macos? pkg.apply_patch "#{base}/uri_generic_remove_safe_nav_operator_r2.5.patch" diff --git a/configs/components/ruby-3.2.4.rb b/configs/components/ruby-3.2.4.rb index b5e808a1b..027d5587f 100644 --- a/configs/components/ruby-3.2.4.rb +++ b/configs/components/ruby-3.2.4.rb @@ -300,4 +300,18 @@ ] end end + + ######### + # BUILD + ######### + + pkg.add_source("file://resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch") + + pkg.build do + # This patch is applied after the install step because rexml gem is the bundled gem hence build + # cannot find the path of the files to be patched prior to configuring and installing. + # This patch is not required for ruby >= 3.3.3 + steps = ["#{platform.patch} --strip=1 --fuzz=0 --ignore-whitespace --no-backup-if-mismatch < ../rexml_for_CVE-2024-35176.patch"] + end + end diff --git a/resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch b/resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch new file mode 100644 index 000000000..f53f6bae3 --- /dev/null +++ b/resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch @@ -0,0 +1,135 @@ +commit e597f07718c27dc4414ad39f121376e53056475a +Author: Shubham Shinde +Date: Tue Jul 9 19:40:43 2024 +0530 + + Read quoted attributes in chunks (#126) + + + # Conflicts: + # lib/rexml/parsers/baseparser.rb + # lib/rexml/source.rb + +diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb +index f76aed0..f0b365d 100644 +--- a/lib/rexml/parsers/baseparser.rb ++++ b/lib/rexml/parsers/baseparser.rb +@@ -518,25 +518,43 @@ module REXML + message = "Missing attribute equal: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- quote = scanner.scan(/['"]/) +- unless quote ++ unless match = @source.match(/(['"])/, true) + message = "Missing attribute value start quote: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- unless scanner.scan(/.*#{Regexp.escape(quote)}/um) +- match_data = @source.match(/^(.*?)(\/)?>/um, true) +- if match_data +- scanner << "/" if closed +- scanner << ">" +- scanner << match_data[1] +- scanner.pos = pos +- closed = !match_data[2].nil? +- next +- end +- message = +- "Missing attribute value end quote: <#{name}>: <#{quote}>" ++ quote = match[1] ++ value = @source.read_until(quote) ++ unless value.chomp!(quote) ++ message = "Missing attribute value end quote: <#{name}>: <#{quote}>" + raise REXML::ParseException.new(message, @source) + end ++ @source.match(/\s*/um, true) ++ if prefix == "xmlns" ++ if local_part == "xml" ++ if value != "http://www.w3.org/XML/1998/namespace" ++ msg = "The 'xml' prefix must not be bound to any other namespace "+ ++ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" ++ raise REXML::ParseException.new( msg, @source, self ) ++ end ++ elsif local_part == "xmlns" ++ msg = "The 'xmlns' prefix must not be declared "+ ++ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" ++ raise REXML::ParseException.new( msg, @source, self) ++ end ++ curr_ns << local_part ++ elsif prefix ++ prefixes << prefix unless prefix == "xml" ++ end ++ ++ if attributes[name] ++ msg = "Duplicate attribute #{name.inspect}" ++ raise REXML::ParseException.new(msg, @source, self) ++ end ++ ++ attributes[name] = value ++ else ++ message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>" ++ raise REXML::ParseException.new(message, @source) + end + name = scanner[1] + prefix = scanner[2] +diff --git a/lib/rexml/source.rb b/lib/rexml/source.rb +index 770aefc..86bf6cf 100644 +--- a/lib/rexml/source.rb ++++ b/lib/rexml/source.rb +@@ -81,7 +81,11 @@ module REXML + rv + end + +- def read ++ def read(term = nil) ++ end ++ ++ def read_until(term) ++ @scanner.scan_until(Regexp.union(term)) or @scanner.rest + end + + def consume( pattern ) +@@ -204,9 +208,9 @@ module REXML + rv + end + +- def read ++ def read(term = nil) + begin +- @buffer << readline ++ @buffer << readline(term) + rescue Exception, NameError + @source = nil + end +@@ -216,6 +220,21 @@ module REXML + match( pattern, true ) + end + ++ def read_until(term) ++ pattern = Regexp.union(term) ++ data = [] ++ begin ++ until str = @scanner.scan_until(pattern) ++ @scanner << readline(term) ++ end ++ rescue EOFError ++ @scanner.rest ++ else ++ read if @scanner.eos? and !@source.eof? ++ str ++ end ++ end ++ + def match( pattern, cons=false ) + rv = pattern.match(@buffer) + @buffer = $' if cons and rv +@@ -263,8 +282,8 @@ module REXML + end + + private +- def readline +- str = @source.readline(@line_break) ++ def readline(term = nil) ++ str = @source.readline(term || @line_break) + if @pending_buffer + if str.nil? + str = @pending_buffer diff --git a/resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch b/resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch new file mode 100644 index 000000000..ef79a19b4 --- /dev/null +++ b/resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch @@ -0,0 +1,123 @@ + +diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb +index 90b370b..373abcf 100644 +--- a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb ++++ b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb +@@ -81,7 +81,11 @@ module REXML + rv + end + +- def read ++ def read(term = nil) ++ end ++ ++ def read_until(term) ++ @scanner.scan_until(Regexp.union(term)) or @scanner.rest + end + + def consume( pattern ) +@@ -204,14 +208,29 @@ module REXML + rv + end + +- def read ++ def read(term = nil) + begin +- @buffer << readline ++ @buffer << readline(term) + rescue Exception, NameError + @source = nil + end + end + ++ def read_until(term) ++ pattern = Regexp.union(term) ++ data = [] ++ begin ++ until str = @scanner.scan_until(pattern) ++ @scanner << readline(term) ++ end ++ rescue EOFError ++ @scanner.rest ++ else ++ read if @scanner.eos? and !@source.eof? ++ str ++ end ++ end ++ + def consume( pattern ) + match( pattern, true ) + end +@@ -263,8 +282,8 @@ module REXML + end + + private +- def readline +- str = @source.readline(@line_break) ++ def readline(term = nil) ++ str = @source.readline(term || @line_break) + if @pending_buffer + if str.nil? + str = @pending_buffer +diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb +index 305b120..7001bb2 100644 +--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb ++++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb +@@ -618,25 +618,43 @@ module REXML + message = "Missing attribute equal: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- quote = scanner.scan(/['"]/) +- unless quote ++ unless match = @source.match(/(['"])/, true) + message = "Missing attribute value start quote: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- unless scanner.scan(/.*#{Regexp.escape(quote)}/um) +- match_data = @source.match(/^(.*?)(\/)?>/um, true) +- if match_data +- scanner << "/" if closed +- scanner << ">" +- scanner << match_data[1] +- scanner.pos = pos +- closed = !match_data[2].nil? +- next +- end +- message = +- "Missing attribute value end quote: <#{name}>: <#{quote}>" ++ quote = match[1] ++ value = @source.read_until(quote) ++ unless value.chomp!(quote) ++ message = "Missing attribute value end quote: <#{name}>: <#{quote}>" + raise REXML::ParseException.new(message, @source) + end ++ @source.match(/\s*/um, true) ++ if prefix == "xmlns" ++ if local_part == "xml" ++ if value != "http://www.w3.org/XML/1998/namespace" ++ msg = "The 'xml' prefix must not be bound to any other namespace "+ ++ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" ++ raise REXML::ParseException.new( msg, @source, self ) ++ end ++ elsif local_part == "xmlns" ++ msg = "The 'xmlns' prefix must not be declared "+ ++ "(http://www.w3.org/TR/REC-xml-names/#ns-decl)" ++ raise REXML::ParseException.new( msg, @source, self) ++ end ++ curr_ns << local_part ++ elsif prefix ++ prefixes << prefix unless prefix == "xml" ++ end ++ ++ if attributes[name] ++ msg = "Duplicate attribute #{name.inspect}" ++ raise REXML::ParseException.new(msg, @source, self) ++ end ++ ++ attributes[name] = value ++ else ++ message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>" ++ raise REXML::ParseException.new(message, @source) + end + name = scanner[1] + prefix = scanner[2]