From 6550f17d50c8459347f7efcf43e78fff604df6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 27 Dec 2025 13:12:03 +0000 Subject: [PATCH] gh-142664: fix UAF in `memoryview.__hash__` via re-entrant data's `__hash__` (GH-143217) (cherry picked from commit 00e24b80e092e7d36dc189fd260b2a4e730a6e7f) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_memoryview.py | 14 ++++++++++++++ .../2025-12-27-13-18-12.gh-issue-142664.peeEDV.rst | 3 +++ Objects/memoryobject.c | 13 ++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-13-18-12.gh-issue-142664.peeEDV.rst diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 1bd58eb6408833..a88413e4bb1d9e 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -387,6 +387,20 @@ def test_hash_writable(self): m = self._view(b) self.assertRaises(ValueError, hash, m) + def test_hash_use_after_free(self): + # Prevent crash in memoryview(v).__hash__ with re-entrant v.__hash__. + # Regression test for https://github.com/python/cpython/issues/142664. + class E(array.array): + def __hash__(self): + mv.release() + self.clear() + return 123 + + v = E('B', b'A' * 4096) + mv = memoryview(v).toreadonly() # must be read-only for hash() + self.assertRaises(BufferError, hash, mv) + self.assertRaises(BufferError, mv.__hash__) + def test_weakref(self): # Check memoryviews are weakrefable for tp in self._types: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-13-18-12.gh-issue-142664.peeEDV.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-13-18-12.gh-issue-142664.peeEDV.rst new file mode 100644 index 00000000000000..39c218395cc4d3 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-13-18-12.gh-issue-142664.peeEDV.rst @@ -0,0 +1,3 @@ +Fix a use-after-free crash in :meth:`memoryview.__hash__ ` +when the ``__hash__`` method of the referenced object mutates that object or +the view. Patch by Bénédikt Tran. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index cf673fb379edcd..cf570d091102f3 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -3222,9 +3222,16 @@ memory_hash(PyObject *_self) "memoryview: hashing is restricted to formats 'B', 'b' or 'c'"); return -1; } - if (view->obj != NULL && PyObject_Hash(view->obj) == -1) { - /* Keep the original error message */ - return -1; + if (view->obj != NULL) { + // Prevent 'self' from being freed when computing the item's hash. + // See https://github.com/python/cpython/issues/142664. + self->exports++; + int rc = PyObject_Hash(view->obj); + self->exports--; + if (rc == -1) { + /* Keep the original error message */ + return -1; + } } if (!MV_C_CONTIGUOUS(self->flags)) {