From e316ab790324bd70535fd67bcedb5580f3c2cae5 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Tue, 8 Nov 2022 13:06:24 +0100 Subject: [PATCH] exec: provide function to test runtime availability of rwx maps SELinux or PaX/grsecurity based kernels may deny creating writable and executable mappings, leading to errors when trying to allocate JIT memory, even though JIT support is generally available. Provide a function to probe for the runtime availability of rwx maps to support users like libpcre2 which can use it to announce the lack of JIT and fall back to the interpreter instead. This function is only needed for Linux and only if we're using the default JIT memory allocator, as all others implement workarounds via double mappings. Signed-off-by: Mathias Krause --- sljit_src/sljitConfigInternal.h | 11 ++++++++ sljit_src/sljitExecAllocator.c | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/sljit_src/sljitConfigInternal.h b/sljit_src/sljitConfigInternal.h index cd3ce6973..0ad655827 100644 --- a/sljit_src/sljitConfigInternal.h +++ b/sljit_src/sljitConfigInternal.h @@ -633,6 +633,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr) #else #define SLJIT_EXEC_OFFSET(ptr) 0 + +/* SELinux or grsecurity kernels may deny creating rwx mappings, so we need +to probe at runtime if JIT memory is supported. */ +#if defined __linux__ && \ + (!defined SLJIT_PROT_EXECUTABLE_ALLOCATOR || !SLJIT_PROT_EXECUTABLE_ALLOCATOR) && \ + (!defined SLJIT_WX_EXECUTABLE_ALLOCATOR || !SLJIT_WX_EXECUTABLE_ALLOCATOR) +SLJIT_API_FUNC_ATTRIBUTE int sljit_get_runtime_support(void); +#else +#define sljit_get_runtime_support() 1 +#endif + #endif #endif /* SLJIT_EXECUTABLE_ALLOCATOR */ diff --git a/sljit_src/sljitExecAllocator.c b/sljit_src/sljitExecAllocator.c index 92d940ddc..2fd3ea2b9 100644 --- a/sljit_src/sljitExecAllocator.c +++ b/sljit_src/sljitExecAllocator.c @@ -94,6 +94,52 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) #else /* POSIX */ +#ifdef __linux__ +SLJIT_API_FUNC_ATTRIBUTE int sljit_get_runtime_support(void) +{ + int status = -1; + size_t size; + void *addr; + FILE *f; + + /* Try to get the status from /proc/self/status, looking for PaX flags. */ + f = fopen("/proc/self/status", "r"); + if (f) { + char *buf = NULL; + size_t len; + + while (getline(&buf, &len, f) != -1) { + if (strncmp(buf, "PaX:", 4)) + continue; + + /* Look for 'm', indicating PaX MPROTECT is disabled. */ + status = !!strchr(buf+4, 'm'); + break; + } + + fclose(f); + free(buf); + + if (status != -1) + return status; + } + + /* + * Create a temporary mapping and try to make it writable to probe for rwx + * support without generating a log message. + */ + size = get_page_alignment() + 1; + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (addr == MAP_FAILED) + return 0; + + status = mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0; + munmap(addr, size); + + return status; +} +#endif + #if defined(__APPLE__) && defined(MAP_JIT) /* On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a