import python3-3.6.8-56.el8_9.2

c8 imports/c8/python3-3.6.8-56.el8_9.2
MSVSphere Packaging Team 12 months ago
parent 6ad02b3763
commit 1521baa1b7

@ -0,0 +1,143 @@
From c563f409ea30bcb0623d785428c9257917371b76 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Thu, 23 Jan 2020 06:49:19 -0800
Subject: [PATCH] bpo-39421: Fix posible crash in heapq with custom comparison
operators (GH-18118) (GH-18146)
(cherry picked from commit 79f89e6e5a659846d1068e8b1bd8e491ccdef861)
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
---
Lib/test/test_heapq.py | 31 ++++++++++++++++
.../2020-01-22-15-53-37.bpo-39421.O3nG7u.rst | 2 ++
Modules/_heapqmodule.c | 35 ++++++++++++++-----
3 files changed, 59 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-01-22-15-53-37.bpo-39421.O3nG7u.rst
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index 2f8c648d84a58..7c3fb0210f69b 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -414,6 +414,37 @@ def test_heappop_mutating_heap(self):
with self.assertRaises((IndexError, RuntimeError)):
self.module.heappop(heap)
+ def test_comparison_operator_modifiying_heap(self):
+ # See bpo-39421: Strong references need to be taken
+ # when comparing objects as they can alter the heap
+ class EvilClass(int):
+ def __lt__(self, o):
+ heap.clear()
+ return NotImplemented
+
+ heap = []
+ self.module.heappush(heap, EvilClass(0))
+ self.assertRaises(IndexError, self.module.heappushpop, heap, 1)
+
+ def test_comparison_operator_modifiying_heap_two_heaps(self):
+
+ class h(int):
+ def __lt__(self, o):
+ list2.clear()
+ return NotImplemented
+
+ class g(int):
+ def __lt__(self, o):
+ list1.clear()
+ return NotImplemented
+
+ list1, list2 = [], []
+
+ self.module.heappush(list1, h(0))
+ self.module.heappush(list2, g(0))
+
+ self.assertRaises((IndexError, RuntimeError), self.module.heappush, list1, g(1))
+ self.assertRaises((IndexError, RuntimeError), self.module.heappush, list2, h(1))
class TestErrorHandlingPython(TestErrorHandling, TestCase):
module = py_heapq
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-01-22-15-53-37.bpo-39421.O3nG7u.rst b/Misc/NEWS.d/next/Core and Builtins/2020-01-22-15-53-37.bpo-39421.O3nG7u.rst
new file mode 100644
index 0000000000000..bae008150ee12
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-01-22-15-53-37.bpo-39421.O3nG7u.rst
@@ -0,0 +1,2 @@
+Fix possible crashes when operating with the functions in the :mod:`heapq`
+module and custom comparison operators.
diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c
index b499e1f668aae..0fb35ffe5ec48 100644
--- a/Modules/_heapqmodule.c
+++ b/Modules/_heapqmodule.c
@@ -29,7 +29,11 @@ siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
while (pos > startpos) {
parentpos = (pos - 1) >> 1;
parent = arr[parentpos];
+ Py_INCREF(newitem);
+ Py_INCREF(parent);
cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
+ Py_DECREF(parent);
+ Py_DECREF(newitem);
if (cmp < 0)
return -1;
if (size != PyList_GET_SIZE(heap)) {
@@ -71,10 +75,13 @@ siftup(PyListObject *heap, Py_ssize_t pos)
/* Set childpos to index of smaller child. */
childpos = 2*pos + 1; /* leftmost child position */
if (childpos + 1 < endpos) {
- cmp = PyObject_RichCompareBool(
- arr[childpos],
- arr[childpos + 1],
- Py_LT);
+ PyObject* a = arr[childpos];
+ PyObject* b = arr[childpos + 1];
+ Py_INCREF(a);
+ Py_INCREF(b);
+ cmp = PyObject_RichCompareBool(a, b, Py_LT);
+ Py_DECREF(a);
+ Py_DECREF(b);
if (cmp < 0)
return -1;
childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
@@ -229,7 +236,10 @@ heappushpop(PyObject *self, PyObject *args)
return item;
}
- cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
+ PyObject* top = PyList_GET_ITEM(heap, 0);
+ Py_INCREF(top);
+ cmp = PyObject_RichCompareBool(top, item, Py_LT);
+ Py_DECREF(top);
if (cmp < 0)
return NULL;
if (cmp == 0) {
@@ -383,7 +393,11 @@ siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
while (pos > startpos) {
parentpos = (pos - 1) >> 1;
parent = arr[parentpos];
+ Py_INCREF(parent);
+ Py_INCREF(newitem);
cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
+ Py_DECREF(parent);
+ Py_DECREF(newitem);
if (cmp < 0)
return -1;
if (size != PyList_GET_SIZE(heap)) {
@@ -425,10 +439,13 @@ siftup_max(PyListObject *heap, Py_ssize_t pos)
/* Set childpos to index of smaller child. */
childpos = 2*pos + 1; /* leftmost child position */
if (childpos + 1 < endpos) {
- cmp = PyObject_RichCompareBool(
- arr[childpos + 1],
- arr[childpos],
- Py_LT);
+ PyObject* a = arr[childpos + 1];
+ PyObject* b = arr[childpos];
+ Py_INCREF(a);
+ Py_INCREF(b);
+ cmp = PyObject_RichCompareBool(a, b, Py_LT);
+ Py_DECREF(a);
+ Py_DECREF(b);
if (cmp < 0)
return -1;
childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */

@ -0,0 +1,560 @@
From cec66eefbee76ee95f252a52de0f5abc1b677f5b Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
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 <storchaka@gmail.com>
---
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

@ -0,0 +1,88 @@
From 0d02ff99721f7650e39ba4c7d8fe06f412bbb591 Mon Sep 17 00:00:00 2001
From: Victor Stinner <vstinner@python.org>
Date: Wed, 13 Dec 2023 11:50:26 +0100
Subject: [PATCH] bpo-46623: Skip two test_zlib tests on s390x (GH-31096)
Skip test_pair() and test_speech128() of test_zlib on s390x since
they fail if zlib uses the s390x hardware accelerator.
---
Lib/test/test_zlib.py | 32 +++++++++++++++++++
.../2022-02-03-09-45-26.bpo-46623.vxzuhV.rst | 2 ++
2 files changed, 34 insertions(+)
create mode 100644 Misc/NEWS.d/next/Tests/2022-02-03-09-45-26.bpo-46623.vxzuhV.rst
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index b7170b4..770a425 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -1,6 +1,7 @@
import unittest
from test import support
import binascii
+import os
import pickle
import random
import sys
@@ -15,6 +16,35 @@ requires_Decompress_copy = unittest.skipUnless(
hasattr(zlib.decompressobj(), "copy"),
'requires Decompress.copy()')
+# bpo-46623: On s390x, when a hardware accelerator is used, using different
+# ways to compress data with zlib can produce different compressed data.
+# Simplified test_pair() code:
+#
+# def func1(data):
+# return zlib.compress(data)
+#
+# def func2(data)
+# co = zlib.compressobj()
+# x1 = co.compress(data)
+# x2 = co.flush()
+# return x1 + x2
+#
+# On s390x if zlib uses a hardware accelerator, func1() creates a single
+# "final" compressed block whereas func2() produces 3 compressed blocks (the
+# last one is a final block). On other platforms with no accelerator, func1()
+# and func2() produce the same compressed data made of a single (final)
+# compressed block.
+#
+# Only the compressed data is different, the decompression returns the original
+# data:
+#
+# zlib.decompress(func1(data)) == zlib.decompress(func2(data)) == data
+#
+# Make the assumption that s390x always has an accelerator to simplify the skip
+# condition. Windows doesn't have os.uname() but it doesn't support s390x.
+skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
+ 'skipped on s390x')
+
class VersionTestCase(unittest.TestCase):
@@ -174,6 +204,7 @@ class CompressTestCase(BaseCompressTestCase, unittest.TestCase):
bufsize=zlib.DEF_BUF_SIZE),
HAMLET_SCENE)
+ @skip_on_s390x
def test_speech128(self):
# compress more data
data = HAMLET_SCENE * 128
@@ -225,6 +256,7 @@ class CompressTestCase(BaseCompressTestCase, unittest.TestCase):
class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
# Test compression object
+ @skip_on_s390x
def test_pair(self):
# straightforward compress/decompress objects
datasrc = HAMLET_SCENE * 128
diff --git a/Misc/NEWS.d/next/Tests/2022-02-03-09-45-26.bpo-46623.vxzuhV.rst b/Misc/NEWS.d/next/Tests/2022-02-03-09-45-26.bpo-46623.vxzuhV.rst
new file mode 100644
index 0000000..be085c0
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2022-02-03-09-45-26.bpo-46623.vxzuhV.rst
@@ -0,0 +1,2 @@
+Skip test_pair() and test_speech128() of test_zlib on s390x since they fail
+if zlib uses the s390x hardware accelerator. Patch by Victor Stinner.
--
2.43.0

@ -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: 56%{?dist}
Release: 56%{?dist}.2
License: Python
@ -802,6 +802,27 @@ Patch399: 00399-cve-2023-24329.patch
# Backported from Python 3.8
Patch404: 00404-cve-2023-40217.patch
# 00408 #
# CVE-2022-48560
#
# Security fix for CVE-2022-48560: python3: use after free in heappushpop()
# of heapq module
# 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
# 00414 #
#
# Skip test_pair() and test_speech128() of test_zlib on s390x since
# they fail if zlib uses the s390x hardware accelerator.
Patch414: 00414-skip_test_zlib_s390x.patch
# (New patches go here ^^^)
#
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@ -1151,6 +1172,9 @@ git apply %{PATCH351}
%patch397 -p1
%patch399 -p1
%patch404 -p1
%patch408 -p1
%patch413 -p1
%patch414 -p1
# Remove files that should be generated by the build
# (This is after patching, so that we can use patches directly from upstream)
@ -2082,6 +2106,16 @@ fi
# ======================================================
%changelog
* Tue Dec 12 2023 Lumír Balhar <lbalhar@redhat.com> - 3.6.8-56.2
- Security fix for CVE-2022-48564
Resolves: RHEL-16673
- Skip tests failing on s390x
Resolves: RHEL-19251
* Thu Nov 23 2023 Lumír Balhar <lbalhar@redhat.com> - 3.6.8-56.1
- Security fix for CVE-2022-48560
Resolves: RHEL-16706
* Thu Sep 07 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-56
- Security fix for CVE-2023-40217
Resolves: RHEL-3041

Loading…
Cancel
Save