Skip to content

Commit 1e99714

Browse files
gh-138204: Forbid expansion of a shared anonymous mmap on Linux
This is a Linux kernel bug which caused a bus error. https://bugzilla.kernel.org/show_bug.cgi?id=8691
1 parent bbcb75c commit 1e99714

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

Lib/test/test_mmap.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,12 +500,81 @@ def test_anonymous(self):
500500
for x in range(PAGESIZE):
501501
self.assertEqual(m[x], 0,
502502
"anonymously mmap'ed contents should be zero")
503+
with self.assertRaises(IndexError):
504+
m[PAGESIZE]
503505

504506
for x in range(PAGESIZE):
505507
b = x & 0xff
506508
m[x] = b
507509
self.assertEqual(m[x], b)
508510

511+
if sys.platform.startswith('linux'):
512+
# Can't expand a shared anonymous mapping on Linux.
513+
# See https://bugzilla.kernel.org/show_bug.cgi?id=8691
514+
with self.assertRaises(ValueError):
515+
m.resize(2 * PAGESIZE)
516+
else:
517+
try:
518+
m.resize(2 * PAGESIZE)
519+
except SystemError:
520+
pass
521+
else:
522+
for x in range(PAGESIZE):
523+
self.assertEqual(m[x], x & 0xff)
524+
for x in range(PAGESIZE, 2 * PAGESIZE):
525+
self.assertEqual(m[x], 0)
526+
with self.assertRaises(IndexError):
527+
m[2 * PAGESIZE]
528+
529+
for x in range(PAGESIZE, 2 * PAGESIZE):
530+
b = x & 0xff
531+
m[x] = b
532+
self.assertEqual(m[x], b)
533+
534+
try:
535+
m.resize(PAGESIZE // 2)
536+
except SystemError:
537+
pass
538+
else:
539+
for x in range(PAGESIZE // 2):
540+
self.assertEqual(m[x], x & 0xff)
541+
with self.assertRaises(IndexError):
542+
m[PAGESIZE // 2]
543+
544+
if sys.platform.startswith('linux'):
545+
# Can't expand to its original size.
546+
with self.assertRaises(ValueError):
547+
m.resize(PAGESIZE)
548+
549+
def test_private_anonymous(self):
550+
m = mmap.mmap(-1, PAGESIZE, flags=mmap.MAP_PRIVATE)
551+
for x in range(PAGESIZE):
552+
self.assertEqual(m[x], 0)
553+
with self.assertRaises(IndexError):
554+
m[PAGESIZE]
555+
556+
for x in range(PAGESIZE):
557+
b = x & 0xff
558+
m[x] = b
559+
self.assertEqual(m[x], b)
560+
561+
try:
562+
m.resize(2 * PAGESIZE)
563+
except SystemError:
564+
pass
565+
else:
566+
for x in range(PAGESIZE):
567+
self.assertEqual(m[x], x & 0xff)
568+
for x in range(PAGESIZE, 2 * PAGESIZE):
569+
self.assertEqual(m[x], 0)
570+
with self.assertRaises(IndexError):
571+
m[2 * PAGESIZE]
572+
573+
for x in range(PAGESIZE, 2 * PAGESIZE):
574+
b = x & 0xff
575+
m[x] = b
576+
self.assertEqual(m[x], b)
577+
509578
def test_read_all(self):
510579
m = mmap.mmap(-1, 16)
511580
self.addCleanup(m.close)
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;
@@ -889,6 +890,13 @@ mmap_resize_method(PyObject *op, PyObject *args)
889890
#else
890891
void *newmap;
891892

893+
#ifdef __linux__
894+
if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) {
895+
PyErr_Format(PyExc_ValueError,
896+
"mmap: can't expand a shared anonymous mapping on Linux");
897+
return NULL;
898+
}
899+
#endif
892900
if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
893901
PyErr_SetFromErrno(PyExc_OSError);
894902
return NULL;
@@ -1685,6 +1693,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
16851693
else {
16861694
m_obj->fd = -1;
16871695
}
1696+
m_obj->flags = flags;
16881697

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

0 commit comments

Comments
 (0)