Skip to content

Commit 4fcb1d9

Browse files
authored
[3.13] gh-142664: fix UAF in memoryview.__hash__ via re-entrant data's __hash__ (GH-143217) (#143222)
(cherry picked from commit 00e24b8)
1 parent 8aca2fd commit 4fcb1d9

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

Lib/test/test_memoryview.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,20 @@ def test_hash_writable(self):
344344
m = self._view(b)
345345
self.assertRaises(ValueError, hash, m)
346346

347+
def test_hash_use_after_free(self):
348+
# Prevent crash in memoryview(v).__hash__ with re-entrant v.__hash__.
349+
# Regression test for https://github.com/python/cpython/issues/142664.
350+
class E(array.array):
351+
def __hash__(self):
352+
mv.release()
353+
self.clear()
354+
return 123
355+
356+
v = E('B', b'A' * 4096)
357+
mv = memoryview(v).toreadonly() # must be read-only for hash()
358+
self.assertRaises(BufferError, hash, mv)
359+
self.assertRaises(BufferError, mv.__hash__)
360+
347361
def test_weakref(self):
348362
# Check memoryviews are weakrefable
349363
for tp in self._types:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a use-after-free crash in :meth:`memoryview.__hash__ <object.__hash__>`
2+
when the ``__hash__`` method of the referenced object mutates that object or
3+
the view. Patch by Bénédikt Tran.

Objects/memoryobject.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3074,9 +3074,16 @@ memory_hash(PyObject *_self)
30743074
"memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
30753075
return -1;
30763076
}
3077-
if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
3078-
/* Keep the original error message */
3079-
return -1;
3077+
if (view->obj != NULL) {
3078+
// Prevent 'self' from being freed when computing the item's hash.
3079+
// See https://github.com/python/cpython/issues/142664.
3080+
self->exports++;
3081+
int rc = PyObject_Hash(view->obj);
3082+
self->exports--;
3083+
if (rc == -1) {
3084+
/* Keep the original error message */
3085+
return -1;
3086+
}
30803087
}
30813088

30823089
if (!MV_C_CONTIGUOUS(self->flags)) {

0 commit comments

Comments
 (0)