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!( /&amp;/, '&' )
+      elsif ref == '&amp;'
+        '&'
+      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
openSUSE Build Service is sponsored by