Skip to content

Commit

Permalink
enforce a depth limit on XML documents
Browse files Browse the repository at this point in the history
XML documents that are too deep can cause an stack overflow, which in
turn will cause a potential DoS attack.

CVE-2015-3227

Conflicts:
	activesupport/lib/active_support/xml_mini.rb
  • Loading branch information
tenderlove authored and rafaelfranca committed Jun 16, 2015
1 parent b344986 commit 153cc84
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 10 deletions.
3 changes: 3 additions & 0 deletions activesupport/lib/active_support/xml_mini.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def content_type
end

attr_reader :backend
attr_accessor :depth
self.depth = 100

delegate :parse, :to => :backend

def backend=(name)
Expand Down
11 changes: 6 additions & 5 deletions activesupport/lib/active_support/xml_mini/jdom.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def parse(data)
xml_string_reader = StringReader.new(data)
xml_input_source = InputSource.new(xml_string_reader)
doc = @dbf.new_document_builder.parse(xml_input_source)
merge_element!({CONTENT_KEY => ''}, doc.document_element)
merge_element!({CONTENT_KEY => ''}, doc.document_element, XmlMini.depth)
end
end

Expand All @@ -59,9 +59,10 @@ def parse(data)
# Hash to merge the converted element into.
# element::
# XML element to merge into hash
def merge_element!(hash, element)
def merge_element!(hash, element, depth)
raise 'Document too deep!' if depth == 0
delete_empty(hash)
merge!(hash, element.tag_name, collapse(element))
merge!(hash, element.tag_name, collapse(element, depth))
end

def delete_empty(hash)
Expand All @@ -72,14 +73,14 @@ def delete_empty(hash)
#
# element::
# The document element to be collapsed.
def collapse(element)
def collapse(element, depth)
hash = get_attributes(element)

child_nodes = element.child_nodes
if child_nodes.length > 0
for i in 0...child_nodes.length
child = child_nodes.item(i)
merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE
merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE
end
merge_texts!(hash, element) unless empty_content?(element)
hash
Expand Down
11 changes: 6 additions & 5 deletions activesupport/lib/active_support/xml_mini/rexml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def parse(data)
doc = REXML::Document.new(data)

if doc.root
merge_element!({}, doc.root)
merge_element!({}, doc.root, XmlMini.depth)
else
raise REXML::ParseException,
"The document #{doc.to_s.inspect} does not have a valid root"
Expand All @@ -45,19 +45,20 @@ def parse(data)
# Hash to merge the converted element into.
# element::
# XML element to merge into hash
def merge_element!(hash, element)
merge!(hash, element.name, collapse(element))
def merge_element!(hash, element, depth)
raise REXML::ParseException, "The document is too deep" if depth == 0
merge!(hash, element.name, collapse(element, depth))
end

# Actually converts an XML document element into a data structure.
#
# element::
# The document element to be collapsed.
def collapse(element)
def collapse(element, depth)
hash = get_attributes(element)

if element.has_elements?
element.each_element {|child| merge_element!(hash, child) }
element.each_element {|child| merge_element!(hash, child, depth - 1) }
merge_texts!(hash, element) unless empty_content?(element)
hash
else
Expand Down

0 comments on commit 153cc84

Please sign in to comment.