Skip to content

Commit 5e93d28

Browse files
committed
sljit/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 <[email protected]>
1 parent f852788 commit 5e93d28

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

src/sljit/sljitConfigInternal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
633633
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
634634
#else
635635
#define SLJIT_EXEC_OFFSET(ptr) 0
636+
637+
/* SELinux or grsecurity kernels may deny creating rwx mappings, so we need
638+
to probe at runtime if JIT memory is supported. */
639+
#if defined __linux__ && \
640+
(!defined SLJIT_PROT_EXECUTABLE_ALLOCATOR || !SLJIT_PROT_EXECUTABLE_ALLOCATOR) && \
641+
(!defined SLJIT_WX_EXECUTABLE_ALLOCATOR || !SLJIT_WX_EXECUTABLE_ALLOCATOR)
642+
SLJIT_API_FUNC_ATTRIBUTE int sljit_get_runtime_support(void);
643+
#else
644+
#define sljit_get_runtime_support() 1
645+
#endif
646+
636647
#endif
637648

638649
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */

src/sljit/sljitExecAllocator.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,61 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
9494

9595
#else /* POSIX */
9696

97+
#ifdef __linux__
98+
#include <errno.h>
99+
100+
static SLJIT_INLINE int is_permission_error(int err)
101+
{
102+
/* PaX uses EPERM, SELinux uses EACCES */
103+
return err == EPERM || err == EACCES;
104+
}
105+
106+
SLJIT_API_FUNC_ATTRIBUTE int sljit_get_runtime_support(void)
107+
{
108+
int status = -1;
109+
size_t size;
110+
void *addr;
111+
FILE *f;
112+
113+
/* Try to get the status from /proc/self/status, looking for PaX flags. */
114+
f = fopen("/proc/self/status", "re");
115+
if (f) {
116+
char *buf = NULL;
117+
size_t len;
118+
119+
while (getline(&buf, &len, f) != -1) {
120+
if (strncmp(buf, "PaX:", 4))
121+
continue;
122+
123+
/* Look for 'm', indicating PaX MPROTECT is disabled. */
124+
status = !!strchr(buf+4, 'm');
125+
break;
126+
}
127+
128+
fclose(f);
129+
free(buf);
130+
131+
if (status != -1)
132+
return status;
133+
}
134+
135+
/*
136+
* Try to create a temporary rwx mapping to probe for its support. If
137+
* this fails, test 'errno' to ensure it failed because we were not
138+
* allowed to create such a mapping and not because of some transient
139+
* error.
140+
*/
141+
size = get_page_alignment() + 1;
142+
addr = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
143+
if (addr == MAP_FAILED)
144+
return is_permission_error(errno) ? 0 : -1;
145+
146+
munmap(addr, size);
147+
148+
return 1;
149+
}
150+
#endif
151+
97152
#if defined(__APPLE__) && defined(MAP_JIT)
98153
/*
99154
On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a

0 commit comments

Comments
 (0)