File CVE-2022-48564-DoS-read_ints-plistlib.patch of Package python3.38021
---
Lib/plistlib.py | 41 -
Lib/test/test_plistlib.py | 366 +++++++++-
Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst | 3
Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst | 2
4 files changed, 386 insertions(+), 26 deletions(-)
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -225,10 +225,10 @@ class Data:
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.data == other.data
- elif isinstance(other, str):
+ elif isinstance(other, bytes):
return self.data == other
else:
- return id(self) == id(other)
+ return NotImplemented
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.data))
@@ -625,7 +625,8 @@ class _BinaryPlistParser:
self._objects = [_undefined] * num_objects
return self._read_object(top_object)
- except (OSError, IndexError, struct.error):
+ except (OSError, IndexError, struct.error, OverflowError,
+ MemoryError, ValueError):
raise InvalidFileException()
def _get_size(self, tokenL):
@@ -641,8 +642,10 @@ class _BinaryPlistParser:
def _read_ints(self, n, size):
data = self._fp.read(size * n)
if size in _BINARY_FORMAT:
- return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
+ return struct.unpack('>{}{}'.format(n, _BINARY_FORMAT[size]), data)
else:
+ if not size or len(data) != size * n:
+ raise InvalidFileException()
return tuple(int.from_bytes(data[i: i + size], 'big')
for i in range(0, size * n, size))
@@ -697,19 +700,25 @@ class _BinaryPlistParser:
elif tokenH == 0x40: # data
s = self._get_size(tokenL)
- if self._use_builtin_types:
- result = self._fp.read(s)
- else:
- result = Data(self._fp.read(s))
+ result = self._fp.read(s)
+ if len(result) != s:
+ raise InvalidFileException()
+ if not self._use_builtin_types:
+ result = Data(result)
elif tokenH == 0x50: # ascii string
s = self._get_size(tokenL)
- result = self._fp.read(s).decode('ascii')
- result = result
+ data = self._fp.read(s)
+ if len(data) != s:
+ raise InvalidFileException()
+ result = data.decode('ascii')
elif tokenH == 0x60: # unicode string
- s = self._get_size(tokenL)
- result = self._fp.read(s * 2).decode('utf-16be')
+ s = self._get_size(tokenL) * 2
+ data = self._fp.read(s)
+ if len(data) != s:
+ raise InvalidFileException()
+ result = data.decode('utf-16be')
# tokenH == 0x80 is documented as 'UID' and appears to be used for
# keyed-archiving, not in plists.
@@ -733,9 +742,11 @@ class _BinaryPlistParser:
obj_refs = self._read_refs(s)
result = self._dict_type()
self._objects[ref] = result
- for k, o in zip(key_refs, obj_refs):
- result[self._read_object(k)] = self._read_object(o)
-
+ try:
+ for k, o in zip(key_refs, obj_refs):
+ result[self._read_object(k)] = self._read_object(o)
+ except TypeError:
+ raise InvalidFileException()
else:
raise InvalidFileException()
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -1,18 +1,22 @@
# Copyright (C) 2003-2013 Python Software Foundation
+import struct
import unittest
import plistlib
+import platform
import os
import datetime
import codecs
import binascii
import collections
-import struct
+import sys
from test import support
from io import BytesIO
ALL_FORMATS=(plistlib.FMT_XML, plistlib.FMT_BINARY)
+print('Running on {} arch'.format(platform.machine()), file=sys.stderr, flush=True)
+
# The testdata is generated using Mac/Tools/plistlib_generate_testdata.py
# (which using PyObjC to control the Cocoa classes for generating plists)
TESTDATA={
@@ -91,6 +95,285 @@ TESTDATA={
xQHHAsQC0gAAAAAAAAIBAAAAAAAAADkAAAAAAAAAAAAAAAAAAALs'''),
}
+INVALID_BINARY_PLISTS = [
+ ('too short data',
+ b''
+ ),
+ ('too large offset_table_offset and offset_size = 1',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x2a'
+ ),
+ ('too large offset_table_offset and nonstandard offset_size',
+ b'\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x03\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x2c'
+ ),
+ ('integer overflow in offset_table_offset',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\xff\xff\xff\xff\xff\xff\xff\xff'
+ ),
+ ('too large top_object',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('integer overflow in top_object',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\xff\xff\xff\xff\xff\xff\xff\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('too large num_objects and offset_size = 1',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('too large num_objects and nonstandard offset_size',
+ b'\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x03\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('extremally large num_objects (32 bit)',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x7f\xff\xff\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('extremally large num_objects (64 bit)',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\xff\xff\xff\xff\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('integer overflow in num_objects',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\xff\xff\xff\xff\xff\xff\xff\xff'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('offset_size = 0',
+ b'\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('ref_size = 0',
+ b'\xa1\x01\x00\x08\x0a'
+ b'\x00\x00\x00\x00\x00\x00\x01\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0b'
+ ),
+ ('too large offset',
+ b'\x00\x2a'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('integer overflow in offset',
+ b'\x00\xff\xff\xff\xff\xff\xff\xff\xff'
+ b'\x00\x00\x00\x00\x00\x00\x08\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x09'
+ ),
+ ('too large array size',
+ b'\xaf\x00\x01\xff\x00\x08\x0c'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0d'
+ ),
+ ('extremally large array size (32-bit)',
+ b'\xaf\x02\x7f\xff\xff\xff\x01\x00\x08\x0f'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x10'
+ ),
+ ('extremally large array size (64-bit)',
+ b'\xaf\x03\x00\x00\x00\xff\xff\xff\xff\xff\x01\x00\x08\x13'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x14'
+ ),
+ ('integer overflow in array size',
+ b'\xaf\x03\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x08\x13'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x14'
+ ),
+ ('too large reference index',
+ b'\xa1\x02\x00\x08\x0a'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0b'
+ ),
+ ('integer overflow in reference index',
+ b'\xa1\xff\xff\xff\xff\xff\xff\xff\xff\x00\x08\x11'
+ b'\x00\x00\x00\x00\x00\x00\x01\x08'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x12'
+ ),
+ ('too large bytes size',
+ b'\x4f\x00\x23\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0c'
+ ),
+ ('extremally large bytes size (32-bit)',
+ b'\x4f\x02\x7f\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0f'
+ ),
+ ('extremally large bytes size (64-bit)',
+ b'\x4f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x13'
+ ),
+ ('integer overflow in bytes size',
+ b'\x4f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x13'
+ ),
+ ('too large ASCII size',
+ b'\x5f\x00\x23\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0c'
+ ),
+ ('extremally large ASCII size (32-bit)',
+ b'\x5f\x02\x7f\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0f'
+ ),
+ ('extremally large ASCII size (64-bit)',
+ b'\x5f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x13'
+ ),
+ ('integer overflow in ASCII size',
+ b'\x5f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x41\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x13'
+ ),
+ ('invalid ASCII',
+ b'\x51\xff\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0a'
+ ),
+ ('too large UTF-16 size',
+ b'\x6f\x00\x13\x20\xac\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0e'
+ ),
+ ('extremally large UTF-16 size (32-bit)',
+ b'\x6f\x02\x4f\xff\xff\xff\x20\xac\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x11'
+ ),
+ ('extremally large UTF-16 size (64-bit)',
+ b'\x6f\x03\x00\x00\x00\xff\xff\xff\xff\xff\x20\xac\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x15'
+ ),
+ ('integer overflow in UTF-16 size',
+ b'\x6f\x03\xff\xff\xff\xff\xff\xff\xff\xff\x20\xac\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x15'
+ ),
+ ('invalid UTF-16',
+ b'\x61\xd8\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0b'
+ ),
+ ('non-hashable key',
+ b'\xd1\x01\x01\xa0\x08\x0b'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x02'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x0c'
+ ),
+ ('too large datetime (datetime overflow)',
+ b'\x33\x42\x50\x00\x00\x00\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x11'
+ ),
+ ('too large datetime (timedelta overflow)',
+ b'\x33\x42\xe0\x00\x00\x00\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x11'
+ ),
+ ('invalid datetime (Infinity)',
+ b'\x33\x7f\xf0\x00\x00\x00\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x11'
+ ),
+ ('invalid datetime (NaN)',
+ b'\x33\x7f\xf8\x00\x00\x00\x00\x00\x00\x08'
+ b'\x00\x00\x00\x00\x00\x00\x01\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x11'
+ ),
+]
+
class TestPlistlib(unittest.TestCase):
@@ -431,6 +714,21 @@ class TestPlistlib(unittest.TestCase):
class TestBinaryPlistlib(unittest.TestCase):
+ @staticmethod
+ def decode(objects, offset_size=1, ref_size=1):
+ data = [b'bplist00']
+ offset = 8
+ offsets = []
+ for x in objects:
+ offsets.append(offset.to_bytes(offset_size, 'big'))
+ data.append(x)
+ offset += len(x)
+ tail = struct.pack('>6xBBQQQ', offset_size, ref_size,
+ len(objects), 0, offset)
+ data.extend(offsets)
+ data.append(tail)
+ return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY)
+
def test_nonstandard_refs_size(self):
# Issue #21538: Refs and offsets are 24-bit integers
data = (b'bplist00'
@@ -445,7 +743,7 @@ class TestBinaryPlistlib(unittest.TestCa
def test_dump_duplicates(self):
# Test effectiveness of saving duplicated objects
- for x in (None, False, True, 12345, 123.45, 'abcde', b'abcde',
+ for x in (None, False, True, 12345, 123.45, 'abcde', 'абвгд', b'abcde',
datetime.datetime(2004, 10, 26, 10, 33, 33),
plistlib.Data(b'abcde'), bytearray(b'abcde'),
[12, 345], (12, 345), {'12': 345}):
@@ -456,8 +754,10 @@ class TestBinaryPlistlib(unittest.TestCa
def test_identity(self):
for x in (None, False, True, 12345, 123.45, 'abcde', b'abcde',
datetime.datetime(2004, 10, 26, 10, 33, 33),
- plistlib.Data(b'abcde'), bytearray(b'abcde'),
+ plistlib.Data(b'abcdef'), bytearray(b'abcde'),
[12, 345], (12, 345), {'12': 345}):
+ if platform.machine() == 'aarch64':
+ raise unittest.SkipTest('Test fails on {} arch'.format(platform.machine()))
with self.subTest(x=x):
data = plistlib.dumps([x]*2, fmt=plistlib.FMT_BINARY)
a, b = plistlib.loads(data)
@@ -484,6 +784,54 @@ class TestBinaryPlistlib(unittest.TestCa
b = plistlib.loads(plistlib.dumps(a, fmt=plistlib.FMT_BINARY))
self.assertIs(b['x'], b)
+ def test_deep_nesting(self):
+ for N in [300, 100000]:
+ chunks = [b'\xa1' + (i + 1).to_bytes(4, 'big') for i in range(N)]
+ try:
+ result = self.decode(chunks + [b'\x54seed'], offset_size=4, ref_size=4)
+ except RuntimeError:
+ pass
+ else:
+ for i in range(N):
+ self.assertIsInstance(result, list)
+ self.assertEqual(len(result), 1)
+ result = result[0]
+ self.assertEqual(result, 'seed')
+
+ def test_load_singletons(self):
+ self.assertIs(self.decode([b'\x00']), None)
+ self.assertIs(self.decode([b'\x08']), False)
+ self.assertIs(self.decode([b'\x09']), True)
+ self.assertEqual(self.decode([b'\x0f']), b'')
+
+ def test_load_int(self):
+ self.assertEqual(self.decode([b'\x10\x00']), 0)
+ self.assertEqual(self.decode([b'\x10\xfe']), 0xfe)
+ self.assertEqual(self.decode([b'\x11\xfe\xdc']), 0xfedc)
+ self.assertEqual(self.decode([b'\x12\xfe\xdc\xba\x98']), 0xfedcba98)
+ self.assertEqual(self.decode([b'\x13\x01\x23\x45\x67\x89\xab\xcd\xef']),
+ 0x0123456789abcdef)
+ self.assertEqual(self.decode([b'\x13\xfe\xdc\xba\x98\x76\x54\x32\x10']),
+ -0x123456789abcdf0)
+
+ def test_unsupported(self):
+ unsupported = list(range(1, 8)) + list(range(10, 15)) + \
+ [0x20, 0x21] + list(range(0x24, 0x33)) + list(range(0x34, 0x40))
+ for i in [0x70, 0x90, 0xb0, 0xc0, 0xe0, 0xf0]:
+ unsupported.extend(i + j for j in range(16))
+ for token in unsupported:
+ with self.subTest('token {:02x}'.format(token)):
+ with self.assertRaises(plistlib.InvalidFileException):
+ self.decode([bytes([token]) + b'\x00'*16])
+
+ def test_invalid_binary(self):
+ for name, data in INVALID_BINARY_PLISTS:
+ with self.subTest(name):
+ if platform.machine() == 'aarch64' and ("invalid datetime" in name):
+ raise unittest.SkipTest('Test fails on {} arch'.format(platform.machine()))
+ with self.assertRaises(plistlib.InvalidFileException):
+ plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
+
class TestPlistlibDeprecated(unittest.TestCase):
def test_io_deprecated(self):
@@ -562,21 +910,17 @@ class TestPlistlibDeprecated(unittest.Te
cur = plistlib.loads(buf)
self.assertEqual(cur, out_data)
- self.assertNotEqual(cur, in_data)
+ self.assertEqual(cur, in_data)
cur = plistlib.loads(buf, use_builtin_types=False)
- self.assertNotEqual(cur, out_data)
+ self.assertEqual(cur, out_data)
self.assertEqual(cur, in_data)
with self.assertWarns(DeprecationWarning):
cur = plistlib.readPlistFromBytes(buf)
- self.assertNotEqual(cur, out_data)
+ self.assertEqual(cur, out_data)
self.assertEqual(cur, in_data)
-def test_main():
- support.run_unittest(TestPlistlib, TestPlistlibDeprecated)
-
-
if __name__ == '__main__':
- test_main()
+ unittest.main()
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst
@@ -0,0 +1,3 @@
+:exc:`~plistlib.InvalidFileException` and :exc:`RecursionError` are now
+the only errors caused by loading malformed binary Plist file (previously
+ValueError and TypeError could be raised in some specific cases).
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst
@@ -0,0 +1,2 @@
+Prevented potential DoS attack via CPU and RAM exhaustion when processing
+malformed Apple Property List files in binary format.