Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Lib/test/test_mmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 7 additions & 0 deletions Modules/mmapmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to not check the bounds twice. You can reorganize the code instead:

  • call PyNumber_AsSsize_t(item) + error check
  • call PyNumber_AsSsize_t(value) + error check
  • adjust i and check bounds
  • check v bounds
  • call safe_byte_copy()

Something like that.

PyErr_SetString(PyExc_IndexError,
"mmap index out of range");
return -1;
}
Comment on lines +1690 to +1696

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can have the same issue in the slice-branch when doing PyObject_GetBuffer(). So instead, we could make the checks inside the safe_byte_copy and safe_memcpy functions. Though I don't know if it's an overkill. Can you verify that the slice pah is also not affected by adding tests.


char v_char = (char) v;
if (safe_byte_copy(self->data + i, &v_char) < 0) {
Expand Down
Loading