Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 33fcb0c

Browse files
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
1 parent c19db1d commit 33fcb0c

File tree

3 files changed

+62
-17
lines changed

3 files changed

+62
-17
lines changed

‎Lib/test/test_mmap.py

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -901,35 +901,69 @@ def test_madvise(self):
901901
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None)
902902
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None)
903903

904-
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
905-
def test_resize_up_when_mapped_to_pagefile(self):
904+
def test_resize_up_anonymous_mapping(self):
906905
"""If the mmap is backed by the pagefile ensure a resize up can happen
907906
and that the original data is still in place
908907
"""
909908
start_size = PAGESIZE
910909
new_size = 2 * start_size
911-
data = bytes(random.getrandbits(8) for_inrange(start_size))
910+
data = random.randbytes(start_size)
912911

913-
m = mmap.mmap(-1, start_size)
914-
m[:] = data
915-
m.resize(new_size)
916-
self.assertEqual(len(m), new_size)
917-
self.assertEqual(m[:start_size], data[:start_size])
912+
with mmap.mmap(-1, start_size) as m:
913+
m[:] = data
914+
if sys.platform.startswith(('linux', 'android')):
915+
# Can't expand a shared anonymous mapping on Linux.
916+
# See https://bugzilla.kernel.org/show_bug.cgi?id=8691
917+
with self.assertRaises(ValueError):
918+
m.resize(new_size)
919+
else:
920+
try:
921+
m.resize(new_size)
922+
except SystemError:
923+
pass
924+
else:
925+
self.assertEqual(len(m), new_size)
926+
self.assertEqual(m[:start_size], data)
927+
self.assertEqual(m[start_size:], b'0円' * (new_size - start_size))
918928

919-
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
920-
def test_resize_down_when_mapped_to_pagefile(self):
929+
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
930+
def test_resize_up_private_anonymous_mapping(self):
931+
start_size = PAGESIZE
932+
new_size = 2 * start_size
933+
data = random.randbytes(start_size)
934+
935+
with mmap.mmap(-1, start_size, flags=mmap.MAP_PRIVATE) as m:
936+
m[:] = data
937+
try:
938+
m.resize(new_size)
939+
except SystemError:
940+
pass
941+
else:
942+
self.assertEqual(len(m), new_size)
943+
self.assertEqual(m[:start_size], data)
944+
self.assertEqual(m[start_size:], b'0円' * (new_size - start_size))
945+
946+
def test_resize_down_anonymous_mapping(self):
921947
"""If the mmap is backed by the pagefile ensure a resize down up can happen
922948
and that a truncated form of the original data is still in place
923949
"""
924-
start_size = PAGESIZE
950+
start_size = 2*PAGESIZE
925951
new_size = start_size // 2
926-
data = bytes(random.getrandbits(8) for_inrange(start_size))
952+
data = random.randbytes(start_size)
927953

928-
m = mmap.mmap(-1, start_size)
929-
m[:] = data
930-
m.resize(new_size)
931-
self.assertEqual(len(m), new_size)
932-
self.assertEqual(m[:new_size], data[:new_size])
954+
with mmap.mmap(-1, start_size) as m:
955+
m[:] = data
956+
try:
957+
m.resize(new_size)
958+
except SystemError:
959+
pass
960+
else:
961+
self.assertEqual(len(m), new_size)
962+
self.assertEqual(m[:], data[:new_size])
963+
if sys.platform.startswith(('linux', 'android')):
964+
# Can't expand to its original size.
965+
with self.assertRaises(ValueError):
966+
m.resize(start_size)
933967

934968
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
935969
def test_resize_fails_if_mapping_held_elsewhere(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Forbid expansion of shared anonymous :mod:`memory maps <mmap>` on Linux,
2+
which caused a bus error.

‎Modules/mmapmodule.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ typedef struct {
120120
#ifdef UNIX
121121
int fd;
122122
_Bool trackfd;
123+
int flags;
123124
#endif
124125

125126
PyObject *weakreflist;
@@ -882,6 +883,13 @@ mmap_resize_method(PyObject *op, PyObject *args)
882883
#else
883884
void *newmap;
884885

886+
#ifdef __linux__
887+
if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) {
888+
PyErr_Format(PyExc_ValueError,
889+
"mmap: can't expand a shared anonymous mapping on Linux");
890+
return NULL;
891+
}
892+
#endif
885893
if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
886894
PyErr_SetFromErrno(PyExc_OSError);
887895
return NULL;
@@ -1678,6 +1686,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
16781686
else {
16791687
m_obj->fd = -1;
16801688
}
1689+
m_obj->flags = flags;
16811690

16821691
Py_BEGIN_ALLOW_THREADS
16831692
m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /