diff --git a/00413-CVE-2022-48564.patch b/00413-CVE-2022-48564.patch new file mode 100644 index 0000000..3fc1cf8 --- /dev/null +++ b/00413-CVE-2022-48564.patch @@ -0,0 +1,560 @@ +From cec66eefbee76ee95f252a52de0f5abc1b677f5b Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +Date: Tue, 12 Dec 2023 13:03:42 +0100 +Subject: [PATCH] [3.6] bpo-42103: Improve validation of Plist files. + (GH-22882) (GH-23118) + +* Prevent some possible DoS attacks via providing invalid Plist files + with extremely large number of objects or collection sizes. +* Raise InvalidFileException for too large bytes and string size instead of returning garbage. +* Raise InvalidFileException instead of ValueError for specific invalid datetime (NaN). +* Raise InvalidFileException instead of TypeError for non-hashable dict keys. +* Add more tests for invalid Plist files.. +(cherry picked from commit 34637a0ce21e7261b952fbd9d006474cc29b681f) + +Co-authored-by: Serhiy Storchaka +--- + Lib/plistlib.py | 34 +- + Lib/test/test_plistlib.py | 394 +++++++++++++++--- + .../2020-10-23-19-20-14.bpo-42103.C5obK2.rst | 3 + + .../2020-10-23-19-19-30.bpo-42103.cILT66.rst | 2 + + 4 files changed, 366 insertions(+), 67 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst + create mode 100644 Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst + +diff --git a/Lib/plistlib.py b/Lib/plistlib.py +index a918643..df1f346 100644 +--- a/Lib/plistlib.py ++++ b/Lib/plistlib.py +@@ -626,7 +626,7 @@ class _BinaryPlistParser: + return self._read_object(top_object) + + except (OSError, IndexError, struct.error, OverflowError, +- UnicodeDecodeError): ++ ValueError): + raise InvalidFileException() + + def _get_size(self, tokenL): +@@ -642,7 +642,7 @@ 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(f'>{n}{_BINARY_FORMAT[size]}', data) + else: + if not size or len(data) != size * n: + raise InvalidFileException() +@@ -701,19 +701,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. +@@ -737,9 +743,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() + +diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py +index d47c607..f71245d 100644 +--- a/Lib/test/test_plistlib.py ++++ b/Lib/test/test_plistlib.py +@@ -1,5 +1,6 @@ + # Copyright (C) 2003-2013 Python Software Foundation + ++import struct + import unittest + import plistlib + import os +@@ -90,6 +91,284 @@ 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): + +@@ -447,6 +726,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' +@@ -461,7 +755,7 @@ class TestBinaryPlistlib(unittest.TestCase): + + 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}): +@@ -500,6 +794,20 @@ class TestBinaryPlistlib(unittest.TestCase): + 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 RecursionError: ++ 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_large_timestamp(self): + # Issue #26709: 32-bit timestamp out of range + for ts in -2**31-1, 2**31: +@@ -509,55 +817,37 @@ class TestBinaryPlistlib(unittest.TestCase): + data = plistlib.dumps(d, fmt=plistlib.FMT_BINARY) + self.assertEqual(plistlib.loads(data), d) + ++ 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 = [*range(1, 8), *range(10, 15), ++ 0x20, 0x21, *range(0x24, 0x33), *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(f'token {token:02x}'): ++ with self.assertRaises(plistlib.InvalidFileException): ++ self.decode(bytes([token]) + b'\x00'*16) ++ + def test_invalid_binary(self): +- for data in [ +- # too short data +- b'', +- # too large offset_table_offset and nonstandard offset_size +- b'\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\x2a', +- # 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', +- # 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', +- # 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', +- # 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', +- # 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', +- ]: +- with self.assertRaises(plistlib.InvalidFileException): +- plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY) ++ for name, data in INVALID_BINARY_PLISTS: ++ with self.subTest(name): ++ with self.assertRaises(plistlib.InvalidFileException): ++ plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY) + + + class TestPlistlibDeprecated(unittest.TestCase): +@@ -655,9 +945,5 @@ class MiscTestCase(unittest.TestCase): + support.check__all__(self, plistlib, blacklist=blacklist) + + +-def test_main(): +- support.run_unittest(TestPlistlib, TestPlistlibDeprecated, MiscTestCase) +- +- + if __name__ == '__main__': +- test_main() ++ unittest.main() +diff --git a/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst b/Misc/NEWS.d/next/Library/2020-10-23-19-20-14.bpo-42103.C5obK2.rst +new file mode 100644 +index 0000000..4eb694c +--- /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). +diff --git a/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst b/Misc/NEWS.d/next/Security/2020-10-23-19-19-30.bpo-42103.cILT66.rst +new file mode 100644 +index 0000000..15d7b65 +--- /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. +-- +2.43.0 + diff --git a/python3.spec b/python3.spec index 5d45d6a..b3f8219 100644 --- a/python3.spec +++ b/python3.spec @@ -14,7 +14,7 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well Version: %{pybasever}.8 -Release: 57%{?dist} +Release: 58%{?dist} License: Python @@ -810,6 +810,13 @@ Patch404: 00404-cve-2023-40217.patch # Resolved upstream: https://github.com/python/cpython/issues/83602 Patch408: 00408-CVE-2022-48560.patch +# 00413 # +# CVE-2022-48564 +# +# DoS when processing malformed Apple Property List files in binary format +# Resolved upstream: https://github.com/python/cpython/commit/a63234c49b2fbfb6f0aca32525e525ce3d43b2b4 +Patch413: 00413-CVE-2022-48564.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1160,6 +1167,7 @@ git apply %{PATCH351} %patch399 -p1 %patch404 -p1 %patch408 -p1 +%patch413 -p1 # Remove files that should be generated by the build # (This is after patching, so that we can use patches directly from upstream) @@ -2091,6 +2099,10 @@ fi # ====================================================== %changelog +* Tue Dec 12 2023 Lumír Balhar - 3.6.8-58 +- Security fix for CVE-2022-48564 +Resolves: RHEL-16674 + * Thu Nov 23 2023 Lumír Balhar - 3.6.8-57 - Security fix for CVE-2022-48560 Resolves: RHEL-16707