Skip to content

Commit 78601c0

Browse files
committed
SL-19707 - maximum parse depth is now 200
1 parent e00171d commit 78601c0

File tree

3 files changed

+39
-20
lines changed

3 files changed

+39
-20
lines changed

llsd/base.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
ALL_CHARS = str(bytearray(range(256))) if PY2 else bytes(range(256))
3333

3434
MAX_FORMAT_DEPTH = 200
35+
MAX_PARSE_DEPTH = 200
36+
3537
class _LLSD:
3638
__metaclass__ = abc.ABCMeta
3739

@@ -209,7 +211,7 @@ def _parse_datestr(datestr):
209211
return datetime.datetime(year, month, day, hour, minute, second, usec)
210212

211213

212-
def _bool_to_python(node):
214+
def _bool_to_python(node, depth=0):
213215
"Convert boolean node to a python object."
214216
val = node.text or ''
215217
try:
@@ -220,35 +222,35 @@ def _bool_to_python(node):
220222
return bool(val)
221223

222224

223-
def _int_to_python(node):
225+
def _int_to_python(node, depth=0):
224226
"Convert integer node to a python object."
225227
val = node.text or ''
226228
if not val.strip():
227229
return 0
228230
return int(val)
229231

230232

231-
def _real_to_python(node):
233+
def _real_to_python(node, depth=0):
232234
"Convert floating point node to a python object."
233235
val = node.text or ''
234236
if not val.strip():
235237
return 0.0
236238
return float(val)
237239

238240

239-
def _uuid_to_python(node):
241+
def _uuid_to_python(node, depth=0):
240242
"Convert uuid node to a python object."
241243
if node.text:
242244
return uuid.UUID(hex=node.text)
243245
return uuid.UUID(int=0)
244246

245247

246-
def _str_to_python(node):
248+
def _str_to_python(node, depth=0):
247249
"Convert string node to a python object."
248250
return node.text or ''
249251

250252

251-
def _bin_to_python(node):
253+
def _bin_to_python(node, depth=0):
252254
base = node.get('encoding') or 'base64'
253255
try:
254256
if base == 'base16':
@@ -267,38 +269,38 @@ def _bin_to_python(node):
267269
return LLSDParseError("Bad binary data: " + str(exc))
268270

269271

270-
def _date_to_python(node):
272+
def _date_to_python(node, depth=0):
271273
"Convert date node to a python object."
272274
val = node.text or ''
273275
if not val:
274276
val = "1970-01-01T00:00:00Z"
275277
return _parse_datestr(val)
276278

277279

278-
def _uri_to_python(node):
280+
def _uri_to_python(node, depth=0):
279281
"Convert uri node to a python object."
280282
val = node.text or ''
281283
return uri(val)
282284

283285

284-
def _map_to_python(node):
286+
def _map_to_python(node, depth=0):
285287
"Convert map node to a python object."
286288
result = {}
287289
for index in range(len(node))[::2]:
288290
if node[index].text is None:
289-
result[''] = _to_python(node[index+1])
291+
result[''] = _to_python(node[index+1], depth+1)
290292
else:
291-
result[node[index].text] = _to_python(node[index+1])
293+
result[node[index].text] = _to_python(node[index+1], depth+1)
292294
return result
293295

294296

295-
def _array_to_python(node):
297+
def _array_to_python(node, depth=0):
296298
"Convert array node to a python object."
297-
return [_to_python(child) for child in node]
299+
return [_to_python(child, depth+1) for child in node]
298300

299301

300302
NODE_HANDLERS = dict(
301-
undef=lambda x: None,
303+
undef=lambda x,y: None,
302304
boolean=_bool_to_python,
303305
integer=_int_to_python,
304306
real=_real_to_python,
@@ -312,9 +314,12 @@ def _array_to_python(node):
312314
)
313315

314316

315-
def _to_python(node):
317+
def _to_python(node, depth=0):
316318
"Convert node to a python object."
317-
return NODE_HANDLERS[node.tag](node)
319+
if depth > MAX_PARSE_DEPTH:
320+
raise LLSDParseError("Cannot serialize depth of more than %d" % MAX_FORMAT_DEPTH)
321+
322+
return NODE_HANDLERS[node.tag](node, depth)
318323

319324

320325
class LLSDBaseFormatter(object):

llsd/serde_binary.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import uuid
66

77
from llsd.base import (_LLSD, LLSDBaseParser, LLSDSerializationError, BINARY_HEADER,
8-
MAX_FORMAT_DEPTH,_str_to_bytes, binary, is_integer, is_string, uri)
8+
MAX_FORMAT_DEPTH, MAX_PARSE_DEPTH, _str_to_bytes, binary, is_integer, is_string, uri)
99

1010

1111
try:
@@ -21,7 +21,7 @@ class LLSDBinaryParser(LLSDBaseParser):
2121
2222
See http://wiki.secondlife.com/wiki/LLSD#Binary_Serialization
2323
"""
24-
__slots__ = ['_dispatch', '_keep_binary']
24+
__slots__ = ['_dispatch', '_keep_binary', '_depth']
2525

2626
def __init__(self):
2727
super(LLSDBinaryParser, self).__init__()
@@ -62,6 +62,7 @@ def __init__(self):
6262
# entries in _dispatch.
6363
for c, func in _dispatch_dict.items():
6464
self._dispatch[ord(c)] = func
65+
self._depth = 0
6566

6667
def parse(self, something, ignore_binary = False):
6768
"""
@@ -81,6 +82,9 @@ def parse(self, something, ignore_binary = False):
8182

8283
def _parse(self):
8384
"The actual parser which is called recursively when necessary."
85+
if self._depth > MAX_PARSE_DEPTH:
86+
self._error("Parse depth exceeded max.")
87+
8488
cc = self._getc()
8589
try:
8690
func = self._dispatch[ord(cc)]
@@ -96,6 +100,7 @@ def _parse_map(self):
96100
count = 0
97101
cc = self._getc()
98102
key = b''
103+
self._depth = self._depth + 1
99104
while (cc != b'}') and (count < size):
100105
if cc == b'k':
101106
key = self._parse_string()
@@ -109,16 +114,19 @@ def _parse_map(self):
109114
cc = self._getc()
110115
if cc != b'}':
111116
self._error("invalid map close token")
117+
self._depth = self._depth - 1
112118
return rv
113119

114120
def _parse_array(self):
115121
"Parse a single llsd array"
116122
rv = []
123+
self._depth = self._depth + 1
117124
size = struct.unpack("!i", self._getc(4))[0]
118125
for count in range(size):
119126
rv.append(self._parse())
120127
if self._getc() != b']':
121128
self._error("invalid array close token")
129+
self._depth = self._depth - 1
122130
return rv
123131

124132
def _parse_string(self):

llsd/serde_notation.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import uuid
55

66
from llsd.base import (_LLSD, B, LLSDBaseFormatter, LLSDBaseParser, NOTATION_HEADER,
7-
MAX_FORMAT_DEPTH, LLSDParseError, LLSDSerializationError, UnicodeType,
7+
MAX_FORMAT_DEPTH, MAX_PARSE_DEPTH, LLSDParseError, LLSDSerializationError, UnicodeType,
88
_format_datestr, _parse_datestr, _str_to_bytes, binary, uri)
99

1010

@@ -70,6 +70,7 @@ def __init__(self):
7070
# Then fill in specific entries based on the dict above.
7171
for c, func in _dispatch_dict.items():
7272
self._dispatch[ord(c)] = func
73+
self._depth = 0
7374

7475
def parse(self, something, ignore_binary = False):
7576
"""
@@ -107,6 +108,8 @@ def _get_until(self, delim):
107108

108109
def _parse(self, cc):
109110
"The notation parser workhorse."
111+
if self._depth > MAX_PARSE_DEPTH:
112+
self._error("Parse depth exceeded max.")
110113
try:
111114
func = self._dispatch[ord(cc)]
112115
except IndexError:
@@ -182,6 +185,7 @@ def _parse_map(self, cc):
182185
rv = {}
183186
key = b''
184187
found_key = False
188+
self._depth = self._depth + 1
185189
# skip the beginning '{'
186190
cc = self._getc()
187191
while (cc != b'}'):
@@ -207,6 +211,7 @@ def _parse_map(self, cc):
207211
else:
208212
self._error("missing separator")
209213
cc = self._getc()
214+
self._depth = self._depth - 1
210215

211216
return rv
212217

@@ -217,6 +222,7 @@ def _parse_array(self, cc):
217222
array: [ object, object, object ]
218223
"""
219224
rv = []
225+
self._depth = self._depth + 1
220226
# skip the beginning '['
221227
cc = self._getc()
222228
while (cc != b']'):
@@ -227,7 +233,7 @@ def _parse_array(self, cc):
227233
continue
228234
rv.append(self._parse(cc))
229235
cc = self._getc()
230-
236+
self._depth = self._depth - 1
231237
return rv
232238

233239
def _parse_uuid(self, cc):

0 commit comments

Comments
 (0)