Skip to content

Commit

Permalink
exec: provide function to test runtime availability of rwx maps
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
minipli-oss committed Dec 16, 2022
1 parent 2c02b2a commit 8e46492
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
10 changes: 10 additions & 0 deletions sljit_src/sljitConfigInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
#endif

/* 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 /* SLJIT_EXECUTABLE_ALLOCATOR */

#ifndef SLJIT_EXEC_OFFSET
Expand Down
55 changes: 55 additions & 0 deletions sljit_src/sljitExecAllocator.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,61 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)

#else /* POSIX */

#ifdef __linux__
#include <errno.h>

static SLJIT_INLINE int is_permission_error(int err)
{
/* PaX uses EPERM, SELinux uses EACCES */
return err == EPERM || err == EACCES;
}

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", "re");
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;
}

/*
* Try to create a temporary rwx mapping to probe for its support. If
* this fails, test 'errno' to ensure it failed because we were not
* allowed to create such a mapping and not because of some transient
* error.
*/
size = get_page_alignment() + 1;
addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
if (addr == MAP_FAILED)
return is_permission_error(errno) ? 0 : -1;

munmap(addr, size);

return 1;
}
#endif

#if defined(__APPLE__) && defined(MAP_JIT)
/*
On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
Expand Down

0 comments on commit 8e46492

Please sign in to comment.