mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
enforce a depth limit on XML documents
XML documents that are too deep can cause an stack overflow, which in turn will cause a potential DoS attack. CVE-2015-3227
This commit is contained in:
parent
193b76cbf0
commit
9b635292db
3 changed files with 15 additions and 10 deletions
|
@ -78,6 +78,9 @@ module ActiveSupport
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_accessor :depth
|
||||||
|
self.depth = 100
|
||||||
|
|
||||||
delegate :parse, :to => :backend
|
delegate :parse, :to => :backend
|
||||||
|
|
||||||
def backend
|
def backend
|
||||||
|
|
|
@ -46,7 +46,7 @@ module ActiveSupport
|
||||||
xml_string_reader = StringReader.new(data)
|
xml_string_reader = StringReader.new(data)
|
||||||
xml_input_source = InputSource.new(xml_string_reader)
|
xml_input_source = InputSource.new(xml_string_reader)
|
||||||
doc = @dbf.new_document_builder.parse(xml_input_source)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,9 +58,10 @@ module ActiveSupport
|
||||||
# Hash to merge the converted element into.
|
# Hash to merge the converted element into.
|
||||||
# element::
|
# element::
|
||||||
# XML element to merge into hash
|
# 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)
|
delete_empty(hash)
|
||||||
merge!(hash, element.tag_name, collapse(element))
|
merge!(hash, element.tag_name, collapse(element, depth))
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_empty(hash)
|
def delete_empty(hash)
|
||||||
|
@ -71,14 +72,14 @@ module ActiveSupport
|
||||||
#
|
#
|
||||||
# element::
|
# element::
|
||||||
# The document element to be collapsed.
|
# The document element to be collapsed.
|
||||||
def collapse(element)
|
def collapse(element, depth)
|
||||||
hash = get_attributes(element)
|
hash = get_attributes(element)
|
||||||
|
|
||||||
child_nodes = element.child_nodes
|
child_nodes = element.child_nodes
|
||||||
if child_nodes.length > 0
|
if child_nodes.length > 0
|
||||||
(0...child_nodes.length).each do |i|
|
(0...child_nodes.length).each do |i|
|
||||||
child = child_nodes.item(i)
|
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
|
end
|
||||||
merge_texts!(hash, element) unless empty_content?(element)
|
merge_texts!(hash, element) unless empty_content?(element)
|
||||||
hash
|
hash
|
||||||
|
|
|
@ -29,7 +29,7 @@ module ActiveSupport
|
||||||
doc = REXML::Document.new(data)
|
doc = REXML::Document.new(data)
|
||||||
|
|
||||||
if doc.root
|
if doc.root
|
||||||
merge_element!({}, doc.root)
|
merge_element!({}, doc.root, XmlMini.depth)
|
||||||
else
|
else
|
||||||
raise REXML::ParseException,
|
raise REXML::ParseException,
|
||||||
"The document #{doc.to_s.inspect} does not have a valid root"
|
"The document #{doc.to_s.inspect} does not have a valid root"
|
||||||
|
@ -44,19 +44,20 @@ module ActiveSupport
|
||||||
# Hash to merge the converted element into.
|
# Hash to merge the converted element into.
|
||||||
# element::
|
# element::
|
||||||
# XML element to merge into hash
|
# XML element to merge into hash
|
||||||
def merge_element!(hash, element)
|
def merge_element!(hash, element, depth)
|
||||||
merge!(hash, element.name, collapse(element))
|
raise REXML::ParseException, "The document is too deep" if depth == 0
|
||||||
|
merge!(hash, element.name, collapse(element, depth))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Actually converts an XML document element into a data structure.
|
# Actually converts an XML document element into a data structure.
|
||||||
#
|
#
|
||||||
# element::
|
# element::
|
||||||
# The document element to be collapsed.
|
# The document element to be collapsed.
|
||||||
def collapse(element)
|
def collapse(element, depth)
|
||||||
hash = get_attributes(element)
|
hash = get_attributes(element)
|
||||||
|
|
||||||
if element.has_elements?
|
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)
|
merge_texts!(hash, element) unless empty_content?(element)
|
||||||
hash
|
hash
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue