From 395eb24f1cb786eec85432d3e767b8ff78390a85 Mon Sep 17 00:00:00 2001 From: Amit Karsale Date: Tue, 2 Jul 2024 22:58:26 +0530 Subject: [PATCH] (PA-6507) Patch REXML for CVE-2024-35176 in ruby 2.7 and 3.2 --- configs/components/ruby-2.7.8.rb | 22 +++++ configs/components/ruby-3.2.4.rb | 22 +++++ .../ruby_27/rexml_for_CVE-2024-35176.patch | 96 +++++++++++++++++++ .../ruby_32/rexml_for_CVE-2024-35176.patch | 96 +++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch create mode 100644 resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch diff --git a/configs/components/ruby-2.7.8.rb b/configs/components/ruby-2.7.8.rb index cf1df8999..f067df63a 100644 --- a/configs/components/ruby-2.7.8.rb +++ b/configs/components/ruby-2.7.8.rb @@ -42,6 +42,7 @@ pkg.apply_patch "#{base}/uri-redos-cve-2023-36617.patch" + if platform.is_cross_compiled? unless platform.is_macos? pkg.apply_patch "#{base}/uri_generic_remove_safe_nav_operator_r2.5.patch" @@ -169,6 +170,26 @@ ] end + ######### + # BUILD + ######### + + pkg.add_source("file://resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch") + + pkg.build do + # This patch is applied after install because rexml gem is the bundled gem unlike default gems and hence + # not able to find the path of the files to be patched prior configuring and installing + #this patch is not required in ruby >= 3.2.5 + ruby = "#{ruby_bindir}/ruby -rrbconfig" + steps = [ + "export RUBYHDRDIR=$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"rubyhdrdir\"]')", + "export VENDORARCHDIR=$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"vendorarchdir\"]')", + "export ARCHDIR=$${RUBYHDRDIR}/$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"arch\"]')", + "export INCLUDESTR=\"-I#{settings[:includedir]} -I$${RUBYHDRDIR} -I$${ARCHDIR}\"" + ] + steps = ["#{platform.patch} --strip=1 --fuzz=3 --ignore-whitespace --no-backup-if-mismatch < ../rexml_for_CVE-2024-35176.patch"] + end + ######### # INSTALL ######### @@ -268,4 +289,5 @@ ] end end + end diff --git a/configs/components/ruby-3.2.4.rb b/configs/components/ruby-3.2.4.rb index b5e808a1b..a2bc01566 100644 --- a/configs/components/ruby-3.2.4.rb +++ b/configs/components/ruby-3.2.4.rb @@ -38,6 +38,7 @@ base = 'resources/patches/ruby_32' + if platform.is_cross_compiled? pkg.apply_patch "#{base}/rbinstall_gem_path.patch" end @@ -300,4 +301,25 @@ ] 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 install because rexml gem is the bundled gem unlike default gems and hence + # not able to find the path of the files to be patched prior configuring and installing + #this patch is not required in ruby >= 3.2.5 + ruby = "#{ruby_bindir}/ruby -rrbconfig" + steps = [ + "export RUBYHDRDIR=$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"rubyhdrdir\"]')", + "export VENDORARCHDIR=$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"vendorarchdir\"]')", + "export ARCHDIR=$${RUBYHDRDIR}/$(shell #{ruby} -e 'puts RbConfig::CONFIG[\"arch\"]')", + "export INCLUDESTR=\"-I#{settings[:includedir]} -I$${RUBYHDRDIR} -I$${ARCHDIR}\"" + ] + steps << ["#{platform.patch} --strip=1 --fuzz=3 --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..a2de9b025 --- /dev/null +++ b/resources/patches/ruby_27/rexml_for_CVE-2024-35176.patch @@ -0,0 +1,96 @@ + +diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb +index 8d62391c..d09237c5 100644 +--- a/lib/rexml/parsers/baseparser.rb ++++ b/lib/rexml/parsers/baseparser.rb +@@ -628,17 +628,17 @@ def parse_attributes(prefixes, curr_ns) + message = "Missing attribute equal: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- unless match = @source.match(/(['"])(.*?)\1\s*/um, true) +- if match = @source.match(/(['"])/, true) +- message = +- "Missing attribute value end quote: <#{name}>: <#{match[1]}>" +- raise REXML::ParseException.new(message, @source) +- else +- message = "Missing attribute value start quote: <#{name}>" +- raise REXML::ParseException.new(message, @source) +- end ++ unless match = @source.match(/(['"])/, true) ++ message = "Missing attribute value start quote: <#{name}>" ++ raise REXML::ParseException.new(message, @source) ++ end ++ 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 +- value = match[2] ++ @source.match(/\s*/um, true) + if prefix == "xmlns" + if local_part == "xml" + if value != "http://www.w3.org/XML/1998/namespace" +diff --git a/lib/rexml/source.rb b/lib/rexml/source.rb +index 7f47c2be..999751b4 100644 +--- a/lib/rexml/source.rb ++++ b/lib/rexml/source.rb +@@ -65,7 +65,11 @@ def encoding=(enc) + encoding_updated + end + +- def read ++ def read(term = nil) ++ end ++ ++ def read_until(term) ++ @scanner.scan_until(Regexp.union(term)) or @scanner.rest + end + + def ensure_buffer +@@ -158,9 +162,9 @@ def initialize(arg, block_size=500, encoding=nil) + end + end + +- def read ++ def read(term = nil) + begin +- @scanner << readline ++ @scanner << readline(term) + true + rescue Exception, NameError + @source = nil +@@ -168,6 +172,21 @@ def read + 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 ensure_buffer + read if @scanner.eos? && @source + end +@@ -218,8 +237,8 @@ def current_line + 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 + \ No newline at end of file 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..a2de9b025 --- /dev/null +++ b/resources/patches/ruby_32/rexml_for_CVE-2024-35176.patch @@ -0,0 +1,96 @@ + +diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb +index 8d62391c..d09237c5 100644 +--- a/lib/rexml/parsers/baseparser.rb ++++ b/lib/rexml/parsers/baseparser.rb +@@ -628,17 +628,17 @@ def parse_attributes(prefixes, curr_ns) + message = "Missing attribute equal: <#{name}>" + raise REXML::ParseException.new(message, @source) + end +- unless match = @source.match(/(['"])(.*?)\1\s*/um, true) +- if match = @source.match(/(['"])/, true) +- message = +- "Missing attribute value end quote: <#{name}>: <#{match[1]}>" +- raise REXML::ParseException.new(message, @source) +- else +- message = "Missing attribute value start quote: <#{name}>" +- raise REXML::ParseException.new(message, @source) +- end ++ unless match = @source.match(/(['"])/, true) ++ message = "Missing attribute value start quote: <#{name}>" ++ raise REXML::ParseException.new(message, @source) ++ end ++ 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 +- value = match[2] ++ @source.match(/\s*/um, true) + if prefix == "xmlns" + if local_part == "xml" + if value != "http://www.w3.org/XML/1998/namespace" +diff --git a/lib/rexml/source.rb b/lib/rexml/source.rb +index 7f47c2be..999751b4 100644 +--- a/lib/rexml/source.rb ++++ b/lib/rexml/source.rb +@@ -65,7 +65,11 @@ def encoding=(enc) + encoding_updated + end + +- def read ++ def read(term = nil) ++ end ++ ++ def read_until(term) ++ @scanner.scan_until(Regexp.union(term)) or @scanner.rest + end + + def ensure_buffer +@@ -158,9 +162,9 @@ def initialize(arg, block_size=500, encoding=nil) + end + end + +- def read ++ def read(term = nil) + begin +- @scanner << readline ++ @scanner << readline(term) + true + rescue Exception, NameError + @source = nil +@@ -168,6 +172,21 @@ def read + 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 ensure_buffer + read if @scanner.eos? && @source + end +@@ -218,8 +237,8 @@ def current_line + 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 + \ No newline at end of file