Skip to content

Commit db91e0f

Browse files
authoredOct 31, 2017
bpo-31897: Convert unexpected errors when read bogus binary plists into InvalidFileException. (python#4171)
1 parent b484d56 commit db91e0f

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed
 

‎Lib/plistlib.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,8 @@ def parse(self, fp):
557557
self._object_offsets = self._read_ints(num_objects, offset_size)
558558
return self._read_object(self._object_offsets[top_object])
559559

560-
except (OSError, IndexError, struct.error):
560+
except (OSError, IndexError, struct.error, OverflowError,
561+
UnicodeDecodeError):
561562
raise InvalidFileException()
562563

563564
def _get_size(self, tokenL):
@@ -575,6 +576,8 @@ def _read_ints(self, n, size):
575576
if size in _BINARY_FORMAT:
576577
return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
577578
else:
579+
if not size or len(data) != size * n:
580+
raise InvalidFileException()
578581
return tuple(int.from_bytes(data[i: i + size], 'big')
579582
for i in range(0, size * n, size))
580583

‎Lib/test/test_plistlib.py

+64-4
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,13 @@ def test_controlcharacters(self):
353353
testString = "string containing %s" % c
354354
if i >= 32 or c in "\r\n\t":
355355
# \r, \n and \t are the only legal control chars in XML
356-
plistlib.dumps(testString, fmt=plistlib.FMT_XML)
356+
data = plistlib.dumps(testString, fmt=plistlib.FMT_XML)
357+
if c != "\r":
358+
self.assertEqual(plistlib.loads(data), testString)
357359
else:
358-
self.assertRaises(ValueError,
359-
plistlib.dumps,
360-
testString)
360+
with self.assertRaises(ValueError):
361+
plistlib.dumps(testString, fmt=plistlib.FMT_XML)
362+
plistlib.dumps(testString, fmt=plistlib.FMT_BINARY)
361363

362364
def test_non_bmp_characters(self):
363365
pl = {'python': '\U0001f40d'}
@@ -366,6 +368,14 @@ def test_non_bmp_characters(self):
366368
data = plistlib.dumps(pl, fmt=fmt)
367369
self.assertEqual(plistlib.loads(data), pl)
368370

371+
def test_lone_surrogates(self):
372+
for fmt in ALL_FORMATS:
373+
with self.subTest(fmt=fmt):
374+
with self.assertRaises(UnicodeEncodeError):
375+
plistlib.dumps('\ud8ff', fmt=fmt)
376+
with self.assertRaises(UnicodeEncodeError):
377+
plistlib.dumps('\udcff', fmt=fmt)
378+
369379
def test_nondictroot(self):
370380
for fmt in ALL_FORMATS:
371381
with self.subTest(fmt=fmt):
@@ -442,6 +452,56 @@ def test_large_timestamp(self):
442452
data = plistlib.dumps(d, fmt=plistlib.FMT_BINARY)
443453
self.assertEqual(plistlib.loads(data), d)
444454

455+
def test_invalid_binary(self):
456+
for data in [
457+
# too short data
458+
b'',
459+
# too large offset_table_offset and nonstandard offset_size
460+
b'\x00\x08'
461+
b'\x00\x00\x00\x00\x00\x00\x03\x01'
462+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
463+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
464+
b'\x00\x00\x00\x00\x00\x00\x00\x2a',
465+
# integer overflow in offset_table_offset
466+
b'\x00\x08'
467+
b'\x00\x00\x00\x00\x00\x00\x01\x01'
468+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
469+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
470+
b'\xff\xff\xff\xff\xff\xff\xff\xff',
471+
# offset_size = 0
472+
b'\x00\x08'
473+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
474+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
475+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
476+
b'\x00\x00\x00\x00\x00\x00\x00\x09',
477+
# ref_size = 0
478+
b'\xa1\x01\x00\x08\x0a'
479+
b'\x00\x00\x00\x00\x00\x00\x01\x00'
480+
b'\x00\x00\x00\x00\x00\x00\x00\x02'
481+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
482+
b'\x00\x00\x00\x00\x00\x00\x00\x0b',
483+
# integer overflow in offset
484+
b'\x00\xff\xff\xff\xff\xff\xff\xff\xff'
485+
b'\x00\x00\x00\x00\x00\x00\x08\x01'
486+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
487+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
488+
b'\x00\x00\x00\x00\x00\x00\x00\x09',
489+
# invalid ASCII
490+
b'\x51\xff\x08'
491+
b'\x00\x00\x00\x00\x00\x00\x01\x01'
492+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
493+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
494+
b'\x00\x00\x00\x00\x00\x00\x00\x0a',
495+
# invalid UTF-16
496+
b'\x61\xd8\x00\x08'
497+
b'\x00\x00\x00\x00\x00\x00\x01\x01'
498+
b'\x00\x00\x00\x00\x00\x00\x00\x01'
499+
b'\x00\x00\x00\x00\x00\x00\x00\x00'
500+
b'\x00\x00\x00\x00\x00\x00\x00\x0b',
501+
]:
502+
with self.assertRaises(plistlib.InvalidFileException):
503+
plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
504+
445505

446506
class TestPlistlibDeprecated(unittest.TestCase):
447507
def test_io_deprecated(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
plistlib now catches more errors when read binary plists and raises
2+
InvalidFileException instead of unexpected exceptions.

0 commit comments

Comments
 (0)
Please sign in to comment.