From f58d5ab881541f2b244fe991dcbfbb749604692b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Nov 2024 09:09:18 +0100 Subject: [PATCH] [3.13] gh-126138: Fix use-after-free in `_asyncio.Task` by evil `__getattribute__` (GH-126305) (#126324) gh-126138: Fix use-after-free in `_asyncio.Task` by evil `__getattribute__` (GH-126305) (cherry picked from commit f032f6ba8fec6fab35edeec0eb40cd73e9d58928) Co-authored-by: Nico-Posada <102486290+Nico-Posada@users.noreply.github.com> Co-authored-by: Carol Willing --- ...-11-01-14-31-41.gh-issue-126138.yTniOG.rst | 3 +++ Modules/_asynciomodule.c | 22 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-11-01-14-31-41.gh-issue-126138.yTniOG.rst diff --git a/Misc/NEWS.d/next/Library/2024-11-01-14-31-41.gh-issue-126138.yTniOG.rst b/Misc/NEWS.d/next/Library/2024-11-01-14-31-41.gh-issue-126138.yTniOG.rst new file mode 100644 index 00000000000..459eebc82bd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-01-14-31-41.gh-issue-126138.yTniOG.rst @@ -0,0 +1,3 @@ +Fix a use-after-free crash on :class:`asyncio.Task` objects +whose underlying coroutine yields an object that implements +an evil :meth:`~object.__getattribute__`. Patch by Nico Posada. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 40fe7d83955..79896c6b9fd 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2907,8 +2907,17 @@ task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *resu if (task->task_must_cancel) { PyObject *r; int is_true; + + // Beware: An evil `__getattribute__` could + // prematurely delete task->task_cancel_msg before the + // task is cancelled, thereby causing a UAF crash. + // + // See https://github.com/python/cpython/issues/126138 + PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg); r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel), - task->task_cancel_msg); + task_cancel_msg); + Py_DECREF(task_cancel_msg); + if (r == NULL) { return NULL; } @@ -3000,8 +3009,17 @@ task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *resu if (task->task_must_cancel) { PyObject *r; int is_true; + + // Beware: An evil `__getattribute__` could + // prematurely delete task->task_cancel_msg before the + // task is cancelled, thereby causing a UAF crash. + // + // See https://github.com/python/cpython/issues/126138 + PyObject *task_cancel_msg = Py_NewRef(task->task_cancel_msg); r = PyObject_CallMethodOneArg(result, &_Py_ID(cancel), - task->task_cancel_msg); + task_cancel_msg); + Py_DECREF(task_cancel_msg); + if (r == NULL) { return NULL; }