Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Tue, 16 Jun 2015 11:03:35 -0700
From: Aaron Patterson <tenderlove@...y-lang.org>
To: security@...e.de, rubyonrails-security@...glegroups.com,
	oss-security@...ts.openwall.com, ruby-security-ann@...glegroups.com
Subject: [CVE-2015-3225] Potential Denial of Service Vulnerability in Rack

Potential Denial of Service Vulnerability in Rack

There is a potential denial of service vulnerability in Rack. This
vulnerability has been assigned the CVE identifier CVE-2015-3225.

Versions Affected:  All.
Not affected:       None.
Fixed Versions:     1.6.2, 1.5.4

Impact 
------ 
Carefully crafted requests can cause a `SystemStackError` and potentially
cause a denial of service attack.

All users running an affected release should either upgrade or use one of the workarounds immediately. 

Releases 
-------- 
The FIXED releases are available at the normal locations. 

Workarounds 
----------- 
There are no feasible workarounds for this issue. 


Patches 
------- 
To aid users who aren't able to upgrade immediately we have provided patches for the two supported release series.  They are in git-am format and consist of a single changeset. 

* 1-6-deep_params.patch - Patch for 1.6 series 
* 1-5-deep_params.patch - Patch for 1.5 series 

Please note that only the 1.6.x and 1.5.x series are supported at present.  Users of earlier unsupported releases are advised to upgrade as soon as possible as we cannot guarantee the continued availability of security fixes for unsupported releases.

Credits 
------- 

Special thanks to Tomek Rabczak from the NCC Group for reporting this!

-- 
Aaron Patterson
http://tenderlovemaking.com/

From fa15479e232663b2b5b048155b8e74228ab75d7e Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@...il.com>
Date: Tue, 20 Jan 2015 14:30:13 -0800
Subject: [PATCH] raise an exception if the parameters are too deep

CVE-2015-3225

Conflicts:
	lib/rack/utils.rb
	test/spec_utils.rb
---
 lib/rack/utils.rb  | 15 +++++++++++----
 test/spec_utils.rb | 12 ++++++++++++
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index 561e46e..a163c49 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -52,12 +52,17 @@ module Rack
 
     class << self
       attr_accessor :key_space_limit
+      attr_accessor :param_depth_limit
     end
 
     # The default number of bytes to allow parameter keys to take up.
     # This helps prevent a rogue client from flooding a Request.
     self.key_space_limit = 65536
 
+    # Default depth at which the parameter parser will raise an exception for
+    # being too deep.  This helps prevent SystemStackErrors
+    self.param_depth_limit = 100
+
     # Stolen from Mongrel, with some small modifications:
     # Parses a query string by breaking it up at the '&'
     # and ';' characters.  You can also use this to parse
@@ -100,7 +105,9 @@ module Rack
     end
     module_function :parse_nested_query
 
-    def normalize_params(params, name, v = nil)
+    def normalize_params(params, name, v = nil, depth = Utils.param_depth_limit)
+      raise RangeError if depth <= 0
+
       name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
       k = $1 || ''
       after = $' || ''
@@ -118,14 +125,14 @@ module Rack
         params[k] ||= []
         raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
         if params_hash_type?(params[k].last) && !params[k].last.key?(child_key)
-          normalize_params(params[k].last, child_key, v)
+          normalize_params(params[k].last, child_key, v, depth - 1)
         else
-          params[k] << normalize_params(params.class.new, child_key, v)
+          params[k] << normalize_params(params.class.new, child_key, v, depth - 1)
         end
       else
         params[k] ||= params.class.new
         raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
-        params[k] = normalize_params(params[k], after, v)
+        params[k] = normalize_params(params[k], after, v, depth - 1)
       end
 
       return params
diff --git a/test/spec_utils.rb b/test/spec_utils.rb
index 622b8ff..c1a2207 100644
--- a/test/spec_utils.rb
+++ b/test/spec_utils.rb
@@ -123,6 +123,18 @@ describe Rack::Utils do
     Rack::Utils.parse_query(",foo=bar;,", ";,").should.equal "foo" => "bar"
   end
 
+  should "raise an exception if the params are too deep" do
+    len = Rack::Utils.param_depth_limit
+
+    lambda {
+      Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
+    }.should.raise(RangeError)
+
+    lambda {
+      Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
+    }.should.not.raise
+  end
+
   should "parse nested query strings correctly" do
     Rack::Utils.parse_nested_query("foo").
       should.equal "foo" => nil
-- 
2.2.1


From bbac5d0d8b6a20487070dc6a298fbb8d9906a538 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@...il.com>
Date: Tue, 9 Jun 2015 17:07:31 -0700
Subject: [PATCH] raise an exception if the parameters are too deep

CVE-2015-3225
---
 lib/rack/utils.rb  | 15 +++++++++++----
 test/spec_utils.rb | 12 ++++++++++++
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index eea8c87..3b6f69f 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -61,6 +61,7 @@ module Rack
 
     class << self
       attr_accessor :key_space_limit
+      attr_accessor :param_depth_limit
       attr_accessor :multipart_part_limit
     end
 
@@ -68,6 +69,10 @@ module Rack
     # This helps prevent a rogue client from flooding a Request.
     self.key_space_limit = 65536
 
+    # Default depth at which the parameter parser will raise an exception for
+    # being too deep.  This helps prevent SystemStackErrors
+    self.param_depth_limit = 100
+
     # The maximum number of parts a request can contain. Accepting too many part
     # can lead to the server running out of file handles.
     # Set to `0` for no limit.
@@ -126,7 +131,9 @@ module Rack
     # normalize_params recursively expands parameters into structural types. If
     # the structural types represented by two different parameter names are in
     # conflict, a ParameterTypeError is raised.
-    def normalize_params(params, name, v = nil)
+    def normalize_params(params, name, v = nil, depth = Utils.param_depth_limit)
+      raise RangeError if depth <= 0
+
       name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
       k = $1 || ''
       after = $' || ''
@@ -146,14 +153,14 @@ module Rack
         params[k] ||= []
         raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
         if params_hash_type?(params[k].last) && !params[k].last.key?(child_key)
-          normalize_params(params[k].last, child_key, v)
+          normalize_params(params[k].last, child_key, v, depth - 1)
         else
-          params[k] << normalize_params(params.class.new, child_key, v)
+          params[k] << normalize_params(params.class.new, child_key, v, depth - 1)
         end
       else
         params[k] ||= params.class.new
         raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
-        params[k] = normalize_params(params[k], after, v)
+        params[k] = normalize_params(params[k], after, v, depth - 1)
       end
 
       return params
diff --git a/test/spec_utils.rb b/test/spec_utils.rb
index 06ed563..c2d479f 100644
--- a/test/spec_utils.rb
+++ b/test/spec_utils.rb
@@ -134,6 +134,18 @@ describe Rack::Utils do
     }.should.not.raise
   end
 
+  should "raise an exception if the params are too deep" do
+    len = Rack::Utils.param_depth_limit
+
+    lambda {
+      Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
+    }.should.raise(RangeError)
+
+    lambda {
+      Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
+    }.should.not.raise
+  end
+
   should "parse nested query strings correctly" do
     Rack::Utils.parse_nested_query("foo").
       should.equal "foo" => nil
-- 
2.2.1



[ CONTENT OF TYPE application/pgp-signature SKIPPED ]

Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Powered by Openwall GNU/*/Linux - Powered by OpenVZ