ruby/backport-CVE-2024-43398-upgrade-lib-rexml-to-3.3.6.patch
shixuantong e04b61b380 upgrade rexml to fix CVE-2024-39908 CVE-2024-41123 CVE-2024-43398
(cherry picked from commit b3848293a70017a11aebbd45e3f7db6be5dea235)
2024-08-29 14:47:41 +08:00

525 lines
19 KiB
Diff

From 95871f399eda642a022b03550479b7994895c742 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <kou@clear-code.com>
Date: Thu, 22 Aug 2024 09:54:49 +0900
Subject: [PATCH] Add 3.3.6 entry
---
.bundle/gems/rexml-3.2.5/lib/rexml/element.rb | 30 ++--
.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb | 52 +------
.../lib/rexml/parsers/baseparser.rb | 139 +++++++++++++-----
.../lib/rexml/parsers/streamparser.rb | 16 +-
.../lib/rexml/parsers/treeparser.rb | 7 -
.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb | 2 +-
6 files changed, 131 insertions(+), 115 deletions(-)
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
index a5808d7..4e3a60b 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/element.rb
@@ -441,9 +441,14 @@ module REXML
# Related: #root_node, #document.
#
def root
- return elements[1] if self.kind_of? Document
- return self if parent.kind_of? Document or parent.nil?
- return parent.root
+ target = self
+ while target
+ return target.elements[1] if target.kind_of? Document
+ parent = target.parent
+ return target if parent.kind_of? Document or parent.nil?
+ target = parent
+ end
+ nil
end
# :call-seq:
@@ -619,8 +624,12 @@ module REXML
else
prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
end
- ns = attributes[ prefix ]
- ns = parent.namespace(prefix) if ns.nil? and parent
+ ns = nil
+ target = self
+ while ns.nil? and target
+ ns = target.attributes[prefix]
+ target = target.parent
+ end
ns = '' if ns.nil? and prefix == 'xmlns'
return ns
end
@@ -2375,17 +2384,6 @@ module REXML
elsif old_attr.kind_of? Hash
old_attr[value.prefix] = value
elsif old_attr.prefix != value.prefix
- # Check for conflicting namespaces
- if value.prefix != "xmlns" and old_attr.prefix != "xmlns"
- old_namespace = old_attr.namespace
- new_namespace = value.namespace
- if old_namespace == new_namespace
- raise ParseException.new(
- "Namespace conflict in adding attribute \"#{value.name}\": "+
- "Prefix \"#{old_attr.prefix}\" = \"#{old_namespace}\" and "+
- "prefix \"#{value.prefix}\" = \"#{new_namespace}\"")
- end
- end
store value.name, {old_attr.prefix => old_attr,
value.prefix => value}
else
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
index 573db69..12bbad3 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/entity.rb
@@ -12,6 +12,7 @@ module REXML
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
NDATADECL = "\\s+NDATA\\s+#{NAME}"
PEREFERENCE = "%#{NAME};"
+ PEREFERENCE_RE = /#{PEREFERENCE}/um
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
@@ -19,7 +20,7 @@ module REXML
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
- attr_reader :name, :external, :ref, :ndata, :pubid
+ attr_reader :name, :external, :ref, :ndata, :pubid, :value
# Create a new entity. Simple entities can be constructed by passing a
# name, value to the constructor; this creates a generic, plain entity
@@ -68,14 +69,11 @@ module REXML
end
# Evaluates to the unnormalized value of this entity; that is, replacing
- # all entities -- both %ent; and &ent; entities. This differs from
- # +value()+ in that +value+ only replaces %ent; entities.
+ # &ent; entities.
def unnormalized
document.record_entity_expansion unless document.nil?
- v = value()
- return nil if v.nil?
- @unnormalized = Text::unnormalize(v, parent)
- @unnormalized
+ return nil if @value.nil?
+ @unnormalized = Text::unnormalize(@value, parent)
end
#once :unnormalized
@@ -121,46 +119,6 @@ module REXML
write rv
rv
end
-
- PEREFERENCE_RE = /#{PEREFERENCE}/um
- # Returns the value of this entity. At the moment, only internal entities
- # are processed. If the value contains internal references (IE,
- # %blah;), those are replaced with their values. IE, if the doctype
- # contains:
- # <!ENTITY % foo "bar">
- # <!ENTITY yada "nanoo %foo; nanoo>
- # then:
- # doctype.entity('yada').value #-> "nanoo bar nanoo"
- def value
- @resolved_value ||= resolve_value
- end
-
- def parent=(other)
- @resolved_value = nil
- super
- end
-
- private
- def resolve_value
- return nil if @value.nil?
- return @value unless @value.match?(PEREFERENCE_RE)
-
- matches = @value.scan(PEREFERENCE_RE)
- rv = @value.clone
- if @parent
- sum = 0
- matches.each do |entity_reference|
- entity_value = @parent.entity( entity_reference[0] )
- if sum + entity_value.bytesize > Security.entity_expansion_text_limit
- raise "entity expansion has grown too large"
- else
- sum += entity_value.bytesize
- end
- rv.gsub!( /%#{entity_reference.join};/um, entity_value )
- end
- end
- rv
- end
end
# This is a set of entity constants -- the ones defined in the XML
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 44dc658..d11c276 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
@@ -1,12 +1,29 @@
# frozen_string_literal: true
require_relative '../parseexception'
require_relative '../undefinednamespaceexception'
+require_relative '../security'
require_relative '../source'
require 'set'
require "strscan"
module REXML
module Parsers
+ unless [].respond_to?(:tally)
+ module EnumerableTally
+ refine Enumerable do
+ def tally
+ counts = {}
+ each do |item|
+ counts[item] ||= 0
+ counts[item] += 1
+ end
+ counts
+ end
+ end
+ end
+ using EnumerableTally
+ end
+
if StringScanner::Version < "3.0.8"
module StringScannerCaptures
refine StringScanner do
@@ -124,6 +141,7 @@ module REXML
}
module Private
+ PEREFERENCE_PATTERN = /#{PEREFERENCE}/um
TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
@@ -163,7 +181,8 @@ module REXML
@tags = []
@stack = []
@entities = []
- @nsstack = []
+ @namespaces = {}
+ @namespaces_restore_stack = []
end
def position
@@ -231,6 +250,10 @@ module REXML
if @document_status == :in_doctype
raise ParseException.new("Malformed DOCTYPE: unclosed", @source)
end
+ unless @tags.empty?
+ path = "/" + @tags.join("/")
+ raise ParseException.new("Missing end tag for '#{path}'", @source)
+ end
return [ :end_document ]
end
return @stack.shift if @stack.size > 0
@@ -263,7 +286,6 @@ module REXML
@source.position = start_position
raise REXML::ParseException.new(message, @source)
end
- @nsstack.unshift(Set.new)
name = parse_name(base_error_message)
if @source.match(/\s*\[/um, true)
id = [nil, nil, nil]
@@ -333,6 +355,8 @@ module REXML
match[4] = match[4][1..-2] # HREF
match.delete_at(5) if match.size > 5 # Chop out NDATA decl
# match is [ :entity, name, PUBLIC, pubid, href(, ndata)? ]
+ elsif Private::PEREFERENCE_PATTERN.match?(match[2])
+ raise REXML::ParseException.new("Parameter entity references forbidden in internal subset: #{match[2]}", @source)
else
match[2] = match[2][1..-2]
match.pop if match.size == 4
@@ -355,7 +379,7 @@ module REXML
val = attdef[4] if val == "#FIXED "
pairs[attdef[0]] = val
if attdef[0] =~ /^xmlns:(.*)/
- @nsstack[0] << $1
+ @namespaces[$1] = val
end
end
end
@@ -408,7 +432,7 @@ module REXML
# here explicitly.
@source.ensure_buffer
if @source.match("/", true)
- @nsstack.shift
+ @namespaces_restore_stack.pop
last_tag = @tags.pop
md = @source.match(Private::CLOSE_PATTERN, true)
if md and !last_tag
@@ -453,18 +477,18 @@ module REXML
@document_status = :in_element
@prefixes.clear
@prefixes << md[2] if md[2]
- @nsstack.unshift(curr_ns=Set.new)
- attributes, closed = parse_attributes(@prefixes, curr_ns)
+ push_namespaces_restore
+ attributes, closed = parse_attributes(@prefixes)
# Verify that all of the prefixes have been defined
for prefix in @prefixes
- unless @nsstack.find{|k| k.member?(prefix)}
+ unless @namespaces.key?(prefix)
raise UndefinedNamespaceException.new(prefix,@source,self)
end
end
if closed
@closed = tag
- @nsstack.shift
+ pop_namespaces_restore
else
if @tags.empty? and @have_root
raise ParseException.new("Malformed XML: Extra tag at the end of the document (got '<#{tag}')", @source)
@@ -504,15 +528,13 @@ module REXML
private :pull_event
def entity( reference, entities )
- value = nil
- value = entities[ reference ] if entities
- if value
- record_entity_expansion
- else
- value = DEFAULT_ENTITIES[ reference ]
- value = value[2] if value
- end
- unnormalize( value, entities ) if value
+ return unless entities
+
+ value = entities[ reference ]
+ return if value.nil?
+
+ record_entity_expansion
+ unnormalize( value, entities )
end
# Escapes all possible entities
@@ -546,22 +568,29 @@ module REXML
[Integer(m)].pack('U*')
}
matches.collect!{|x|x[0]}.compact!
+ if filter
+ matches.reject! do |entity_reference|
+ filter.include?(entity_reference)
+ end
+ end
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
+ matches.tally.each do |entity_reference, n|
+ entity_expansion_count_before = @entity_expansion_count
+ entity_value = entity( entity_reference, entities )
+ if entity_value
+ if n > 1
+ entity_expansion_count_delta =
+ @entity_expansion_count - entity_expansion_count_before
+ record_entity_expansion(entity_expansion_count_delta * (n - 1))
end
+ re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
+ rv.gsub!( re, entity_value )
+ if rv.bytesize > 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
end
end
rv.gsub!( Private::DEFAULT_ENTITIES_PATTERNS['amp'], '&' )
@@ -570,9 +599,34 @@ module REXML
end
private
+ def add_namespace(prefix, uri)
+ @namespaces_restore_stack.last[prefix] = @namespaces[prefix]
+ if uri.nil?
+ @namespaces.delete(prefix)
+ else
+ @namespaces[prefix] = uri
+ end
+ end
+
+ def push_namespaces_restore
+ namespaces_restore = {}
+ @namespaces_restore_stack.push(namespaces_restore)
+ namespaces_restore
+ end
- def record_entity_expansion
- @entity_expansion_count += 1
+ def pop_namespaces_restore
+ namespaces_restore = @namespaces_restore_stack.pop
+ namespaces_restore.each do |prefix, uri|
+ if uri.nil?
+ @namespaces.delete(prefix)
+ else
+ @namespaces[prefix] = uri
+ end
+ end
+ end
+
+ def record_entity_expansion(delta=1)
+ @entity_expansion_count += delta
if @entity_expansion_count > Security.entity_expansion_limit
raise "number of entity expansions exceeded, processing aborted."
end
@@ -698,8 +752,9 @@ module REXML
[:processing_instruction, name, content]
end
- def parse_attributes(prefixes, curr_ns)
+ def parse_attributes(prefixes)
attributes = {}
+ expanded_names = {}
closed = false
while true
if @source.match(">", true)
@@ -741,7 +796,7 @@ module REXML
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
raise REXML::ParseException.new( msg, @source, self)
end
- curr_ns << local_part
+ add_namespace(local_part, value)
elsif prefix
prefixes << prefix unless prefix == "xml"
end
@@ -751,6 +806,20 @@ module REXML
raise REXML::ParseException.new(msg, @source, self)
end
+ unless prefix == "xmlns"
+ uri = @namespaces[prefix]
+ expanded_name = [uri, local_part]
+ existing_prefix = expanded_names[expanded_name]
+ if existing_prefix
+ message = "Namespace conflict in adding attribute " +
+ "\"#{local_part}\": " +
+ "Prefix \"#{existing_prefix}\" = \"#{uri}\" and " +
+ "prefix \"#{prefix}\" = \"#{uri}\""
+ raise REXML::ParseException.new(message, @source, self)
+ end
+ expanded_names[expanded_name] = prefix
+ end
+
attributes[name] = value
else
message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>"
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb
index fa3ac49..7781fe4 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb
@@ -7,36 +7,33 @@ module REXML
def initialize source, listener
@listener = listener
@parser = BaseParser.new( source )
- @tag_stack = []
+ @entities = {}
end
def add_listener( listener )
@parser.add_listener( listener )
end
+ def entity_expansion_count
+ @parser.entity_expansion_count
+ end
+
def parse
# entity string
while true
event = @parser.pull
case event[0]
when :end_document
- unless @tag_stack.empty?
- tag_path = "/" + @tag_stack.join("/")
- raise ParseException.new("Missing end tag for '#{tag_path}'",
- @parser.source)
- end
return
when :start_element
- @tag_stack << event[1]
attrs = event[2].each do |n, v|
event[2][n] = @parser.unnormalize( v )
end
@listener.tag_start( event[1], attrs )
when :end_element
@listener.tag_end( event[1] )
- @tag_stack.pop
when :text
- unnormalized = @parser.unnormalize( event[1] )
+ unnormalized = @parser.unnormalize( event[1], @entities )
@listener.text( unnormalized )
when :processing_instruction
@listener.instruction( *event[1,2] )
@@ -48,6 +45,7 @@ module REXML
when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
@listener.send( event[0].to_s, *event[1..-1] )
when :entitydecl, :notationdecl
+ @entities[ event[1] ] = event[2] if event.size == 3
@listener.send( event[0].to_s, event[1..-1] )
when :externalentity
entity_reference = event[1]
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
index 0cb6f7c..4565a40 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb
@@ -15,7 +15,6 @@ module REXML
end
def parse
- tag_stack = []
entities = nil
begin
while true
@@ -23,19 +22,13 @@ module REXML
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
case event[0]
when :end_document
- unless tag_stack.empty?
- raise ParseException.new("No close tag for #{@build_context.xpath}",
- @parser.source, @parser)
- end
return
when :start_element
- tag_stack.push(event[1])
el = @build_context = @build_context.add_element( event[1] )
event[2].each do |key, value|
el.attributes[key]=Attribute.new(key,value,self)
end
when :end_element
- tag_stack.pop
@build_context = @build_context.parent
when :text
if @build_context[-1].instance_of? Text
diff --git a/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb b/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
index 39e92a5..99d574b 100644
--- a/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
+++ b/.bundle/gems/rexml-3.2.5/lib/rexml/rexml.rb
@@ -31,7 +31,7 @@
module REXML
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
DATE = "2008/019"
- VERSION = "3.3.3"
+ VERSION = "3.3.6"
REVISION = ""
Copyright = COPYRIGHT
--
2.27.0