mirror of
https://github.com/python/cpython.git
synced 2026-01-06 15:32:22 +00:00
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
This commit is contained in:
parent
c19db1d2b8
commit
33fcb0c4a0
3 changed files with 62 additions and 17 deletions
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Forbid expansion of shared anonymous :mod:`memory maps <mmap>` on Linux,
|
||||
which caused a bus error.
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue