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 06dbf81

Browse files
miss-islingtonserhiy-storchaka
andauthored
[3.13] gh-138204: Forbid expansion of a shared anonymous mmap on Linux (GH-138220) (GH-138387)
This is a Linux kernel bug which caused a bus error. https://bugzilla.kernel.org/show_bug.cgi?id=8691 (cherry picked from commit 33fcb0c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 154ec76 commit 06dbf81

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
@@ -899,35 +899,69 @@ def test_madvise(self):
899899
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None)
900900
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None)
901901

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

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

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

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

932966
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
933967
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;
@@ -871,6 +872,13 @@ mmap_resize_method(mmap_object *self,
871872
#else
872873
void *newmap;
873874

875+
#ifdef __linux__
876+
if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) {
877+
PyErr_Format(PyExc_ValueError,
878+
"mmap: can't expand a shared anonymous mapping on Linux");
879+
return NULL;
880+
}
881+
#endif
874882
if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
875883
PyErr_SetFromErrno(PyExc_OSError);
876884
return NULL;
@@ -1651,6 +1659,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
16511659
else {
16521660
m_obj->fd = -1;
16531661
}
1662+
m_obj->flags = flags;
16541663

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

0 commit comments

Comments
(0)

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