Skip to content

Commit 485a83c

Browse files
committed
Merge branch 'main' into fix/bytearray/uaf-in-mod-142557
2 parents e209539 + 3a728e5 commit 485a83c

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

Lib/test/test_memoryview.py

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

390+
def test_hash_use_after_free(self):
391+
# Prevent crash in memoryview(v).__hash__ with re-entrant v.__hash__.
392+
# Regression test for https://github.com/python/cpython/issues/142664.
393+
class E(array.array):
394+
def __hash__(self):
395+
mv.release()
396+
self.clear()
397+
return 123
398+
399+
v = E('B', b'A' * 4096)
400+
mv = memoryview(v).toreadonly() # must be read-only for hash()
401+
self.assertRaises(BufferError, hash, mv)
402+
self.assertRaises(BufferError, mv.__hash__)
403+
390404
def test_weakref(self):
391405
# Check memoryviews are weakrefable
392406
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.

Modules/_remote_debugging/module.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ _remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self)
947947
}
948948

949949
/*[clinic input]
950+
@permit_long_docstring_body
950951
@critical_section
951952
_remote_debugging.RemoteUnwinder.pause_threads
952953
@@ -963,7 +964,7 @@ Returns True if threads were successfully paused, False if they were already pau
963964

964965
static PyObject *
965966
_remote_debugging_RemoteUnwinder_pause_threads_impl(RemoteUnwinderObject *self)
966-
/*[clinic end generated code: output=aaf2bdc0a725750c input=78601c60dbc245fe]*/
967+
/*[clinic end generated code: output=aaf2bdc0a725750c input=d8a266f19a81c67e]*/
967968
{
968969
#ifdef Py_REMOTE_DEBUG_SUPPORTS_BLOCKING
969970
if (self->threads_stopped) {
@@ -985,6 +986,7 @@ _remote_debugging_RemoteUnwinder_pause_threads_impl(RemoteUnwinderObject *self)
985986
}
986987

987988
/*[clinic input]
989+
@permit_long_docstring_body
988990
@critical_section
989991
_remote_debugging.RemoteUnwinder.resume_threads
990992
@@ -997,7 +999,7 @@ Returns True if threads were successfully resumed, False if they were not paused
997999

9981000
static PyObject *
9991001
_remote_debugging_RemoteUnwinder_resume_threads_impl(RemoteUnwinderObject *self)
1000-
/*[clinic end generated code: output=8d6781ea37095536 input=67ca813bd804289e]*/
1002+
/*[clinic end generated code: output=8d6781ea37095536 input=16baaaab007f4259]*/
10011003
{
10021004
#ifdef Py_REMOTE_DEBUG_SUPPORTS_BLOCKING
10031005
if (!self->threads_stopped) {
@@ -1261,6 +1263,7 @@ class _remote_debugging.BinaryWriter "BinaryWriterObject *" "&PyBinaryWriter_Typ
12611263
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e948838b90a2003c]*/
12621264

12631265
/*[clinic input]
1266+
@permit_long_docstring_body
12641267
_remote_debugging.BinaryWriter.__init__
12651268
filename: str
12661269
sample_interval_us: unsigned_long_long
@@ -1285,7 +1288,7 @@ _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self,
12851288
unsigned long long sample_interval_us,
12861289
unsigned long long start_time_us,
12871290
int compression)
1288-
/*[clinic end generated code: output=014c0306f1bacf4b input=57497fe3cb9214a6]*/
1291+
/*[clinic end generated code: output=014c0306f1bacf4b input=3bdf01c1cc2f5a1d]*/
12891292
{
12901293
if (self->writer) {
12911294
binary_writer_destroy(self->writer);
@@ -1300,6 +1303,7 @@ _remote_debugging_BinaryWriter___init___impl(BinaryWriterObject *self,
13001303
}
13011304

13021305
/*[clinic input]
1306+
@permit_long_docstring_body
13031307
_remote_debugging.BinaryWriter.write_sample
13041308
stack_frames: object
13051309
timestamp_us: unsigned_long_long
@@ -1315,7 +1319,7 @@ static PyObject *
13151319
_remote_debugging_BinaryWriter_write_sample_impl(BinaryWriterObject *self,
13161320
PyObject *stack_frames,
13171321
unsigned long long timestamp_us)
1318-
/*[clinic end generated code: output=24d5b86679b4128f input=dce3148417482624]*/
1322+
/*[clinic end generated code: output=24d5b86679b4128f input=4e6d832d360bea46]*/
13191323
{
13201324
if (!self->writer) {
13211325
PyErr_SetString(PyExc_ValueError, "Writer is closed");
@@ -1422,6 +1426,7 @@ _remote_debugging_BinaryWriter___exit___impl(BinaryWriterObject *self,
14221426
}
14231427

14241428
/*[clinic input]
1429+
@permit_long_docstring_body
14251430
_remote_debugging.BinaryWriter.get_stats
14261431
14271432
Get encoding statistics for the writer.
@@ -1432,7 +1437,7 @@ record counts, frames written/saved, and compression ratio.
14321437

14331438
static PyObject *
14341439
_remote_debugging_BinaryWriter_get_stats_impl(BinaryWriterObject *self)
1435-
/*[clinic end generated code: output=06522cd52544df89 input=82968491b53ad277]*/
1440+
/*[clinic end generated code: output=06522cd52544df89 input=837c874ffdebd24c]*/
14361441
{
14371442
if (!self->writer) {
14381443
PyErr_SetString(PyExc_ValueError, "Writer is closed");
@@ -1754,6 +1759,7 @@ _remote_debugging_zstd_available_impl(PyObject *module)
17541759
* ============================================================================ */
17551760

17561761
/*[clinic input]
1762+
@permit_long_docstring_body
17571763
_remote_debugging.get_child_pids
17581764
17591765
pid: int
@@ -1779,7 +1785,7 @@ Child processes may exit or new ones may be created after the list is returned.
17791785
static PyObject *
17801786
_remote_debugging_get_child_pids_impl(PyObject *module, int pid,
17811787
int recursive)
1782-
/*[clinic end generated code: output=1ae2289c6b953e4b input=3395cbe7f17066c9]*/
1788+
/*[clinic end generated code: output=1ae2289c6b953e4b input=19d8d5d6e2b59e6e]*/
17831789
{
17841790
return enumerate_child_pids((pid_t)pid, recursive);
17851791
}

Objects/memoryobject.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,9 +3231,16 @@ memory_hash(PyObject *_self)
32313231
"memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
32323232
return -1;
32333233
}
3234-
if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
3235-
/* Keep the original error message */
3236-
return -1;
3234+
if (view->obj != NULL) {
3235+
// Prevent 'self' from being freed when computing the item's hash.
3236+
// See https://github.com/python/cpython/issues/142664.
3237+
self->exports++;
3238+
int rc = PyObject_Hash(view->obj);
3239+
self->exports--;
3240+
if (rc == -1) {
3241+
/* Keep the original error message */
3242+
return -1;
3243+
}
32373244
}
32383245

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

Python/remote_debug.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ static void
154154
_Py_RemoteDebug_FreePageCache(proc_handle_t *handle)
155155
{
156156
for (int i = 0; i < MAX_PAGES; i++) {
157-
PyMem_RawFree(handle->pages[i].data);
157+
if (handle->pages[i].data) {
158+
PyMem_RawFree(handle->pages[i].data);
159+
}
158160
handle->pages[i].data = NULL;
159161
handle->pages[i].valid = 0;
160162
}

0 commit comments

Comments
 (0)