File CVE-2013-1821.patch of Package ruby.SLE_11
Description: Fix entity expansion DoS vulnerability in REXML
CVE-2013-1821
Origin: upstream, http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=39384&view=patch
Bug-Debian: http://bugs.debian.org/702526
Forwarded: not-needed
Author: Salvatore Bonaccorso <carnil@debian.org>
Last-Update: 2013-03-09
--- a/lib/rexml/document.rb
+++ b/lib/rexml/document.rb
@@ -214,6 +214,18 @@
return @@entity_expansion_limit
end
+ @@entity_expansion_text_limit = 10_240
+
+ # Set the entity expansion limit. By default the limit is set to 10240.
+ def Document::entity_expansion_text_limit=( val )
+ @@entity_expansion_text_limit = val
+ end
+
+ # Get the entity expansion limit. By default the limit is set to 10000.
+ def Document::entity_expansion_text_limit
+ return @@entity_expansion_text_limit
+ end
+
attr_reader :entity_expansion_count
def record_entity_expansion
--- a/test/rexml/test_document.rb
+++ b/test/rexml/test_document.rb
@@ -63,4 +63,23 @@
ensure
REXML::Document.entity_expansion_limit = 10000
end
+
+ def test_entity_string_limit
+ template = '<!DOCTYPE bomb [ <!ENTITY a "^" > ]> <bomb>$</bomb>'
+ len = 5120 # 5k per entity
+ template.sub!(/\^/, "B" * len)
+
+ # 10k is OK
+ entities = '&a;' * 2 # 5k entity * 2 = 10k
+ xmldoc = REXML::Document.new(template.sub(/\$/, entities))
+ assert_equal(len * 2, xmldoc.root.text.bytesize)
+
+ # above 10k explodes
+ entities = '&a;' * 3 # 5k entity * 2 = 15k
+ xmldoc = REXML::Document.new(template.sub(/\$/, entities))
+ assert_raises(RuntimeError) do
+ xmldoc.root.text
+ end
+ end
+
end
--- a/lib/rexml/text.rb
+++ b/lib/rexml/text.rb
@@ -308,37 +308,35 @@
# Unescapes all possible entities
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil )
- rv = string.clone
- rv.gsub!( /\r\n?/, "\n" )
- matches = rv.scan( REFERENCE )
- return rv if matches.size == 0
- rv.gsub!( NUMERICENTITY ) {|m|
- m=$1
- m = "0#{m}" if m[0] == ?x
- [Integer(m)].pack('U*')
+ sum = 0
+ string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
+ s = Text.expand($&, doctype, filter)
+ if sum + s.bytesize > Document.entity_expansion_text_limit
+ raise "entity expansion has grown too large"
+ else
+ sum += s.bytesize
+ end
+ s
}
- matches.collect!{|x|x[0]}.compact!
- if matches.size > 0
- if doctype
- matches.each do |entity_reference|
- unless filter and filter.include?(entity_reference)
- entity_value = doctype.entity( entity_reference )
- re = /&#{entity_reference};/
- rv.gsub!( re, entity_value ) if entity_value
- end
- end
+ end
+
+ def Text.expand(ref, doctype, filter)
+ if ref[1] == ?#
+ if ref[2] == ?x
+ [ref[3...-1].to_i(16)].pack('U*')
else
- matches.each do |entity_reference|
- unless filter and filter.include?(entity_reference)
- entity_value = DocType::DEFAULT_ENTITIES[ entity_reference ]
- re = /&#{entity_reference};/
- rv.gsub!( re, entity_value.value ) if entity_value
- end
- end
+ [ref[2...-1].to_i].pack('U*')
end
- rv.gsub!( /&/, '&' )
+ elsif ref == '&'
+ '&'
+ elsif filter and filter.include?( ref[1...-1] )
+ ref
+ elsif doctype
+ doctype.entity( ref[1...-1] ) or ref
+ else
+ entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
+ entity_value ? entity_value.value : ref
end
- rv
end
end
end