From 033d1909a8f259d5a7c53681bcaf14f13bcf0368 Mon Sep 17 00:00:00 2001
From: NAITOH Jun <naitoh@gmail.com>
Date: Thu, 1 Aug 2024 09:20:31 +0900
Subject: [PATCH] Add support for XML entity expansion limitation in SAX and 
 pull parsers (#187)

- Supported `REXML::Security.entity_expansion_limit=` in SAX and pull parsers
- Supported `REXML::Security.entity_expansion_text_limit=` in SAX and pull parsers

CVE: CVE-2024-41946

Upstream-Status: Backport [https://github.com/ruby/rexml/commit/033d1909a8f259d5a7c53681bcaf14f13bcf0368]

Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
---
 .../lib/rexml/parsers/baseparser.rb           | 19 ++++++++++++++++++-
 .../lib/rexml/parsers/pullparser.rb           |  4 ++++
 .../lib/rexml/parsers/sax2parser.rb           |  4 ++++
 3 files changed, 26 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 661f0e2..e32c7f4 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
@@ -135,6 +135,7 @@ module REXML
       def initialize( source )
         self.stream = source
         @listeners = []
+        @entity_expansion_count = 0
         @attributes_scanner = StringScanner.new('')
       end
 
@@ -143,6 +144,7 @@ module REXML
       end
 
       attr_reader :source
+      attr_reader :entity_expansion_count
 
       def stream=( source )
         @source = SourceFactory.create_from( source )
@@ -447,7 +449,9 @@ module REXML
       def entity( reference, entities )
         value = nil
         value = entities[ reference ] if entities
-        if not value
+        if value
+          record_entity_expansion
+        else
           value = DEFAULT_ENTITIES[ reference ]
           value = value[2] if value
         end
@@ -486,12 +490,17 @@ module REXML
         }
         matches.collect!{|x|x[0]}.compact!
         if matches.size > 0
+          sum = 0
           matches.each do |entity_reference|
             unless filter and filter.include?(entity_reference)
               entity_value = entity( entity_reference, entities )
               if entity_value
                 re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
                 rv.gsub!( re, entity_value )
+                sum += rv.bytesize
+                if sum > Security.entity_expansion_text_limit
+                  raise "entity expansion has grown too large"
+                end
               else
                 er = DEFAULT_ENTITIES[entity_reference]
                 rv.gsub!( er[0], er[2] ) if er
@@ -504,6 +513,14 @@ module REXML
       end
 
       private
+
+      def record_entity_expansion
+        @entity_expansion_count += 1
+        if @entity_expansion_count > Security.entity_expansion_limit
+          raise "number of entity expansions exceeded, processing aborted."
+        end
+      end
+
       def need_source_encoding_update?(xml_declaration_encoding)
         return false if xml_declaration_encoding.nil?
         return false if /\AUTF-16\z/i =~ xml_declaration_encoding
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb
index f8b232a..36b4595 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb
@@ -47,6 +47,10 @@ module REXML
         @listeners << listener
       end
 
+      def entity_expansion_count
+        @parser.entity_expansion_count
+      end
+
       def each
         while has_next?
           yield self.pull
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb
index 6a24ce2..01cb469 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb
@@ -22,6 +22,10 @@ module REXML
         @parser.source
       end
 
+      def entity_expansion_count
+        @parser.entity_expansion_count
+      end
+
       def add_listener( listener )
         @parser.add_listener( listener )
       end
-- 
2.40.0

