Skip to content

Commit 3173493

Browse files
picnixzmiss-islington
authored andcommitted
gh-142557: fix UAF in bytearray.__mod__ when object is mutated while formatting %-style arguments (GH-143213)
(cherry picked from commit 61ee048) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent bbe9ed9 commit 3173493

File tree

3 files changed

+24
-1
lines changed

3 files changed

+24
-1
lines changed

Lib/test/test_bytes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,18 @@ def test_bytearray_api(self):
13821382
except OSError:
13831383
pass
13841384

1385+
def test_mod_concurrent_mutation(self):
1386+
# Prevent crash in __mod__ when formatting mutates the bytearray.
1387+
# Regression test for https://github.com/python/cpython/issues/142557.
1388+
fmt = bytearray(b"%a end")
1389+
1390+
class S:
1391+
def __repr__(self):
1392+
fmt.clear()
1393+
return "E"
1394+
1395+
self.assertRaises(BufferError, fmt.__mod__, S())
1396+
13851397
def test_reverse(self):
13861398
b = bytearray(b'hello')
13871399
self.assertEqual(b.reverse(), None)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a use-after-free crash in :ref:`bytearray.__mod__ <bytes-formatting>` when
2+
the :class:`!bytearray` is mutated while formatting the ``%``-style arguments.
3+
Patch by Bénédikt Tran.

Objects/bytearrayobject.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2790,7 +2790,15 @@ bytearray_mod_lock_held(PyObject *v, PyObject *w)
27902790
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(v);
27912791
if (!PyByteArray_Check(v))
27922792
Py_RETURN_NOTIMPLEMENTED;
2793-
return _PyBytes_FormatEx(PyByteArray_AS_STRING(v), PyByteArray_GET_SIZE(v), w, 1);
2793+
2794+
PyByteArrayObject *self = _PyByteArray_CAST(v);
2795+
/* Increase exports to prevent bytearray storage from changing during op. */
2796+
self->ob_exports++;
2797+
PyObject *res = _PyBytes_FormatEx(
2798+
PyByteArray_AS_STRING(v), PyByteArray_GET_SIZE(v), w, 1
2799+
);
2800+
self->ob_exports--;
2801+
return res;
27942802
}
27952803

27962804
static PyObject *

0 commit comments

Comments
 (0)