Skip to content

Commit abadcec

Browse files
committed
fixup! Bound decoder work to prevent a pointer fan-out denial of service
1 parent 10603fd commit abadcec

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

maxminddb/decoder.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ def _decode_pointer(
179179
if self._pointer_test:
180180
return pointer, new_offset
181181

182+
# The pointer itself was charged by its containing array or map. Charge
183+
# its target separately because it is decoded separately each time the
184+
# pointer is followed.
185+
remaining = budget[0] - 1
186+
if remaining < 0:
187+
raise InvalidDatabaseError(_TOO_MANY_VALUES)
188+
budget[0] = remaining
182189
budget[1] += 1
183190
if budget[1] > _MAX_DEPTH:
184191
raise InvalidDatabaseError(_TOO_DEEP)

tests/decoder_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,19 @@ def test_pointer_fan_out_is_bounded(self) -> None:
255255
with self.assertRaises(InvalidDatabaseError):
256256
Decoder(bytes(buf), pointer_base=0).decode(prev)
257257

258+
def test_flat_scalar_pointer_fan_out_is_bounded(self) -> None:
259+
# The array's 32,769 pointer fields and their separately decoded scalar
260+
# targets exceed the 65,536-value limit even without nested containers.
261+
# 0x1e: extended type with size code 30; 0x04: array; 0x7ee4:
262+
# 32,769 - 285.
263+
data = bytes([0xA0, 0x1E, 0x04, 0x7E, 0xE4]) + self._pointer(0) * 32_769
264+
265+
with self.assertRaisesRegex(
266+
InvalidDatabaseError,
267+
"^The MaxMind DB file's data section exceeds the maximum number of values$",
268+
):
269+
Decoder(data, pointer_base=0).decode(1)
270+
258271
def test_cyclic_pointer_raises(self) -> None:
259272
# A pointer to itself must hit the decoder's own depth limit even when
260273
# Python's process-wide recursion limit is much higher.

0 commit comments

Comments
 (0)