mirror of https://github.com/python/cpython
gh-106092: Fix use-after-free crash in frame_dealloc (#106875)
It was possible for the trashcan to delay the deallocation of a PyFrameObject until after its corresponding _PyInterpreterFrame has already been freed. So frame_dealloc needs to avoid dereferencing the f_frame pointer unless it first checks that the pointer still points to the interpreter frame within the frame object. Signed-off-by: Anders Kaseorg <andersk@mit.edu>
This commit is contained in:
parent
052a0d1106
commit
557b05c7a5
|
@ -0,0 +1,2 @@
|
|||
Fix a segmentation fault caused by a use-after-free bug in ``frame_dealloc``
|
||||
when the trashcan delays the deallocation of a ``PyFrameObject``.
|
|
@ -879,9 +879,6 @@ frame_dealloc(PyFrameObject *f)
|
|||
/* It is the responsibility of the owning generator/coroutine
|
||||
* to have cleared the generator pointer */
|
||||
|
||||
assert(f->f_frame->owner != FRAME_OWNED_BY_GENERATOR ||
|
||||
_PyFrame_GetGenerator(f->f_frame)->gi_frame_state == FRAME_CLEARED);
|
||||
|
||||
if (_PyObject_GC_IS_TRACKED(f)) {
|
||||
_PyObject_GC_UNTRACK(f);
|
||||
}
|
||||
|
@ -889,10 +886,14 @@ frame_dealloc(PyFrameObject *f)
|
|||
Py_TRASHCAN_BEGIN(f, frame_dealloc);
|
||||
PyObject *co = NULL;
|
||||
|
||||
/* Kill all local variables including specials, if we own them */
|
||||
if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
|
||||
assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data);
|
||||
/* GH-106092: If f->f_frame was on the stack and we reached the maximum
|
||||
* nesting depth for deallocations, the trashcan may have delayed this
|
||||
* deallocation until after f->f_frame is freed. Avoid dereferencing
|
||||
* f->f_frame unless we know it still points to valid memory. */
|
||||
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data;
|
||||
|
||||
/* Kill all local variables including specials, if we own them */
|
||||
if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
|
||||
/* Don't clear code object until the end */
|
||||
co = frame->f_executable;
|
||||
frame->f_executable = NULL;
|
||||
|
|
Loading…
Reference in New Issue