Skip to content

Commit

Permalink
add #entity_expansion_limit=, #entity_expansion_text_limit=
Browse files Browse the repository at this point in the history
## Why?
See: ruby#192
  • Loading branch information
naitoh committed Aug 22, 2024
1 parent 1c694d1 commit f62ec5c
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 72 deletions.
7 changes: 6 additions & 1 deletion lib/rexml/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class Document < Element
#
def initialize( source = nil, context = {} )
@entity_expansion_count = 0
@entity_expansion_limit = Security.entity_expansion_limit
super()
@context = context
return if source.nil?
Expand Down Expand Up @@ -434,11 +435,15 @@ def Document::entity_expansion_text_limit

def record_entity_expansion
@entity_expansion_count += 1
if @entity_expansion_count > Security.entity_expansion_limit
if @entity_expansion_count > @entity_expansion_limit
raise "number of entity expansions exceeded, processing aborted."
end
end

def entity_expansion_limit=( limit )
@entity_expansion_limit = limit
end

def document
self
end
Expand Down
15 changes: 13 additions & 2 deletions lib/rexml/parsers/baseparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ def initialize( source )
@listeners = []
@prefixes = Set.new
@entity_expansion_count = 0
@entity_expansion_limit = Security.entity_expansion_limit
@entity_expansion_text_limit = Security.entity_expansion_text_limit
end

def add_listener( listener )
Expand Down Expand Up @@ -585,7 +587,7 @@ def unnormalize( string, entities=nil, filter=nil )
end
re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
rv.gsub!( re, entity_value )
if rv.bytesize > Security.entity_expansion_text_limit
if rv.bytesize > @entity_expansion_text_limit
raise "entity expansion has grown too large"
end
else
Expand All @@ -598,6 +600,15 @@ def unnormalize( string, entities=nil, filter=nil )
rv
end

def entity_expansion_limit=( limit )
@entity_expansion_limit = limit
end


def entity_expansion_text_limit=( limit )
@entity_expansion_text_limit = limit
end

private
def add_namespace(prefix, uri)
@namespaces_restore_stack.last[prefix] = @namespaces[prefix]
Expand Down Expand Up @@ -627,7 +638,7 @@ def pop_namespaces_restore

def record_entity_expansion(delta=1)
@entity_expansion_count += delta
if @entity_expansion_count > Security.entity_expansion_limit
if @entity_expansion_count > @entity_expansion_limit
raise "number of entity expansions exceeded, processing aborted."
end
end
Expand Down
8 changes: 8 additions & 0 deletions lib/rexml/parsers/pullparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ def entity_expansion_count
@parser.entity_expansion_count
end

def entity_expansion_limit=( limit )
@parser.entity_expansion_limit = limit
end

def entity_expansion_text_limit=( limit )
@parser.entity_expansion_text_limit = limit
end

def each
while has_next?
yield self.pull
Expand Down
8 changes: 8 additions & 0 deletions lib/rexml/parsers/sax2parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def entity_expansion_count
@parser.entity_expansion_count
end

def entity_expansion_limit=( limit )
@parser.entity_expansion_limit = limit
end

def entity_expansion_text_limit=( limit )
@parser.entity_expansion_text_limit = limit
end

def add_listener( listener )
@parser.add_listener( listener )
end
Expand Down
8 changes: 8 additions & 0 deletions lib/rexml/parsers/streamparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def entity_expansion_count
@parser.entity_expansion_count
end

def entity_expansion_limit=( limit )
@parser.entity_expansion_limit = limit
end

def entity_expansion_text_limit=( limit )
@parser.entity_expansion_text_limit = limit
end

def parse
# entity string
while true
Expand Down
12 changes: 4 additions & 8 deletions test/test_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ def test_new

class EntityExpansionLimitTest < Test::Unit::TestCase
def setup
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
end

def teardown
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
end

Expand All @@ -64,9 +62,8 @@ def test_have_value
doc.root.children.first.value
end

REXML::Security.entity_expansion_limit = 100
assert_equal(100, REXML::Security.entity_expansion_limit)
doc = REXML::Document.new(xml)
doc.entity_expansion_limit = 100
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
doc.root.children.first.value
end
Expand Down Expand Up @@ -95,9 +92,8 @@ def test_empty_value
doc.root.children.first.value
end

REXML::Security.entity_expansion_limit = 100
assert_equal(100, REXML::Security.entity_expansion_limit)
doc = REXML::Document.new(xml)
doc.entity_expansion_limit = 100
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
doc.root.children.first.value
end
Expand All @@ -118,12 +114,12 @@ def test_with_default_entity
</member>
XML

REXML::Security.entity_expansion_limit = 4
doc = REXML::Document.new(xml)
doc.entity_expansion_limit = 4
assert_equal("\na\na a\n<\n", doc.root.children.first.value)

REXML::Security.entity_expansion_limit = 3
doc = REXML::Document.new(xml)
doc.entity_expansion_limit = 3
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
doc.root.children.first.value
end
Expand Down
27 changes: 8 additions & 19 deletions test/test_pullparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,6 @@ def test_peek
end

class EntityExpansionLimitTest < Test::Unit::TestCase
def setup
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
end

def teardown
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
end

class GeneralEntityTest < self
def test_have_value
source = <<-XML
Expand Down Expand Up @@ -206,22 +196,21 @@ def test_empty_value
</member>
XML

REXML::Security.entity_expansion_limit = 100000
parser = REXML::Parsers::PullParser.new(source)
parser.entity_expansion_limit = 100000
while parser.has_next?
parser.pull
end
assert_equal(11111, parser.entity_expansion_count)

REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
parser = REXML::Parsers::PullParser.new(source)
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
while parser.has_next?
parser.pull
end
end
assert do
parser.entity_expansion_count > @default_entity_expansion_limit
parser.entity_expansion_count > REXML::Security.entity_expansion_limit
end
end

Expand All @@ -239,14 +228,14 @@ def test_with_default_entity
</member>
XML

REXML::Security.entity_expansion_limit = 4
parser = REXML::Parsers::PullParser.new(source)
parser.entity_expansion_limit = 4
while parser.has_next?
parser.pull
end

REXML::Security.entity_expansion_limit = 3
parser = REXML::Parsers::PullParser.new(source)
parser.entity_expansion_limit = 3
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
while parser.has_next?
parser.pull
Expand All @@ -255,7 +244,7 @@ def test_with_default_entity
end

def test_with_only_default_entities
member_value = "&lt;p&gt;#{'A' * @default_entity_expansion_text_limit}&lt;/p&gt;"
member_value = "&lt;p&gt;#{'A' * REXML::Security.entity_expansion_text_limit}&lt;/p&gt;"
source = <<-XML
<?xml version="1.0" encoding="UTF-8"?>
<member>
Expand All @@ -276,11 +265,11 @@ def test_with_only_default_entities
end
end

expected_value = "<p>#{'A' * @default_entity_expansion_text_limit}</p>"
expected_value = "<p>#{'A' * REXML::Security.entity_expansion_text_limit}</p>"
assert_equal(expected_value, events['member'].strip)
assert_equal(0, parser.entity_expansion_count)
assert do
events['member'].bytesize > @default_entity_expansion_text_limit
events['member'].bytesize > REXML::Security.entity_expansion_text_limit
end
end

Expand All @@ -296,8 +285,8 @@ def test_entity_expansion_text_limit
<member>&a;</member>
XML

REXML::Security.entity_expansion_text_limit = 90
parser = REXML::Parsers::PullParser.new(source)
parser.entity_expansion_text_limit = 90
events = {}
element_name = ''
while parser.has_next?
Expand Down
27 changes: 8 additions & 19 deletions test/test_sax.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,6 @@ def test_sax2
end

class EntityExpansionLimitTest < Test::Unit::TestCase
def setup
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
end

def teardown
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
end

class GeneralEntityTest < self
def test_have_value
source = <<-XML
Expand Down Expand Up @@ -147,18 +137,17 @@ def test_empty_value
</member>
XML

REXML::Security.entity_expansion_limit = 100000
sax = REXML::Parsers::SAX2Parser.new(source)
sax.entity_expansion_limit = 100000
sax.parse
assert_equal(11111, sax.entity_expansion_count)

REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
sax = REXML::Parsers::SAX2Parser.new(source)
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
sax.parse
end
assert do
sax.entity_expansion_count > @default_entity_expansion_limit
sax.entity_expansion_count > REXML::Security.entity_expansion_limit
end
end

Expand All @@ -176,19 +165,19 @@ def test_with_default_entity
</member>
XML

REXML::Security.entity_expansion_limit = 4
sax = REXML::Parsers::SAX2Parser.new(source)
sax.entity_expansion_limit = 4
sax.parse

REXML::Security.entity_expansion_limit = 3
sax = REXML::Parsers::SAX2Parser.new(source)
sax.entity_expansion_limit = 3
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
sax.parse
end
end

def test_with_only_default_entities
member_value = "&lt;p&gt;#{'A' * @default_entity_expansion_text_limit}&lt;/p&gt;"
member_value = "&lt;p&gt;#{'A' * REXML::Security.entity_expansion_text_limit}&lt;/p&gt;"
source = <<-XML
<?xml version="1.0" encoding="UTF-8"?>
<member>
Expand All @@ -203,11 +192,11 @@ def test_with_only_default_entities
end
sax.parse

expected_value = "<p>#{'A' * @default_entity_expansion_text_limit}</p>"
expected_value = "<p>#{'A' * REXML::Security.entity_expansion_text_limit}</p>"
assert_equal(expected_value, text_value.strip)
assert_equal(0, sax.entity_expansion_count)
assert do
text_value.bytesize > @default_entity_expansion_text_limit
text_value.bytesize > REXML::Security.entity_expansion_text_limit
end
end

Expand All @@ -223,8 +212,8 @@ def test_entity_expansion_text_limit
<member>&a;</member>
XML

REXML::Security.entity_expansion_text_limit = 90
sax = REXML::Parsers::SAX2Parser.new(source)
sax.entity_expansion_text_limit = 90
text_size = nil
sax.listen(:characters, ["member"]) do |text|
text_size = text.size
Expand Down
Loading

0 comments on commit f62ec5c

Please sign in to comment.