]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-142557: fix UAF in `bytearray.__mod__` when object is mutated while formatt...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 27 Dec 2025 15:23:08 +0000 (16:23 +0100)
committerGitHub <noreply@github.com>
Sat, 27 Dec 2025 15:23:08 +0000 (15:23 +0000)
gh-142557: fix UAF in `bytearray.__mod__` when object is mutated while formatting `%`-style arguments (GH-143213)
(cherry picked from commit 61ee04834b096be00678c6819b4957f3f4413a5e)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Lib/test/test_bytes.py
Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-12-25-06.gh-issue-142557.KWOc8b.rst [new file with mode: 0644]
Objects/bytearrayobject.c

index 54604376863d35d41e8b50800f294ef47d4e0b10..ce26700aa6dcbfeaa79f960ed4496024317ce88f 100644 (file)
@@ -1382,6 +1382,18 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase):
             except OSError:
                 pass
 
+    def test_mod_concurrent_mutation(self):
+        # Prevent crash in __mod__ when formatting mutates the bytearray.
+        # Regression test for https://github.com/python/cpython/issues/142557.
+        fmt = bytearray(b"%a end")
+
+        class S:
+            def __repr__(self):
+                fmt.clear()
+                return "E"
+
+        self.assertRaises(BufferError, fmt.__mod__, S())
+
     def test_reverse(self):
         b = bytearray(b'hello')
         self.assertEqual(b.reverse(), None)
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-12-25-06.gh-issue-142557.KWOc8b.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-12-25-06.gh-issue-142557.KWOc8b.rst
new file mode 100644 (file)
index 0000000..b7f7a58
--- /dev/null
@@ -0,0 +1,3 @@
+Fix a use-after-free crash in :ref:`bytearray.__mod__ <bytes-formatting>` when
+the :class:`!bytearray` is mutated while formatting the ``%``-style arguments.
+Patch by Bénédikt Tran.
index 3778a37daac818013af11a277f674943c9ac4ac7..ba4ad85201ecabfef01705b5587f3b12a7dc49c1 100644 (file)
@@ -2790,7 +2790,15 @@ bytearray_mod_lock_held(PyObject *v, PyObject *w)
     _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(v);
     if (!PyByteArray_Check(v))
         Py_RETURN_NOTIMPLEMENTED;
-    return _PyBytes_FormatEx(PyByteArray_AS_STRING(v), PyByteArray_GET_SIZE(v), w, 1);
+
+    PyByteArrayObject *self = _PyByteArray_CAST(v);
+    /* Increase exports to prevent bytearray storage from changing during op. */
+    self->ob_exports++;
+    PyObject *res = _PyBytes_FormatEx(
+        PyByteArray_AS_STRING(v), PyByteArray_GET_SIZE(v), w, 1
+    );
+    self->ob_exports--;
+    return res;
 }
 
 static PyObject *