diff options
author | Anthony Green <green@moxielogic.com> | 2017-11-03 07:05:31 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-03 07:05:31 -0400 |
commit | 4fdbb0578e921a9da146c2b040061a3a39fe4fda (patch) | |
tree | 875c8a6c4fbbeb0c5b2355ada8254b9f329796e1 /src/closures.c | |
parent | b302bc3dfe47e3ea57de11610fced3170c06df28 (diff) | |
parent | 2bfcd29955c02b67fa10a68cc4200f6838181e0f (diff) | |
download | libffi-4fdbb0578e921a9da146c2b040061a3a39fe4fda.tar.gz |
Merge pull request #320 from 0-wiz-0/master
Support NetBSD with mprotect.
Diffstat (limited to 'src/closures.c')
-rw-r--r-- | src/closures.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/src/closures.c b/src/closures.c index e8dbb78..59ce828 100644 --- a/src/closures.c +++ b/src/closures.c @@ -34,6 +34,82 @@ #include <ffi.h> #include <ffi_common.h> +#ifdef __NetBSD__ +#include <sys/param.h> +#endif + +#if __NetBSD_Version__ - 0 >= 799007200 +/* NetBSD with PROT_MPROTECT */ +#include <sys/mman.h> + +#include <stddef.h> +#include <unistd.h> + +static const size_t overhead = + (sizeof(max_align_t) > sizeof(void *) + sizeof(size_t)) ? + sizeof(max_align_t) + : sizeof(void *) + sizeof(size_t); + +#define ADD_TO_POINTER(p, d) ((void *)((uintptr_t)(p) + (d))) + +void * +ffi_closure_alloc (size_t size, void **code) +{ + static size_t page_size; + size_t rounded_size; + void *codeseg, *dataseg; + int prot; + + /* Expect that PAX mprotect is active and a separate code mapping is necessary. */ + if (!code) + return NULL; + + /* Obtain system page size. */ + if (!page_size) + page_size = sysconf(_SC_PAGESIZE); + + /* Round allocation size up to the next page, keeping in mind the size field and pointer to code map. */ + rounded_size = (size + overhead + page_size - 1) & ~(page_size - 1); + + /* Primary mapping is RW, but request permission to switch to PROT_EXEC later. */ + prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC); + dataseg = mmap(NULL, rounded_size, prot, MAP_ANON | MAP_PRIVATE, -1, 0); + if (dataseg == MAP_FAILED) + return NULL; + + /* Create secondary mapping and switch it to RX. */ + codeseg = mremap(dataseg, rounded_size, NULL, rounded_size, MAP_REMAPDUP); + if (codeseg == MAP_FAILED) { + munmap(dataseg, rounded_size); + return NULL; + } + if (mprotect(codeseg, rounded_size, PROT_READ | PROT_EXEC) == -1) { + munmap(codeseg, rounded_size); + munmap(dataseg, rounded_size); + return NULL; + } + + /* Remember allocation size and location of the secondary mapping for ffi_closure_free. */ + memcpy(dataseg, &rounded_size, sizeof(rounded_size)); + memcpy(ADD_TO_POINTER(dataseg, sizeof(size_t)), &codeseg, sizeof(void *)); + *code = ADD_TO_POINTER(codeseg, overhead); + return ADD_TO_POINTER(dataseg, overhead); +} + +void +ffi_closure_free (void *ptr) +{ + void *codeseg, *dataseg; + size_t rounded_size; + + dataseg = ADD_TO_POINTER(ptr, -overhead); + memcpy(&rounded_size, dataseg, sizeof(rounded_size)); + memcpy(&codeseg, ADD_TO_POINTER(dataseg, sizeof(size_t)), sizeof(void *)); + munmap(dataseg, rounded_size); + munmap(codeseg, rounded_size); +} +#else /* !NetBSD with PROT_MPROTECT */ + #if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE # if __linux__ && !defined(__ANDROID__) /* This macro indicates it may be forbidden to map anonymous memory @@ -856,3 +932,5 @@ ffi_closure_free (void *ptr) # endif /* ! FFI_MMAP_EXEC_WRIT */ #endif /* FFI_CLOSURES */ + +#endif /* NetBSD with PROT_MPROTECT */ |