From 007349fd6b64d42ac7b9b8b1df6208aee859cf32 Mon Sep 17 00:00:00 2001 From: zhangxianting Date: Fri, 9 Aug 2024 11:28:45 +0800 Subject: [PATCH] fix CVE-2024-41946 --- backport-CVE-2024-41946.patch | 407 ++++++++++++++++++++++++++++++++++ ruby.spec | 6 +- 2 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2024-41946.patch diff --git a/backport-CVE-2024-41946.patch b/backport-CVE-2024-41946.patch new file mode 100644 index 0000000..ff3a363 --- /dev/null +++ b/backport-CVE-2024-41946.patch @@ -0,0 +1,407 @@ +From 033d1909a8f259d5a7c53681bcaf14f13bcf0368 Mon Sep 17 00:00:00 2001 +From: NAITOH Jun +Date: Thu, 1 Aug 2024 09:20:31 +0900 +Subject: [PATCH] Add support for XML entity expansion limitation in SAX and + pull parsers (#187) +https://github.com/ruby/rexml/commit/033d1909a8f259d5a7c53681bcaf14f13bcf0368 + +- Supported `REXML::Security.entity_expansion_limit=` in SAX and pull parsers +- Supported `REXML::Security.entity_expansion_text_limit=` in SAX and pull parsers +--- + lib/rexml/parsers/baseparser.rb | 19 ++++++- + lib/rexml/parsers/pullparser.rb | 4 ++ + lib/rexml/parsers/sax2parser.rb | 4 ++ + test/rexml/test_document.rb | 25 +++++---- + test/rexml/test_pullparser.rb | 96 +++++++++++++++++++++++++++++++++ + test/rexml/test_sax.rb | 86 +++++++++++++++++++++++++++++ + 6 files changed, 222 insertions(+), 12 deletions(-) + +diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb +index 54014e5..c4ddee3 100644 +--- a/lib/rexml/parsers/baseparser.rb ++++ b/lib/rexml/parsers/baseparser.rb +@@ -154,6 +154,7 @@ module REXML + self.stream = source + @listeners = [] + @prefixes = Set.new ++ @entity_expansion_count = 0 + end + + def add_listener( listener ) +@@ -161,6 +162,7 @@ module REXML + end + + attr_reader :source ++ attr_reader :entity_expansion_count + + def stream=( source ) + @source = SourceFactory.create_from( source ) +@@ -513,7 +515,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 +@@ -552,12 +556,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 +@@ -570,6 +579,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/lib/rexml/parsers/pullparser.rb b/lib/rexml/parsers/pullparser.rb +index f8b232a..36b4595 100644 +--- a/lib/rexml/parsers/pullparser.rb ++++ b/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/lib/rexml/parsers/sax2parser.rb b/lib/rexml/parsers/sax2parser.rb +index 36f98c2..cec9d2f 100644 +--- a/lib/rexml/parsers/sax2parser.rb ++++ b/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 +diff --git a/test/rexml/test_document.rb b/test/rexml/test_document.rb +index 33cf400..0764631 100644 +--- a/test/rexml/test_document.rb ++++ b/test/rexml/test_document.rb +@@ -41,7 +41,7 @@ EOF + + class GeneralEntityTest < self + def test_have_value +- xml = < + +@@ -55,23 +55,24 @@ EOF + + &a; + +-EOF ++XML + + doc = REXML::Document.new(xml) +- assert_raise(RuntimeError) do ++ assert_raise(RuntimeError.new("entity expansion has grown too large")) do + doc.root.children.first.value + end ++ + REXML::Security.entity_expansion_limit = 100 + assert_equal(100, REXML::Security.entity_expansion_limit) + doc = REXML::Document.new(xml) +- assert_raise(RuntimeError) do ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do + doc.root.children.first.value + end + assert_equal(101, doc.entity_expansion_count) + end + + def test_empty_value +- xml = < + +@@ -85,23 +86,24 @@ EOF + + &a; + +-EOF ++XML + + doc = REXML::Document.new(xml) +- assert_raise(RuntimeError) do ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do + doc.root.children.first.value + end ++ + REXML::Security.entity_expansion_limit = 100 + assert_equal(100, REXML::Security.entity_expansion_limit) + doc = REXML::Document.new(xml) +- assert_raise(RuntimeError) do ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do + doc.root.children.first.value + end + assert_equal(101, doc.entity_expansion_count) + end + + def test_with_default_entity +- xml = < + +@@ -112,14 +114,15 @@ EOF + &a2; + < + +-EOF ++XML + + REXML::Security.entity_expansion_limit = 4 + doc = REXML::Document.new(xml) + assert_equal("\na\na a\n<\n", doc.root.children.first.value) ++ + REXML::Security.entity_expansion_limit = 3 + doc = REXML::Document.new(xml) +- assert_raise(RuntimeError) do ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do + doc.root.children.first.value + end + end +diff --git a/test/rexml/test_pullparser.rb b/test/rexml/test_pullparser.rb +index 096e8b7..55205af 100644 +--- a/test/rexml/test_pullparser.rb ++++ b/test/rexml/test_pullparser.rb +@@ -155,5 +155,101 @@ module REXMLTests + end + assert_equal( 0, names.length ) + end ++ ++ class EntityExpansionLimitTest < Test::Unit::TestCase ++ def setup ++ @default_entity_expansion_limit = REXML::Security.entity_expansion_limit ++ end ++ ++ def teardown ++ REXML::Security.entity_expansion_limit = @default_entity_expansion_limit ++ end ++ ++ class GeneralEntityTest < self ++ def test_have_value ++ source = <<-XML ++ ++ ++ ++ ++ ++ ++]> ++ ++&a; ++ ++ XML ++ ++ parser = REXML::Parsers::PullParser.new(source) ++ assert_raise(RuntimeError.new("entity expansion has grown too large")) do ++ while parser.has_next? ++ parser.pull ++ end ++ end ++ end ++ ++ def test_empty_value ++ source = <<-XML ++ ++ ++ ++ ++ ++ ++]> ++ ++&a; ++ ++ XML ++ ++ parser = REXML::Parsers::PullParser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ while parser.has_next? ++ parser.pull ++ end ++ end ++ ++ REXML::Security.entity_expansion_limit = 100 ++ parser = REXML::Parsers::PullParser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ while parser.has_next? ++ parser.pull ++ end ++ end ++ assert_equal(101, parser.entity_expansion_count) ++ end ++ ++ def test_with_default_entity ++ source = <<-XML ++ ++ ++ ++]> ++ ++&a; ++&a2; ++< ++ ++ XML ++ ++ REXML::Security.entity_expansion_limit = 4 ++ parser = REXML::Parsers::PullParser.new(source) ++ while parser.has_next? ++ parser.pull ++ end ++ ++ REXML::Security.entity_expansion_limit = 3 ++ parser = REXML::Parsers::PullParser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ while parser.has_next? ++ parser.pull ++ end ++ end ++ end ++ end ++ end + end + end +diff --git a/test/rexml/test_sax.rb b/test/rexml/test_sax.rb +index 5a3f5e4..5e3ad75 100644 +--- a/test/rexml/test_sax.rb ++++ b/test/rexml/test_sax.rb +@@ -99,6 +99,92 @@ module REXMLTests + end + end + ++ class EntityExpansionLimitTest < Test::Unit::TestCase ++ def setup ++ @default_entity_expansion_limit = REXML::Security.entity_expansion_limit ++ end ++ ++ def teardown ++ REXML::Security.entity_expansion_limit = @default_entity_expansion_limit ++ end ++ ++ class GeneralEntityTest < self ++ def test_have_value ++ source = <<-XML ++ ++ ++ ++ ++ ++ ++]> ++ ++&a; ++ ++ XML ++ ++ sax = REXML::Parsers::SAX2Parser.new(source) ++ assert_raise(RuntimeError.new("entity expansion has grown too large")) do ++ sax.parse ++ end ++ end ++ ++ def test_empty_value ++ source = <<-XML ++ ++ ++ ++ ++ ++ ++]> ++ ++&a; ++ ++ XML ++ ++ sax = REXML::Parsers::SAX2Parser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ sax.parse ++ end ++ ++ REXML::Security.entity_expansion_limit = 100 ++ sax = REXML::Parsers::SAX2Parser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ sax.parse ++ end ++ assert_equal(101, sax.entity_expansion_count) ++ end ++ ++ def test_with_default_entity ++ source = <<-XML ++ ++ ++ ++]> ++ ++&a; ++&a2; ++< ++ ++ XML ++ ++ REXML::Security.entity_expansion_limit = 4 ++ sax = REXML::Parsers::SAX2Parser.new(source) ++ sax.parse ++ ++ REXML::Security.entity_expansion_limit = 3 ++ sax = REXML::Parsers::SAX2Parser.new(source) ++ assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do ++ sax.parse ++ end ++ end ++ end ++ end ++ + # used by test_simple_doctype_listener + # submitted by Jeff Barczewski + class SimpleDoctypeListener +-- +2.20.1 + diff --git a/ruby.spec b/ruby.spec index d8aaa3a..3a2b2f9 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ Name: ruby Version: 2.5.8 -Release: 126 +Release: 127 Summary: Object-oriented scripting language interpreter License: (Ruby or BSD) and Public Domain and MIT and CC0 and zlib and UCD URL: https://www.ruby-lang.org/ @@ -69,6 +69,7 @@ Patch6025: backport-0004-CVE-2024-35221.patch Patch6026: backport-0005-CVE-2024-35221.patch Patch6027: upgrade-lib-rexml-to-3.3.1.patch Patch6028: upgrade-lib-rexml-test-to-3.3.1.patch +Patch6029: backport-CVE-2024-41946.patch Patch9000: add-require_relative-helper-to-uninitialized-constan.patch @@ -608,6 +609,9 @@ make runruby TESTRUN_SCRIPT=%{SOURCE13} %exclude %{gem_dir}/gems/xmlrpc-0.3.0/.* %changelog +* Fri Aug 09 2024 zhangxianting - 2.5.8-127 +- fix CVE-2024-41946 + * Tue Jul 02 2024 shixuantong - 2.5.8-126 - upgrade rexml version to fix CVE-2024-35176