Skip to content

Commit

Permalink
raise an exception if the parameters are too deep
Browse files Browse the repository at this point in the history
CVE-2015-3225

Conflicts:
	lib/rack/utils.rb
	test/spec_utils.rb
  • Loading branch information
tenderlove committed Jun 16, 2015
1 parent 688516a commit 88b067e
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
15 changes: 11 additions & 4 deletions lib/rack/utils.rb
Expand Up @@ -51,12 +51,17 @@ def unescape(s, encoding = nil)

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
Expand Down Expand Up @@ -100,7 +105,9 @@ def parse_nested_query(qs, d = nil)
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 = $' || ''
Expand All @@ -118,14 +125,14 @@ def normalize_params(params, name, v = nil)
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
Expand Down
12 changes: 12 additions & 0 deletions test/spec_utils.rb
Expand Up @@ -123,6 +123,18 @@ def kcodeu
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
Expand Down

0 comments on commit 88b067e

Please sign in to comment.