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

gh-125984: fix use-after-free on `fut->fut_{callback,context}0` due to an evil `loop.__getattribute__` (GH-126003)
(cherry picked from commit f819d4301d)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2024-10-27 16:23:07 +01:00 committed by GitHub
parent 67b270142d
commit fdedb2618a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 86 additions and 7 deletions

View file

@ -433,12 +433,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. */