mirror of
https://git.yoctoproject.org/poky
synced 2026-02-26 11:29:40 +01:00
python3: patch CVE-2025-13837
Pick patch from 3.12 branch per NVD report. (From OE-Core rev: 37936e0e93ab5c236d8cc8e709ba1faf8380577c) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
8d61eb390a
commit
534b2c966a
162
meta/recipes-devtools/python/python3/CVE-2025-13837.patch
Normal file
162
meta/recipes-devtools/python/python3/CVE-2025-13837.patch
Normal file
@@ -0,0 +1,162 @@
|
||||
From 5a8b19677d818fb41ee55f310233772e15aa1a2b Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Mon, 22 Dec 2025 15:49:44 +0200
|
||||
Subject: [PATCH] [3.12] gh-119342: Fix a potential denial of service in
|
||||
plistlib (GH-119343) (#142149)
|
||||
|
||||
Reading a specially prepared small Plist file could cause OOM because file's
|
||||
read(n) preallocates a bytes object for reading the specified amount of
|
||||
data. Now plistlib reads large data by chunks, therefore the upper limit of
|
||||
consumed memory is proportional to the size of the input file.
|
||||
(cherry picked from commit 694922cf40aa3a28f898b5f5ee08b71b4922df70)
|
||||
|
||||
CVE: CVE-2025-13837
|
||||
Upstream-Status: Backport [https://github.com/python/cpython/commit/5a8b19677d818fb41ee55f310233772e15aa1a2b]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
Lib/plistlib.py | 31 ++++++++++------
|
||||
Lib/test/test_plistlib.py | 37 +++++++++++++++++--
|
||||
...-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst | 5 +++
|
||||
3 files changed, 59 insertions(+), 14 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
|
||||
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
|
||||
index 3292c30d5f..c5554ea1f7 100644
|
||||
--- a/Lib/plistlib.py
|
||||
+++ b/Lib/plistlib.py
|
||||
@@ -73,6 +73,9 @@ from xml.parsers.expat import ParserCreate
|
||||
PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
|
||||
globals().update(PlistFormat.__members__)
|
||||
|
||||
+# Data larger than this will be read in chunks, to prevent extreme
|
||||
+# overallocation.
|
||||
+_MIN_READ_BUF_SIZE = 1 << 20
|
||||
|
||||
class UID:
|
||||
def __init__(self, data):
|
||||
@@ -499,12 +502,24 @@ class _BinaryPlistParser:
|
||||
|
||||
return tokenL
|
||||
|
||||
+ def _read(self, size):
|
||||
+ cursize = min(size, _MIN_READ_BUF_SIZE)
|
||||
+ data = self._fp.read(cursize)
|
||||
+ while True:
|
||||
+ if len(data) != cursize:
|
||||
+ raise InvalidFileException
|
||||
+ if cursize == size:
|
||||
+ return data
|
||||
+ delta = min(cursize, size - cursize)
|
||||
+ data += self._fp.read(delta)
|
||||
+ cursize += delta
|
||||
+
|
||||
def _read_ints(self, n, size):
|
||||
- data = self._fp.read(size * n)
|
||||
+ data = self._read(size * n)
|
||||
if size in _BINARY_FORMAT:
|
||||
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
|
||||
else:
|
||||
- if not size or len(data) != size * n:
|
||||
+ if not size:
|
||||
raise InvalidFileException()
|
||||
return tuple(int.from_bytes(data[i: i + size], 'big')
|
||||
for i in range(0, size * n, size))
|
||||
@@ -561,22 +576,16 @@ class _BinaryPlistParser:
|
||||
|
||||
elif tokenH == 0x40: # data
|
||||
s = self._get_size(tokenL)
|
||||
- result = self._fp.read(s)
|
||||
- if len(result) != s:
|
||||
- raise InvalidFileException()
|
||||
+ result = self._read(s)
|
||||
|
||||
elif tokenH == 0x50: # ascii string
|
||||
s = self._get_size(tokenL)
|
||||
- data = self._fp.read(s)
|
||||
- if len(data) != s:
|
||||
- raise InvalidFileException()
|
||||
+ data = self._read(s)
|
||||
result = data.decode('ascii')
|
||||
|
||||
elif tokenH == 0x60: # unicode string
|
||||
s = self._get_size(tokenL) * 2
|
||||
- data = self._fp.read(s)
|
||||
- if len(data) != s:
|
||||
- raise InvalidFileException()
|
||||
+ data = self._read(s)
|
||||
result = data.decode('utf-16be')
|
||||
|
||||
elif tokenH == 0x80: # UID
|
||||
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
|
||||
index fa46050658..229a5a242e 100644
|
||||
--- a/Lib/test/test_plistlib.py
|
||||
+++ b/Lib/test/test_plistlib.py
|
||||
@@ -841,8 +841,7 @@ class TestPlistlib(unittest.TestCase):
|
||||
|
||||
class TestBinaryPlistlib(unittest.TestCase):
|
||||
|
||||
- @staticmethod
|
||||
- def decode(*objects, offset_size=1, ref_size=1):
|
||||
+ def build(self, *objects, offset_size=1, ref_size=1):
|
||||
data = [b'bplist00']
|
||||
offset = 8
|
||||
offsets = []
|
||||
@@ -854,7 +853,11 @@ class TestBinaryPlistlib(unittest.TestCase):
|
||||
len(objects), 0, offset)
|
||||
data.extend(offsets)
|
||||
data.append(tail)
|
||||
- return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY)
|
||||
+ return b''.join(data)
|
||||
+
|
||||
+ def decode(self, *objects, offset_size=1, ref_size=1):
|
||||
+ data = self.build(*objects, offset_size=offset_size, ref_size=ref_size)
|
||||
+ return plistlib.loads(data, fmt=plistlib.FMT_BINARY)
|
||||
|
||||
def test_nonstandard_refs_size(self):
|
||||
# Issue #21538: Refs and offsets are 24-bit integers
|
||||
@@ -963,6 +966,34 @@ class TestBinaryPlistlib(unittest.TestCase):
|
||||
with self.assertRaises(plistlib.InvalidFileException):
|
||||
plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
|
||||
|
||||
+ def test_truncated_large_data(self):
|
||||
+ self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
||||
+ def check(data):
|
||||
+ with open(os_helper.TESTFN, 'wb') as f:
|
||||
+ f.write(data)
|
||||
+ # buffered file
|
||||
+ with open(os_helper.TESTFN, 'rb') as f:
|
||||
+ with self.assertRaises(plistlib.InvalidFileException):
|
||||
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
|
||||
+ # unbuffered file
|
||||
+ with open(os_helper.TESTFN, 'rb', buffering=0) as f:
|
||||
+ with self.assertRaises(plistlib.InvalidFileException):
|
||||
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
|
||||
+ for w in range(20, 64):
|
||||
+ s = 1 << w
|
||||
+ # data
|
||||
+ check(self.build(b'\x4f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # ascii string
|
||||
+ check(self.build(b'\x5f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # unicode string
|
||||
+ check(self.build(b'\x6f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # array
|
||||
+ check(self.build(b'\xaf\x13' + s.to_bytes(8, 'big')))
|
||||
+ # dict
|
||||
+ check(self.build(b'\xdf\x13' + s.to_bytes(8, 'big')))
|
||||
+ # number of objects
|
||||
+ check(b'bplist00' + struct.pack('>6xBBQQQ', 1, 1, s, 0, 8))
|
||||
+
|
||||
|
||||
class TestKeyedArchive(unittest.TestCase):
|
||||
def test_keyed_archive_data(self):
|
||||
diff --git a/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
new file mode 100644
|
||||
index 0000000000..04fd8faca4
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
@@ -0,0 +1,5 @@
|
||||
+Fix a potential memory denial of service in the :mod:`plistlib` module.
|
||||
+When reading a Plist file received from untrusted source, it could cause
|
||||
+an arbitrary amount of memory to be allocated.
|
||||
+This could have led to symptoms including a :exc:`MemoryError`, swapping, out
|
||||
+of memory (OOM) killed processes or containers, or even system crashes.
|
||||
Reference in New Issue
Block a user