https://github.com/python/cpython/commit/33fcb0c4a054f646d9d3686c145209a893b09bb0 commit: 33fcb0c4a054f646d9d3686c145209a893b09bb0 branch: main author: Serhiy Storchaka <storch...@gmail.com> committer: serhiy-storchaka <storch...@gmail.com> date: 2025-09-02T19:00:39+03:00 summary:
gh-138204: Forbid expansion of a shared anonymous mmap on Linux (GH-138220) This is a Linux kernel bug which caused a bus error. https://bugzilla.kernel.org/show_bug.cgi?id=8691 files: A Misc/NEWS.d/next/Library/2025-08-28-13-20-09.gh-issue-138204.8oLOud.rst M Lib/test/test_mmap.py M Modules/mmapmodule.c diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index b2a299ed172967..38d1a496c30e21 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -901,35 +901,69 @@ def test_madvise(self): self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None) - @unittest.skipUnless(os.name == 'nt', 'requires Windows') - def test_resize_up_when_mapped_to_pagefile(self): + def test_resize_up_anonymous_mapping(self): """If the mmap is backed by the pagefile ensure a resize up can happen and that the original data is still in place """ start_size = PAGESIZE new_size = 2 * start_size - data = bytes(random.getrandbits(8) for _ in range(start_size)) + data = random.randbytes(start_size) - m = mmap.mmap(-1, start_size) - m[:] = data - m.resize(new_size) - self.assertEqual(len(m), new_size) - self.assertEqual(m[:start_size], data[:start_size]) + with mmap.mmap(-1, start_size) as m: + m[:] = data + if sys.platform.startswith(('linux', 'android')): + # Can't expand a shared anonymous mapping on Linux. + # See https://bugzilla.kernel.org/show_bug.cgi?id=8691 + with self.assertRaises(ValueError): + m.resize(new_size) + else: + try: + m.resize(new_size) + except SystemError: + pass + else: + self.assertEqual(len(m), new_size) + self.assertEqual(m[:start_size], data) + self.assertEqual(m[start_size:], b'\0' * (new_size - start_size)) - @unittest.skipUnless(os.name == 'nt', 'requires Windows') - def test_resize_down_when_mapped_to_pagefile(self): + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_resize_up_private_anonymous_mapping(self): + start_size = PAGESIZE + new_size = 2 * start_size + data = random.randbytes(start_size) + + with mmap.mmap(-1, start_size, flags=mmap.MAP_PRIVATE) as m: + m[:] = data + try: + m.resize(new_size) + except SystemError: + pass + else: + self.assertEqual(len(m), new_size) + self.assertEqual(m[:start_size], data) + self.assertEqual(m[start_size:], b'\0' * (new_size - start_size)) + + def test_resize_down_anonymous_mapping(self): """If the mmap is backed by the pagefile ensure a resize down up can happen and that a truncated form of the original data is still in place """ - start_size = PAGESIZE + start_size = 2 * PAGESIZE new_size = start_size // 2 - data = bytes(random.getrandbits(8) for _ in range(start_size)) + data = random.randbytes(start_size) - m = mmap.mmap(-1, start_size) - m[:] = data - m.resize(new_size) - self.assertEqual(len(m), new_size) - self.assertEqual(m[:new_size], data[:new_size]) + with mmap.mmap(-1, start_size) as m: + m[:] = data + try: + m.resize(new_size) + except SystemError: + pass + else: + self.assertEqual(len(m), new_size) + self.assertEqual(m[:], data[:new_size]) + if sys.platform.startswith(('linux', 'android')): + # Can't expand to its original size. + with self.assertRaises(ValueError): + m.resize(start_size) @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_resize_fails_if_mapping_held_elsewhere(self): diff --git a/Misc/NEWS.d/next/Library/2025-08-28-13-20-09.gh-issue-138204.8oLOud.rst b/Misc/NEWS.d/next/Library/2025-08-28-13-20-09.gh-issue-138204.8oLOud.rst new file mode 100644 index 00000000000000..8eb5497f5da545 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-28-13-20-09.gh-issue-138204.8oLOud.rst @@ -0,0 +1,2 @@ +Forbid expansion of shared anonymous :mod:`memory maps <mmap>` on Linux, +which caused a bus error. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8413ebe668dffe..5d5b53717c829c 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -120,6 +120,7 @@ typedef struct { #ifdef UNIX int fd; _Bool trackfd; + int flags; #endif PyObject *weakreflist; @@ -882,6 +883,13 @@ mmap_resize_method(PyObject *op, PyObject *args) #else void *newmap; +#ifdef __linux__ + if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) { + PyErr_Format(PyExc_ValueError, + "mmap: can't expand a shared anonymous mapping on Linux"); + return NULL; + } +#endif if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -1678,6 +1686,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) else { m_obj->fd = -1; } + m_obj->flags = flags; Py_BEGIN_ALLOW_THREADS m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset); _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: arch...@mail-archive.com