106 lines
4.3 KiB
Text
106 lines
4.3 KiB
Text
Make the CPython bootstrap W^X compatible.
|
|
|
|
Index: rpython/rlib/rmmap.py
|
|
--- rpython/rlib/rmmap.py.orig
|
|
+++ rpython/rlib/rmmap.py
|
|
@@ -166,6 +166,9 @@ if _POSIX:
|
|
_, c_madvise_safe = external('madvise', [PTR, size_t, rffi.INT],
|
|
rffi.INT, _nowrapper=True)
|
|
|
|
+ c_mprotect, _ = external('mprotect',
|
|
+ [PTR, size_t, rffi.INT], rffi.INT)
|
|
+
|
|
# this one is always safe
|
|
_pagesize = rffi_platform.getintegerfunctionresult('getpagesize',
|
|
includes=includes)
|
|
@@ -717,6 +720,25 @@ if _POSIX:
|
|
prot = NonConstant(prot)
|
|
return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
|
|
|
|
+ def alloc_hinted_noexec(hintp, map_size):
|
|
+ """Same as alloc_hinted, but allocates pages non-executable.
|
|
+ Duplicated because of constancy constraints on prot."""
|
|
+
|
|
+ flags = MAP_PRIVATE | MAP_ANONYMOUS
|
|
+ prot = PROT_READ | PROT_WRITE
|
|
+
|
|
+ if we_are_translated():
|
|
+ flags = NonConstant(flags)
|
|
+ prot = NonConstant(prot)
|
|
+ return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
|
|
+
|
|
+ def set_pages_executable(addr, size):
|
|
+ from rpython.rlib import debug
|
|
+
|
|
+ rv = c_mprotect(addr, size, PROT_EXEC)
|
|
+ if rv < 0:
|
|
+ debug.fatalerror_notb("set_pages_executable failed")
|
|
+
|
|
def clear_large_memory_chunk_aligned(addr, map_size):
|
|
addr = rffi.cast(PTR, addr)
|
|
flags = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
|
|
@@ -732,10 +754,44 @@ if _POSIX:
|
|
pos = -0x4fff0000 # for reproducible results
|
|
hint = Hint()
|
|
|
|
+ def alloc_noexec(map_size):
|
|
+ """The same as `alloc`, but doesn't set the executable flag.
|
|
+ Duplicated because of constancy constraints on prot."""
|
|
+ from errno import ENOMEM
|
|
+ from rpython.rlib import debug
|
|
+
|
|
+ if _CYGWIN:
|
|
+ # XXX: JIT memory should be using mmap MAP_PRIVATE with
|
|
+ # PROT_EXEC but Cygwin's fork() fails. mprotect()
|
|
+ # cannot be used, but seems to be unnecessary there.
|
|
+ res = c_malloc_safe(map_size)
|
|
+ if res == rffi.cast(PTR, 0):
|
|
+ raise MemoryError
|
|
+ return res
|
|
+ res = alloc_hinted_noexec(rffi.cast(PTR, hint.pos), map_size)
|
|
+ if res == rffi.cast(PTR, -1):
|
|
+ # some systems (some versions of OS/X?) complain if they
|
|
+ # are passed a non-zero address. Try again.
|
|
+ res = alloc_hinted_noexec(rffi.cast(PTR, 0), map_size)
|
|
+ if res == rffi.cast(PTR, -1):
|
|
+ # ENOMEM simply raises MemoryError, but other errors are fatal
|
|
+ if rposix.get_saved_errno() != ENOMEM:
|
|
+ debug.fatalerror_notb(
|
|
+ "Got an unexpected error trying to allocate some "
|
|
+ "memory for the JIT (tried to do mmap() with "
|
|
+ "PROT_EXEC|PROT_READ|PROT_WRITE). This can be caused "
|
|
+ "by a system policy like PAX. You need to find how "
|
|
+ "to work around the policy on your system.")
|
|
+ raise MemoryError
|
|
+ else:
|
|
+ hint.pos += map_size
|
|
+ return res
|
|
+ alloc_noexec._annenforceargs_ = (int,)
|
|
+
|
|
def alloc(map_size):
|
|
"""Allocate memory. This is intended to be used by the JIT,
|
|
- so the memory has the executable bit set and gets allocated
|
|
- internally in case of a sandboxed process.
|
|
+ so the memory has the executable bit set.
|
|
+ and gets allocated internally in case of a sandboxed process.
|
|
"""
|
|
from errno import ENOMEM
|
|
from rpython.rlib import debug
|
|
@@ -936,6 +992,17 @@ elif _MS_WINDOWS:
|
|
pos = -0x4fff0000 # for reproducible results
|
|
hint = Hint()
|
|
# XXX this has no effect on windows
|
|
+ def alloc_noexec(map_size):
|
|
+ """Allocate memory. This is intended to be used by the JIT,
|
|
+ so the memory has the executable bit set.
|
|
+ XXX implement me: it should get allocated internally in
|
|
+ case of a sandboxed process
|
|
+
|
|
+ XXX no_exec ignored on windows
|
|
+ """
|
|
+ return alloc(map_size)
|
|
+ alloc_noexec._annenforceargs_ = (int,)
|
|
+
|
|
|
|
def alloc(map_size):
|
|
"""Allocate memory. This is intended to be used by the JIT,
|