gh-125984: fix use-after-free on fut->fut_{callback,context}0 due to an evil loop.__getattribute__ (#126003)

This commit is contained in:
Bénédikt Tran 2024-10-27 16:04:43 +01:00 committed by GitHub
parent 80eec52fc8
commit f819d4301d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 86 additions and 7 deletions

View file

@ -409,12 +409,19 @@ future_schedule_callbacks(asyncio_state *state, FutureObj *fut)
if (fut->fut_callback0 != NULL) {
/* There's a 1st callback */
int ret = call_soon(state,
fut->fut_loop, fut->fut_callback0,
(PyObject *)fut, fut->fut_context0);
// Beware: An evil call_soon could alter fut_callback0 or fut_context0.
// Since we are anyway clearing them after the call, whether call_soon
// succeeds or not, the idea is to transfer ownership so that external
// code is not able to alter them during the call.
PyObject *fut_callback0 = fut->fut_callback0;
fut->fut_callback0 = NULL;
PyObject *fut_context0 = fut->fut_context0;
fut->fut_context0 = NULL;
Py_CLEAR(fut->fut_callback0);
Py_CLEAR(fut->fut_context0);
int ret = call_soon(state, fut->fut_loop, fut_callback0,
(PyObject *)fut, fut_context0);
Py_CLEAR(fut_callback0);
Py_CLEAR(fut_context0);
if (ret) {
/* If an error occurs in pure-Python implementation,
all callbacks are cleared. */