diff mbox series

[kirkstone,3/3] ruby: fix CVE-2024-41123

Message ID 20251120093722.4148633-3-divya.chellam@windriver.com
State New
Headers show
Series [kirkstone,1/3] ruby: fix CVE-2024-35176 | expand

Commit Message

dchellam Nov. 20, 2025, 9:37 a.m. UTC
From: Divya Chellam <divya.chellam@windriver.com>

REXML is an XML toolkit for Ruby. The REXML gem before 3.3.2 has some DoS
vulnerabilities when it parses an XML that has many specific characters
such as whitespace character, `>]` and `]>`. The REXML gem 3.3.3 or later
include the patches to fix these vulnerabilities.

Reference:
https://nvd.nist.gov/vuln/detail/CVE-2024-41123

Upstream-patches:
https://github.com/ruby/rexml/commit/2c39c91a65d69357cfbc35dd8079b3606d86bb70
https://github.com/ruby/rexml/commit/4444a04ece4c02a7bd51e8c75623f22dc12d882b
https://github.com/ruby/rexml/commit/ebc3e85bfa2796fb4922c1932760bec8390ff87c
https://github.com/ruby/rexml/commit/6cac15d45864c8d70904baa5cbfcc97181000960
https://github.com/ruby/rexml/commit/e2546e6ecade16b04c9ee528e5be8509fe16c2d6

Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
---
 .../ruby/ruby/CVE-2024-41123-0001.patch       |  44 +++++
 .../ruby/ruby/CVE-2024-41123-0002.patch       |  37 ++++
 .../ruby/ruby/CVE-2024-41123-0003.patch       |  55 ++++++
 .../ruby/ruby/CVE-2024-41123-0004.patch       | 163 ++++++++++++++++++
 .../ruby/ruby/CVE-2024-41123-0005.patch       | 111 ++++++++++++
 meta/recipes-devtools/ruby/ruby_3.1.3.bb      |   5 +
 6 files changed, 415 insertions(+)
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0001.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0002.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0003.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0004.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0005.patch
diff mbox series

Patch

diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0001.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0001.patch
new file mode 100644
index 0000000000..c9d7ed2626
--- /dev/null
+++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0001.patch
@@ -0,0 +1,44 @@ 
+From 2c39c91a65d69357cfbc35dd8079b3606d86bb70 Mon Sep 17 00:00:00 2001
+From: Watson <watson1978@gmail.com>
+Date: Fri, 19 Jul 2024 17:15:15 +0900
+Subject: [PATCH] Fix method scope in test in order to invoke the tests
+ properly and fix exception message (#182)
+
+This PR includes following two fixes.
+
+1. The `test_empty` and `test_linear_performance_gt` were defined as
+private method. Seems that test-unit runner does not invoke private
+methods even if the methods have `test_` prefix.
+2. When parse malformed entity declaration, the exception might have the
+message about `NoMethodError`. The proper exception message will be
+contained by this fix.
+
+CVE: CVE-2024-41123
+
+Upstream-Status: Backport [https://github.com/ruby/rexml/commit/2c39c91a65d69357cfbc35dd8079b3606d86bb70]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ .bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+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 4864ba1..451fbf8 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
+@@ -308,7 +308,11 @@ module REXML
+               raise REXML::ParseException.new( "Bad ELEMENT declaration!", @source ) if md.nil?
+               return [ :elementdecl, "<!ELEMENT" + md[1] ]
+             elsif @source.match("ENTITY", true)
+-              match = [:entitydecl, *@source.match(Private::ENTITYDECL_PATTERN, true, term: Private::ENTITY_TERM).captures.compact]
++              match_data = @source.match(Private::ENTITYDECL_PATTERN, true, term: Private::ENTITY_TERM)
++              unless match_data
++                raise REXML::ParseException.new("Malformed entity declaration", @source)
++              end
++              match = [:entitydecl, *match_data.captures.compact]
+               ref = false
+               if match[1] == '%'
+                 ref = true
+-- 
+2.40.0
+
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0002.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0002.patch
new file mode 100644
index 0000000000..6c6c81d7f1
--- /dev/null
+++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0002.patch
@@ -0,0 +1,37 @@ 
+From 4444a04ece4c02a7bd51e8c75623f22dc12d882b Mon Sep 17 00:00:00 2001
+From: Sutou Kouhei <kou@clear-code.com>
+Date: Sun, 2 Jun 2024 16:59:16 +0900
+Subject: [PATCH] Add missing encode for custom term
+
+CVE: CVE-2024-41123
+
+Upstream-Status: Backport [https://github.com/ruby/rexml/commit/4444a04ece4c02a7bd51e8c75623f22dc12d882b]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ .bundle/gems/rexml-3.2.5/lib/rexml/source.rb | 2 ++
+ 1 file changed, 2 insertions(+)
+
+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 08a035c..7be430a 100644
+--- a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
++++ b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
+@@ -160,6 +160,7 @@ module REXML
+     end
+ 
+     def read(term = nil)
++      term = encode(term) if term
+       begin
+         @scanner << readline(term)
+         true
+@@ -171,6 +172,7 @@ module REXML
+ 
+     def read_until(term)
+       pattern = Regexp.union(term)
++      term = encode(term)
+       data = []
+       begin
+         until str = @scanner.scan_until(pattern)
+-- 
+2.40.0
+
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0003.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0003.patch
new file mode 100644
index 0000000000..d31b77efbf
--- /dev/null
+++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0003.patch
@@ -0,0 +1,55 @@ 
+From ebc3e85bfa2796fb4922c1932760bec8390ff87c Mon Sep 17 00:00:00 2001
+From: NAITOH Jun <naitoh@gmail.com>
+Date: Mon, 8 Jul 2024 05:54:06 +0900
+Subject: [PATCH] Add position check for XML declaration (#162)
+
+XML declaration must be the first item.
+
+https://www.w3.org/TR/2006/REC-xml11-20060816/#document
+
+```
+[1]   document   ::=   ( prolog element Misc* ) - ( Char* RestrictedChar Char* )
+```
+
+https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-prolog
+
+```
+[22]   prolog   ::=     XMLDecl Misc* (doctypedecl Misc*)?
+```
+
+https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-XMLDecl
+
+```
+[23]   XMLDecl  ::=   '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+```
+
+See: https://github.com/ruby/rexml/pull/161#discussion_r1666118193
+
+CVE: CVE-2024-41123
+
+Upstream-Status: Backport [https://github.com/ruby/rexml/commit/ebc3e85bfa2796fb4922c1932760bec8390ff87c]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ .bundle/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+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 451fbf8..71fce99 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
+@@ -670,7 +670,10 @@ module REXML
+           @source.position = start_position
+           raise REXML::ParseException.new(message, @source)
+         end
+-        if @document_status.nil? and match_data[1] == "xml"
++        if match_data[1] == "xml"
++          if @document_status
++            raise ParseException.new("Malformed XML: XML declaration is not at the start", @source)
++          end
+           content = match_data[2]
+           version = VERSION.match(content)
+           version = version[1] unless version.nil?
+-- 
+2.40.0
+
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0004.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0004.patch
new file mode 100644
index 0000000000..4d7603a5b9
--- /dev/null
+++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0004.patch
@@ -0,0 +1,163 @@ 
+From 6cac15d45864c8d70904baa5cbfcc97181000960 Mon Sep 17 00:00:00 2001
+From: tomoya ishida <tomoyapenguin@gmail.com>
+Date: Thu, 1 Aug 2024 09:21:19 +0900
+Subject: [PATCH] Fix source.match performance without specifying term string
+ (#186)
+
+Performance problem of `source.match(regexp)` was recently fixed by
+specifying terminator string. However, I think maintaining appropriate
+terminator string for a regexp is hard.
+I propose solving this performance issue by increasing bytes to read in
+each iteration.
+
+CVE: CVE-2024-41123
+
+Upstream-Status: Backport [https://github.com/ruby/rexml/commit/6cac15d45864c8d70904baa5cbfcc97181000960]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ .../lib/rexml/parsers/baseparser.rb           | 22 ++++++------------
+ .bundle/gems/rexml-3.2.5/lib/rexml/source.rb  | 23 +++++++++++++++----
+ 2 files changed, 25 insertions(+), 20 deletions(-)
+
+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 71fce99..c1a22b8 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
+@@ -124,14 +124,6 @@ module REXML
+       }
+ 
+       module Private
+-        # Terminal requires two or more letters.
+-        INSTRUCTION_TERM = "?>"
+-        COMMENT_TERM = "-->"
+-        CDATA_TERM = "]]>"
+-        DOCTYPE_TERM = "]>"
+-        # Read to the end of DOCTYPE because there is no proper ENTITY termination
+-        ENTITY_TERM = DOCTYPE_TERM
+-
+         INSTRUCTION_END = /#{NAME}(\s+.*?)?\?>/um
+         TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
+         CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
+@@ -244,7 +236,7 @@ module REXML
+             return process_instruction(start_position)
+           elsif @source.match("<!", true)
+             if @source.match("--", true)
+-              md = @source.match(/(.*?)-->/um, true, term: Private::COMMENT_TERM)
++              md = @source.match(/(.*?)-->/um, true)
+               if md.nil?
+                 raise REXML::ParseException.new("Unclosed comment", @source)
+               end
+@@ -308,7 +300,7 @@ module REXML
+               raise REXML::ParseException.new( "Bad ELEMENT declaration!", @source ) if md.nil?
+               return [ :elementdecl, "<!ELEMENT" + md[1] ]
+             elsif @source.match("ENTITY", true)
+-              match_data = @source.match(Private::ENTITYDECL_PATTERN, true, term: Private::ENTITY_TERM)
++              match_data = @source.match(Private::ENTITYDECL_PATTERN, true)
+               unless match_data
+                 raise REXML::ParseException.new("Malformed entity declaration", @source)
+               end
+@@ -377,14 +369,14 @@ module REXML
+                 raise REXML::ParseException.new(message, @source)
+               end
+               return [:notationdecl, name, *id]
+-            elsif md = @source.match(/--(.*?)-->/um, true, term: Private::COMMENT_TERM)
++            elsif md = @source.match(/--(.*?)-->/um, true)
+               case md[1]
+               when /--/, /-\z/
+                 raise REXML::ParseException.new("Malformed comment", @source)
+               end
+               return [ :comment, md[1] ] if md
+             end
+-          elsif match = @source.match(/(%.*?;)\s*/um, true, term: Private::DOCTYPE_TERM)
++          elsif match = @source.match(/(%.*?;)\s*/um, true)
+             return [ :externalentity, match[1] ]
+           elsif @source.match(/\]\s*>/um, true)
+             @document_status = :after_doctype
+@@ -417,7 +409,7 @@ module REXML
+               #STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
+               raise REXML::ParseException.new("Malformed node", @source) unless md
+               if md[0][0] == ?-
+-                md = @source.match(/--(.*?)-->/um, true, term: Private::COMMENT_TERM)
++                md = @source.match(/--(.*?)-->/um, true)
+ 
+                 case md[1]
+                 when /--/, /-\z/
+@@ -426,7 +418,7 @@ module REXML
+ 
+                 return [ :comment, md[1] ] if md
+               else
+-                md = @source.match(/\[CDATA\[(.*?)\]\]>/um, true, term: Private::CDATA_TERM)
++                md = @source.match(/\[CDATA\[(.*?)\]\]>/um, true)
+                 return [ :cdata, md[1] ] if md
+               end
+               raise REXML::ParseException.new( "Declarations can only occur "+
+@@ -664,7 +656,7 @@ module REXML
+       end
+ 
+       def process_instruction(start_position)
+-        match_data = @source.match(Private::INSTRUCTION_END, true, term: Private::INSTRUCTION_TERM)
++        match_data = @source.match(Private::INSTRUCTION_END, true)
+         unless match_data
+           message = "Invalid processing instruction node"
+           @source.position = start_position
+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 7be430a..7c05cb5 100644
+--- a/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
++++ b/.bundle/gems/rexml-3.2.5/lib/rexml/source.rb
+@@ -72,7 +72,7 @@ module REXML
+       @scanner.scan_until(Regexp.union(term)) or @scanner.rest
+     end
+ 
+-    def match(pattern, cons=false, term: nil)
++    def match(pattern, cons=false)
+       if cons
+         @scanner.scan(pattern).nil? ? nil : @scanner
+       else
+@@ -159,10 +159,20 @@ module REXML
+       end
+     end
+ 
+-    def read(term = nil)
++    def read(term = nil, min_bytes = 1)
+       term = encode(term) if term
+       begin
+-        @scanner << readline(term)
++        str = readline(term)
++        @scanner << str
++        read_bytes = str.bytesize
++        begin
++          while read_bytes < min_bytes
++            str = readline(term)
++            @scanner << str
++            read_bytes += str.bytesize
++          end
++        rescue IOError
++        end
+         true
+       rescue Exception, NameError
+         @source = nil
+@@ -186,7 +196,9 @@ module REXML
+       end
+     end
+ 
+-    def match( pattern, cons=false, term: nil )
++    def match( pattern, cons=false )
++      # To avoid performance issue, we need to increase bytes to read per scan
++      min_bytes = 1
+       read if @scanner.eos? && @source
+       while true
+         if cons
+@@ -197,7 +209,8 @@ module REXML
+         break if md
+         return nil if pattern.is_a?(String) && pattern.bytesize <= @scanner.rest_size
+         return nil if @source.nil?
+-        return nil unless read(term)
++        return nil unless read(nil, min_bytes)
++        min_bytes *= 2
+       end
+ 
+       md.nil? ? nil : @scanner
+-- 
+2.40.0
+
diff --git a/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0005.patch b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0005.patch
new file mode 100644
index 0000000000..3d79d07327
--- /dev/null
+++ b/meta/recipes-devtools/ruby/ruby/CVE-2024-41123-0005.patch
@@ -0,0 +1,111 @@ 
+From e2546e6ecade16b04c9ee528e5be8509fe16c2d6 Mon Sep 17 00:00:00 2001
+From: Sutou Kouhei <kou@clear-code.com>
+Date: Thu, 1 Aug 2024 11:23:43 +0900
+Subject: [PATCH] parse pi: improve invalid case detection
+
+CVE: CVE-2024-41123
+
+Upstream-Status: Backport [https://github.com/ruby/rexml/commit/e2546e6ecade16b04c9ee528e5be8509fe16c2d6]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ .../lib/rexml/parsers/baseparser.rb           | 35 +++++++++++--------
+ 1 file changed, 20 insertions(+), 15 deletions(-)
+
+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 c1a22b8..0ece9b5 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
+@@ -124,11 +124,10 @@ module REXML
+       }
+ 
+       module Private
+-        INSTRUCTION_END = /#{NAME}(\s+.*?)?\?>/um
+         TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
+         CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
+         ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
+-        NAME_PATTERN = /\s*#{NAME}/um
++        NAME_PATTERN = /#{NAME}/um
+         GEDECL_PATTERN = "\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
+         PEDECL_PATTERN = "\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
+         ENTITYDECL_PATTERN = /(?:#{GEDECL_PATTERN})|(?:#{PEDECL_PATTERN})/um
+@@ -233,7 +232,7 @@ module REXML
+         if @document_status == nil
+           start_position = @source.position
+           if @source.match("<?", true)
+-            return process_instruction(start_position)
++            return process_instruction
+           elsif @source.match("<!", true)
+             if @source.match("--", true)
+               md = @source.match(/(.*?)-->/um, true)
+@@ -424,7 +423,7 @@ module REXML
+               raise REXML::ParseException.new( "Declarations can only occur "+
+                 "in the doctype declaration.", @source)
+             elsif @source.match("?", true)
+-              return process_instruction(start_position)
++              return process_instruction
+             else
+               # Get the next tag
+               md = @source.match(TAG_PATTERN, true)
+@@ -579,14 +578,14 @@ module REXML
+       def parse_name(base_error_message)
+         md = @source.match(NAME_PATTERN, true)
+         unless md
+-          if @source.match(/\s*\S/um)
++          if @source.match(/\S/um)
+             message = "#{base_error_message}: invalid name"
+           else
+             message = "#{base_error_message}: name is missing"
+           end
+           raise REXML::ParseException.new(message, @source)
+         end
+-        md[1]
++        md[0]
+       end
+ 
+       def parse_id(base_error_message,
+@@ -655,18 +654,24 @@ module REXML
+         end
+       end
+ 
+-      def process_instruction(start_position)
+-        match_data = @source.match(Private::INSTRUCTION_END, true)
+-        unless match_data
+-          message = "Invalid processing instruction node"
+-          @source.position = start_position
+-          raise REXML::ParseException.new(message, @source)
++      def process_instruction
++        name = parse_name("Malformed XML: Invalid processing instruction node")
++        if @source.match(/\s+/um, true)
++          match_data = @source.match(/(.*?)\?>/um, true)
++          unless match_data
++            raise ParseException.new("Malformed XML: Unclosed processing instruction", @source)
++          end
++          content = match_data[1]
++        else
++          content = nil
++          unless @source.match("?>", true)
++            raise ParseException.new("Malformed XML: Unclosed processing instruction", @source)
++          end
+         end
+-        if match_data[1] == "xml"
++        if name == "xml"
+           if @document_status
+             raise ParseException.new("Malformed XML: XML declaration is not at the start", @source)
+           end
+-          content = match_data[2]
+           version = VERSION.match(content)
+           version = version[1] unless version.nil?
+           encoding = ENCODING.match(content)
+@@ -681,7 +686,7 @@ module REXML
+           standalone = standalone[1] unless standalone.nil?
+           return [ :xmldecl, version, encoding, standalone ]
+         end
+-        [:processing_instruction, match_data[1], match_data[2]]
++        [:processing_instruction, name, content]
+       end
+ 
+       def parse_attributes(prefixes)
+-- 
+2.40.0
+
diff --git a/meta/recipes-devtools/ruby/ruby_3.1.3.bb b/meta/recipes-devtools/ruby/ruby_3.1.3.bb
index f967cc6948..f2f9c848f0 100644
--- a/meta/recipes-devtools/ruby/ruby_3.1.3.bb
+++ b/meta/recipes-devtools/ruby/ruby_3.1.3.bb
@@ -66,6 +66,11 @@  SRC_URI = "http://cache.ruby-lang.org/pub/ruby/${SHRT_VER}/ruby-${PV}.tar.gz \
            file://CVE-2024-39908-0010.patch \
            file://CVE-2024-39908-0011.patch \
            file://CVE-2024-39908-0012.patch \
+           file://CVE-2024-41123-0001.patch \
+           file://CVE-2024-41123-0002.patch \
+           file://CVE-2024-41123-0003.patch \
+           file://CVE-2024-41123-0004.patch \
+           file://CVE-2024-41123-0005.patch \
            "
 UPSTREAM_CHECK_URI = "https://www.ruby-lang.org/en/downloads/"