On Fri, 29 Nov 2013, Thijs Kinkhorst wrote:
> > PS: I didn't took care of oldstable. Someone should handle that.
> 
> Obviously we prefer to release updates for all suites at the same time.
> Are the versions in squeeze so much different that it would be a lot of
> work to also apply the patches there?

Probably not, in fact Moritz already provided a patch for ruby1.8/squeeze.
I just took care to prepare the corresponding updates too (see debdiff
attached for 1.8.7.302-2squeeze2 and 1.9.2.0-2+deb6u2). Again they do
build but they are untested. Dear maintainers, please test and upload.

Cheers,
-- 
Raphaël Hertzog ◈ Debian Developer

Discover the Debian Administrator's Handbook:
→ http://debian-handbook.info/get/
diff --git a/debian/changelog b/debian/changelog
index a001b23..7d20446 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+ruby1.8 (1.8.7.302-2squeeze2) stable-security; urgency=high
+
+  * Add multiple patches to fix security issues:
+    - CVE-2013-4164: Fix heap overflow in floating point parsing
+      (Closes: #730189)
+    - CVE-2013-1821: Fix entity expansion DoS vulnerability in REXML
+      (Closes: #702526)
+    - CVE-2013-4073: Fix incorrect ssl hostname verification (Closes: #714541)
+    Thanks to Moritz Muehlenhoff for the patches.
+
+ -- Raphaël Hertzog <hert...@debian.org>  Fri, 29 Nov 2013 13:51:39 +0100
+
 ruby1.8 (1.8.7.302-2squeeze1) stable; urgency=low
 
   * Add Conflicts and Replaces to libruby1.8 for irb1.8 and rdoc1.8.
diff --git a/debian/patches/904-CVE-2013-4164.patch b/debian/patches/904-CVE-2013-4164.patch
new file mode 100644
index 0000000..071002c
--- /dev/null
+++ b/debian/patches/904-CVE-2013-4164.patch
@@ -0,0 +1,63 @@
+Description: Fix Heap Overflow in Floating Point Parsing
+ This vulnerability is tracked with CVE-2013-4164.
+ .
+ https://www.ruby-lang.org/en/news/2013/11/22/ruby-1-9-3-p484-is-released/
+Origin: backport, https://bugs.ruby-lang.org/projects/ruby-193/repository/revisions/43776/diff
+ https://bugs.ruby-lang.org/projects/ruby-193/repository/revisions/43782/diff
+Bug-Debian: http://bugs.debian.org/730189
+Forwarded: not-needed
+Applied-Upstream: 1.9.3-p484, 2.0.0-p353
+Last-Update: 2013-11-29
+
+diff -aur ruby1.8-1.8.7.302.orig//util.c ruby1.8-1.8.7.302/util.c
+--- ruby1.8-1.8.7.302.orig//util.c	2009-11-16 11:53:12.000000000 +0100
++++ ruby1.8-1.8.7.302/util.c	2013-11-25 13:22:29.977023805 +0100
+@@ -888,6 +888,11 @@
+ #else
+ #define MALLOC malloc
+ #endif
++#ifdef FREE
++extern void FREE(void*);
++#else
++#define FREE free
++#endif
+ 
+ #ifndef Omit_Private_Memory
+ #ifndef PRIVATE_MEM
+@@ -1172,7 +1177,7 @@
+ #endif
+ 
+     ACQUIRE_DTOA_LOCK(0);
+-    if ((rv = freelist[k]) != 0) {
++    if (k <= Kmax && (rv = freelist[k]) != 0) {
+         freelist[k] = rv->next;
+     }
+     else {
+@@ -1182,7 +1187,7 @@
+ #else
+         len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+                 /sizeof(double);
+-        if (pmem_next - private_mem + len <= PRIVATE_mem) {
++        if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+             rv = (Bigint*)pmem_next;
+             pmem_next += len;
+         }
+@@ -1201,6 +1206,10 @@
+ Bfree(Bigint *v)
+ {
+     if (v) {
++        if (v->k > Kmax) {
++            FREE(v);
++            return;
++        }
+         ACQUIRE_DTOA_LOCK(0);
+         v->next = freelist[v->k];
+         freelist[v->k] = v;
+@@ -2196,6 +2205,7 @@
+         for (; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+             nz++;
++            if (nf > DBL_DIG * 4) continue;
+             if (c -= '0') {
+                 nf += nz;
+                 for (i = 1; i < nz; i++)
diff --git a/debian/patches/905-CVE-2013-1821.patch b/debian/patches/905-CVE-2013-1821.patch
new file mode 100644
index 0000000..7d87556
--- /dev/null
+++ b/debian/patches/905-CVE-2013-1821.patch
@@ -0,0 +1,120 @@
+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 <car...@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
diff --git a/debian/patches/906-CVE-2013-4073.patch b/debian/patches/906-CVE-2013-4073.patch
new file mode 100644
index 0000000..871aab9
--- /dev/null
+++ b/debian/patches/906-CVE-2013-4073.patch
@@ -0,0 +1,79 @@
+Description: fix incorrect ssl hostname verification
+Origin: upstream, https://github.com/ruby/ruby/commit/961bf7496ded3acfe847cf56fa90bbdcfd6e614f
+Origin: backport, https://github.com/ruby/ruby/commit/a3a62f87e144be31b9ca8ad6415b207f43f4e126
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=714541
+Bug: https://bugs.ruby-lang.org/issues/8575
+
+Index: ruby1.8-1.8.7.352/ext/openssl/lib/openssl/ssl-internal.rb
+===================================================================
+--- ruby1.8-1.8.7.352.orig/ext/openssl/lib/openssl/ssl-internal.rb	2013-07-08 10:16:49.926709322 -0400
++++ ruby1.8-1.8.7.352/ext/openssl/lib/openssl/ssl-internal.rb	2013-07-08 10:16:49.918709322 -0400
+@@ -90,14 +90,22 @@
+       should_verify_common_name = true
+       cert.extensions.each{|ext|
+         next if ext.oid != "subjectAltName"
+-        ext.value.split(/,\s+/).each{|general_name|
+-          if /\ADNS:(.*)/ =~ general_name
++        ostr = OpenSSL::ASN1.decode(ext.to_der).value.last
++        sequence = OpenSSL::ASN1.decode(ostr.value)
++        sequence.value.each{|san|
++          case san.tag
++          when 2 # dNSName in GeneralName (RFC5280)
+             should_verify_common_name = false
+-            reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
++            reg = Regexp.escape(san.value).gsub(/\\\*/, "[^.]+")
+             return true if /\A#{reg}\z/i =~ hostname
+-          elsif /\AIP Address:(.*)/ =~ general_name
++          when 7 # iPAddress in GeneralName (RFC5280)
+             should_verify_common_name = false
+-            return true if $1 == hostname
++            # follows GENERAL_NAME_print() in x509v3/v3_alt.c
++            if san.value.size == 4
++              return true if san.value.unpack('C*').join('.') == hostname
++            elsif san.value.size == 16
++              return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
++            end
+           end
+         }
+       }
+Index: ruby1.8-1.8.7.352/test/openssl/test_ssl.rb
+===================================================================
+--- ruby1.8-1.8.7.352.orig/test/openssl/test_ssl.rb	2013-07-08 10:16:49.926709322 -0400
++++ ruby1.8-1.8.7.352/test/openssl/test_ssl.rb	2013-07-08 10:16:49.922709322 -0400
+@@ -532,6 +532,36 @@
+       end
+     end
+   end
++ 
++  def test_verify_certificate_identity
++    [true, false].each do |criticality|
++      cert = create_null_byte_SAN_certificate(criticality)
++      assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, 'www.example.com'))
++      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, 'www.example.com\0.evil.com'))
++      assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.255'))
++      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.1'))
++      assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '13::17'))
++      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '13:0:0:0:0:0:0:17'))
++    end
++  end
++
++  # Create NULL byte SAN certificate
++  def create_null_byte_SAN_certificate(critical = false)
++    ef = OpenSSL::X509::ExtensionFactory.new
++    cert = OpenSSL::X509::Certificate.new
++    cert.subject = OpenSSL::X509::Name.parse "/DC=some/DC=site/CN=Some Site"
++    ext = ef.create_ext('subjectAltName', 'DNS:placeholder,IP:192.168.7.1,IP:13::17', critical)
++    ext_asn1 = OpenSSL::ASN1.decode(ext.to_der)
++    san_list_der = ext_asn1.value.reduce(nil) { |memo,val| val.tag == 4 ? val.value : memo }
++    san_list_asn1 = OpenSSL::ASN1.decode(san_list_der)
++    san_list_asn1.value[0].value = 'www.example.com\0.evil.com'
++    pos = critical ? 2 : 1
++    ext_asn1.value[pos].value = san_list_asn1.to_der
++    real_ext = OpenSSL::X509::Extension.new ext_asn1
++    cert.add_extension(real_ext)
++    cert
++  end
++
+ end
+ 
+ end
diff --git a/debian/patches/series b/debian/patches/series
index 9dd9322..6c35224 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -10,3 +10,6 @@
 100730_disable_getsetcontext_on_nptl.patch
 100730_verbose-tests.patch
 100901_threading_fixes.patch
+904-CVE-2013-4164.patch
+905-CVE-2013-1821.patch
+906-CVE-2013-4073.patch
diff --git a/debian/changelog b/debian/changelog
index 8542e71..8313465 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+ruby1.9.1 (1.9.2.0-2+deb6u2) oldstable-security; urgency=high
+
+  * debian/patches/CVE-2013-4164.patch: add upstream patch to fix heap
+    overflow in floating point parsing. Closes: #730178
+
+ -- Raphaël Hertzog <b...@kali.org>  Fri, 29 Nov 2013 07:36:01 +0000
+
 ruby1.9.1 (1.9.2.0-2+deb6u1) oldstable-security; urgency=high
 
   * Team upload
diff --git a/debian/patches/CVE-2013-4164.patch b/debian/patches/CVE-2013-4164.patch
new file mode 100644
index 0000000..6bb222f
--- /dev/null
+++ b/debian/patches/CVE-2013-4164.patch
@@ -0,0 +1,80 @@
+Description: Fix Heap Overflow in Floating Point Parsing
+ This vulnerability is tracked with CVE-2013-4164.
+ .
+ https://www.ruby-lang.org/en/news/2013/11/22/ruby-1-9-3-p484-is-released/
+Origin: upstream, https://bugs.ruby-lang.org/projects/ruby-193/repository/revisions/43776/diff
+Bug-Debian: http://bugs.debian.org/730178
+Forwarded: not-needed
+Applied-Upstream: 1.9.3-p484, 2.0.0-p353
+Last-Update: 2013-11-29
+
+--- a/util.c
++++ b/util.c
+@@ -852,6 +852,11 @@ extern void *MALLOC(size_t);
+ #else
+ #define MALLOC malloc
+ #endif
++#ifdef FREE
++extern void FREE(void*);
++#else
++#define FREE free
++#endif
+ 
+ #ifndef Omit_Private_Memory
+ #ifndef PRIVATE_MEM
+@@ -1142,7 +1147,7 @@ Balloc(int k)
+ #endif
+ 
+     ACQUIRE_DTOA_LOCK(0);
+-    if ((rv = freelist[k]) != 0) {
++    if (k <= Kmax && (rv = freelist[k]) != 0) {
+         freelist[k] = rv->next;
+     }
+     else {
+@@ -1152,7 +1157,7 @@ Balloc(int k)
+ #else
+         len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+                 /sizeof(double);
+-        if (pmem_next - private_mem + len <= PRIVATE_mem) {
++        if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+             rv = (Bigint*)pmem_next;
+             pmem_next += len;
+         }
+@@ -1171,6 +1176,10 @@ static void
+ Bfree(Bigint *v)
+ {
+     if (v) {
++        if (v->k > Kmax) {
++            FREE(v);
++            return;
++        }
+         ACQUIRE_DTOA_LOCK(0);
+         v->next = freelist[v->k];
+         freelist[v->k] = v;
+@@ -2201,6 +2210,7 @@ break2:
+         for (; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+             nz++;
++            if (nf > DBL_DIG * 4) continue;
+             if (c -= '0') {
+                 nf += nz;
+                 for (i = 1; i < nz; i++)
+--- a/test/ruby/test_float.rb
++++ b/test/ruby/test_float.rb
+@@ -450,4 +450,16 @@ class TestFloat < Test::Unit::TestCase
+       sleep(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1)
+     end
+   end
++
++  def test_long_string
++    assert_normal_exit(<<-'end;')
++    assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9)
++    end;
++  end
++
++  def test_long_string
++    assert_normal_exit(<<-'end;')
++    assert_in_epsilon(10.0, ("1."+"1"*300000).to_f*9)
++    end;
++  end
+ end
diff --git a/debian/patches/series b/debian/patches/series
index d2ff813..8097101 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -27,3 +27,4 @@
 20100829-rubygems_default_dir.diff
 CVE-2013-1821.patch
 CVE-2013-4073.patch
+CVE-2013-4164.patch

Reply via email to