From c9b2513b57c996aa1d54659ef80cf504619db8ba Mon Sep 17 00:00:00 2001 From: Joekrry Date: Sun, 13 Sep 2026 16:11:38 +0100 Subject: [PATCH] gh-157335: Fixed out of bounds write in mmap.mmap.__setitem__. Assigning to a single index causes mmap.mmap.__setitem__ to validate the index against the object's size, which then converts the assigned value via PyNumber_AsSsize_t(). This invokes arbitrary python code via __index__(). mmap.resize(), which shrinks mapping could point past the end fo the new buffer causing an out of bounds error write. --- Lib/test/test_mmap.py | 18 ++++++++++++++++++ ...6-09-13-15-58-28.gh-issue-157335.efaMah.rst | 3 +++ Modules/mmapmodule.c | 7 +++++++ 3 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-09-13-15-58-28.gh-issue-157335.efaMah.rst diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 053a4ca4db53a5..5726ab84ee53c7 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -953,6 +953,24 @@ def test_resize_down_anonymous_mapping(self): with self.assertRaises(ValueError): m.resize(start_size) + def test_setitem_resize_reentrancy(self): + """Resizing the mmap from inside __index__ while assigning to a + single item must not access memory past the new bounds (gh-157335).""" + size = 2 * PAGESIZE + new_size = PAGESIZE + + class ResizeOnIndex: + def __init__(self, m): + self.m = m + def __index__(self): + self.m.resize(new_size) + return 0 + + with mmap.mmap(-1, size) as m: + with self.assertRaises(IndexError): + m[size - 1] = ResizeOnIndex(m) + self.assertEqual(len(m), new_size) + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_resize_fails_if_mapping_held_elsewhere(self): """If more than one mapping is held against a named file on Windows, neither diff --git a/Misc/NEWS.d/next/Library/2026-09-13-15-58-28.gh-issue-157335.efaMah.rst b/Misc/NEWS.d/next/Library/2026-09-13-15-58-28.gh-issue-157335.efaMah.rst new file mode 100644 index 00000000000000..090c6a9f91be93 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-13-15-58-28.gh-issue-157335.efaMah.rst @@ -0,0 +1,3 @@ +Fix out-of-bounds write in :meth:`mmap.mmap.__setitem__` that could occur +when the assigned value's :meth:`~object.__index__` method resized the +mmap object during the assignment. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 58f1e3b2ddcca7..4dc10b4aca65c7 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1687,6 +1687,13 @@ mmap_ass_subscript_lock_held(PyObject *op, PyObject *item, PyObject *value) return -1; } CHECK_VALID(-1); + /* value's __index__ may have resized the mmap, invalidating + * the earlier bounds check on i. */ + if (i >= self->size) { + PyErr_SetString(PyExc_IndexError, + "mmap index out of range"); + return -1; + } char v_char = (char) v; if (safe_byte_copy(self->data + i, &v_char) < 0) {