diff options
author | Landon Fuller <landonf@bikemonkey.org> | 2010-09-19 10:43:06 -0700 |
---|---|---|
committer | Landon Fuller <landonf@bikemonkey.org> | 2010-09-19 10:43:06 -0700 |
commit | 9e1196444e78aef20028c18891f44ebe39a815fd (patch) | |
tree | 9372769473b276b73589762f56404b3b443f3f50 /src/closures.c | |
parent | f38364b399184e682fc3e785084bd497827bc5af (diff) | |
download | libffi-9e1196444e78aef20028c18891f44ebe39a815fd.tar.gz |
Add a hard-coded FFI_EXEC_TRAMPOLINE_TABLE arm implementation.
This implements support for re-mapping a shared table of executable
trampolines directly in front of a writable configuration page, working
around PROT_WRITE restrictions for sandboxed applications on Apple's
iOS.
This implementation is for testing purposes; a proper allocator is still
necessary, and ARM-specific code needs to be moved out of
src/closures.c.
Diffstat (limited to 'src/closures.c')
-rw-r--r-- | src/closures.c | 86 |
1 files changed, 84 insertions, 2 deletions
diff --git a/src/closures.c b/src/closures.c index 8f295dd..c214196 100644 --- a/src/closures.c +++ b/src/closures.c @@ -32,7 +32,7 @@ #include <ffi.h> #include <ffi_common.h> -#ifndef FFI_MMAP_EXEC_WRIT +#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE # if __gnu_linux__ /* This macro indicates it may be forbidden to map anonymous memory with both write and execute permission. Code compiled when this @@ -63,7 +63,89 @@ #if FFI_CLOSURES -# if FFI_MMAP_EXEC_WRIT +# if FFI_EXEC_TRAMPOLINE_TABLE + +// XXX - non-thread-safe, non-portable implementation, intended for initial testing +#include <mach/mach.h> +#include <stdio.h> +#include <stdlib.h> + +extern void *ffi_closure_trampoline_table; + +static void *tramp_table = NULL; +static void **config_table = NULL; +static int tramp_table_free = 0; + +void * +ffi_closure_alloc (size_t size, void **code) +{ + if (!code) + return NULL; + + /* Allocate our config page and remap the trampoline table */ + while (tramp_table == NULL) { + vm_address_t config_page = 0x0; + kern_return_t kt; + + /* Try to allocate two pages */ + kt = vm_allocate(mach_task_self(), &config_page, PAGE_SIZE*2, VM_FLAGS_ANYWHERE); + if (kt != KERN_SUCCESS) { + fprintf(stderr, "vm_allocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); + break; + } + + /* Now drop the second half of the allocation to make room for the trampoline table */ + kt = vm_deallocate(mach_task_self(), config_page+PAGE_SIZE, PAGE_SIZE); + if (kt != KERN_SUCCESS) { + fprintf(stderr, "vm_deallocate() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); + break; + } + + /* Remap the trampoline table to directly follow the config page */ + vm_address_t table_page = config_page+PAGE_SIZE; + vm_prot_t cur_prot; + vm_prot_t max_prot; + + kt = vm_remap(mach_task_self(), &table_page, PAGE_SIZE, 0x0, FALSE, mach_task_self(), (vm_address_t) &ffi_closure_trampoline_table, FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE); + + /* If we lost access to the destination trampoline page, drop our config allocation mapping and retry */ + if (kt != KERN_SUCCESS) { + /* Log unexpected failures */ + if (kt != KERN_NO_SPACE) { + fprintf(stderr, "vm_remap() failure: %d at %s:%d\n", kt, __FILE__, __LINE__); + } + + vm_deallocate(mach_task_self(), config_page, PAGE_SIZE); + continue; + } + + tramp_table = (void *) table_page; + config_table = (void **) config_page; + config_table += 4; // XXX - there's a 16 byte offset into the config page on ARM + + fprintf(stderr, "[DEBUG] Allocated config page at %p, trampoline page at %p, configs start at %p\n", (void *) config_page, (void *) table_page, config_table); + } + + /* Check for permanent allocation failure */ + if (tramp_table == NULL) + return *code = NULL; + + *code = tramp_table + (3 * tramp_table_free); + tramp_table_free++; + + void *closure = malloc(size); + + return closure; +} + +void +ffi_closure_free (void *ptr) +{ + // TODO + //free (ptr); +} + +# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */ #define USE_LOCKS 1 #define USE_DL_PREFIX 1 |