From 0b0a0bd083e6a758c8ccbc07c9392564b18253d5 Mon Sep 17 00:00:00 2001 From: Tim Lucas Date: Thu, 29 Sep 2011 01:30:15 +0200 Subject: [PATCH 1/2] Regression test for DoS attack on form/cookie param decoding See http://redmine.ruby-lang.org/issues/5149 --- test/spec_utils.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/spec_utils.rb b/test/spec_utils.rb index 82a4c7b5c..0e8935f46 100644 --- a/test/spec_utils.rb +++ b/test/spec_utils.rb @@ -58,6 +58,16 @@ def kcodeu Rack::Utils.escape("ΓΈ".encode("ISO-8859-1")).should.equal "%F8" end end + + should "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do + lambda { + timeout(1) do + lambda { + URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %" + }.should.raise(ArgumentError) + end + }.should.not.raise(Timeout::Error) + end should "escape path spaces with %20" do Rack::Utils.escape_path("foo bar").should.equal "foo%20bar" From 0c3255d05683a0d1abf92b408ea2e0a52f50ff4a Mon Sep 17 00:00:00 2001 From: Tim Lucas Date: Thu, 29 Sep 2011 01:50:10 +0200 Subject: [PATCH 2/2] Added backport of Ruby URI's 1.9.3 DoS fix --- .../backports/uri/{common.rb => common_18.rb} | 0 lib/rack/backports/uri/common_192.rb | 54 +++++++++++++++++++ lib/rack/utils.rb | 7 +-- 3 files changed, 58 insertions(+), 3 deletions(-) rename lib/rack/backports/uri/{common.rb => common_18.rb} (100%) create mode 100644 lib/rack/backports/uri/common_192.rb diff --git a/lib/rack/backports/uri/common.rb b/lib/rack/backports/uri/common_18.rb similarity index 100% rename from lib/rack/backports/uri/common.rb rename to lib/rack/backports/uri/common_18.rb diff --git a/lib/rack/backports/uri/common_192.rb b/lib/rack/backports/uri/common_192.rb new file mode 100644 index 000000000..beb148a61 --- /dev/null +++ b/lib/rack/backports/uri/common_192.rb @@ -0,0 +1,54 @@ +# :stopdoc: + +# Stolen from ruby core's uri/common.rb @32618ba to fix DoS issues in 1.9.2 +# +# https://github.com/ruby/ruby/blob/32618ba7438a2247042bba9b5d85b5d49070f5e5/lib/uri/common.rb +# +# Issue: +# http://redmine.ruby-lang.org/issues/5149 +# +# Relevant Fixes: +# https://github.com/ruby/ruby/commit/b5f91deee04aa6ccbe07c23c8222b937c22a799b +# https://github.com/ruby/ruby/commit/93177c1e5c3906abf14472ae0b905d8b5c72ce1b +# +# This should probably be removed once there is a Ruby 1.9.2 patch level that +# includes this fix. + +require 'uri/common' + +module URI + def self.decode_www_form(str, enc=Encoding::UTF_8) + return [] if str.empty? + unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str + raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})" + end + ary = [] + $&.scan(/([^=;&]+)=([^;&]*)/) do + ary << [decode_www_form_component($1, enc), decode_www_form_component($2, enc)] + end + ary + end + + def self.decode_www_form_component(str, enc=Encoding::UTF_8) + if TBLDECWWWCOMP_.empty? + tbl = {} + 256.times do |i| + h, l = i>>4, i&15 + tbl['%%%X%X' % [h, l]] = i.chr + tbl['%%%x%X' % [h, l]] = i.chr + tbl['%%%X%x' % [h, l]] = i.chr + tbl['%%%x%x' % [h, l]] = i.chr + end + tbl['+'] = ' ' + begin + TBLDECWWWCOMP_.replace(tbl) + TBLDECWWWCOMP_.freeze + rescue + end + end + raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str + str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc) + end + + WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc: +end diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 795e9dc9f..450b41ca4 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -6,9 +6,10 @@ major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i } -if (major == 1 && minor < 9) || (major == 1 && minor == 9 && patch < 2) - # pull in backports - require 'rack/backports/uri/common' +if major == 1 && minor < 9 + require 'rack/backports/uri/common_18' +elsif major == 1 && minor == 9 && patch < 3 + require 'rack/backports/uri/common_192' else require 'uri/common' end