Bug#1065326: bookworm-pu: package python3.11/3.11.2-6+deb12u1
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: python3.11@packages.debian.org, doko@debian.org
Control: affects -1 + src:python3.11
User: release.debian.org@packages.debian.org
Usertags: pu
[ Reason ]
A use-after-free causing a SEGV was found in python 3.11, affecting the
the Zulip chat server.
The bug is known to affect python 3.11.0 - 3.11.4. And since being fixed
upstream, there have been no known related regressions.
[ Impact ]
Potential SEGV in python3. Known to be triggered by zulip's CI when
running under coverage.
[ Tests ]
The Python stdlib testsuite is extensive and passes with this patch.
There is a stand-alone reproducer that I've manually reproduced the bug
with and verified that it's fixed.
[ Risks ]
The code is pretty straight-forward. It asserts that the f_frame hasn't
already been freed before freeing.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
diff -Nru python3.11-3.11.2/debian/changelog python3.11-3.11.2/debian/changelog
--- python3.11-3.11.2/debian/changelog 2023-03-13 08:18:29.000000000 -0400
+++ python3.11-3.11.2/debian/changelog 2024-03-02 16:28:50.000000000 -0400
@@ -1,3 +1,11 @@
+python3.11 (3.11.2-6+deb12u1) bookworm; urgency=medium
+
+ [ Anders Kaseorg ]
+ * Fix a use-after-free crash when deallocating a frame object
+ (closes: #1050843).
+
+ -- Stefano Rivera <stefanor@debian.org> Sat, 02 Mar 2024 16:28:50 -0400
+
python3.11 (3.11.2-6) unstable; urgency=high
[ Stefano Rivera ]
diff -Nru python3.11-3.11.2/debian/patches/frame_dealloc-crash.diff python3.11-3.11.2/debian/patches/frame_dealloc-crash.diff
--- python3.11-3.11.2/debian/patches/frame_dealloc-crash.diff 1969-12-31 20:00:00.000000000 -0400
+++ python3.11-3.11.2/debian/patches/frame_dealloc-crash.diff 2024-03-02 16:28:50.000000000 -0400
@@ -0,0 +1,54 @@
+Description: Fix use-after-free crash in frame_dealloc
+ 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.
+Origin: https://github.com/python/cpython/commit/46cae02085311481dc8b1ea9a5110969d9325bc7
+Bug-upstream: https://github.com/python/cpython/issues/106092
+Bug-Debian: https://bugs.debian.org/1050843
+Author: Anders Kaseorg <andersk@mit.edu>
+Last-Update: 2023-08-29
+Applied-Upstream: 3.11.5
+
+---
+ .../2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst | 2 ++
+ Objects/frameobject.c | 13 +++++++------
+ 2 files changed, 9 insertions(+), 6 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst
+
+--- /dev/null
++++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst
+@@ -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``.
+--- a/Objects/frameobject.c
++++ b/Objects/frameobject.c
+@@ -851,9 +851,6 @@
+ /* 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);
+ }
+@@ -861,10 +858,14 @@
+ Py_TRASHCAN_BEGIN(f, frame_dealloc);
+ PyCodeObject *co = NULL;
+
++ /* 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->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
+- assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data);
+- _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data;
++ if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
+ /* Don't clear code object until the end */
+ co = frame->f_code;
+ frame->f_code = NULL;
diff -Nru python3.11-3.11.2/debian/patches/series python3.11-3.11.2/debian/patches/series
--- python3.11-3.11.2/debian/patches/series 2023-03-01 05:58:01.000000000 -0400
+++ python3.11-3.11.2/debian/patches/series 2024-03-02 16:28:50.000000000 -0400
@@ -39,3 +39,4 @@
fix-py_compile.diff
ntpath-import.diff
shutdown-deadlock.diff
+frame_dealloc-crash.diff
Reply to: