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.
This commit is contained in:
Landon Fuller
2010-09-19 10:43:06 -07:00
parent f38364b399
commit 9e1196444e
2 changed files with 92 additions and 3 deletions

View File

@@ -297,10 +297,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
{ {
FFI_ASSERT (cif->abi == FFI_SYSV); FFI_ASSERT (cif->abi == FFI_SYSV);
#if FFI_EXEC_TRAMPOLINE_TABLE
// XXX - hardcoded offset
void **config = (void **) (((uint8_t *) codeloc) - 4080);
config[0] = closure;
config[1] = ffi_closure_SYSV;
#else
FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
&ffi_closure_SYSV, \ &ffi_closure_SYSV, \
codeloc); codeloc);
#endif
closure->cif = cif; closure->cif = cif;
closure->user_data = user_data; closure->user_data = user_data;
closure->fun = fun; closure->fun = fun;

View File

@@ -32,7 +32,7 @@
#include <ffi.h> #include <ffi.h>
#include <ffi_common.h> #include <ffi_common.h>
#ifndef FFI_MMAP_EXEC_WRIT #if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
# if __gnu_linux__ # if __gnu_linux__
/* This macro indicates it may be forbidden to map anonymous memory /* This macro indicates it may be forbidden to map anonymous memory
with both write and execute permission. Code compiled when this with both write and execute permission. Code compiled when this
@@ -63,7 +63,89 @@
#if FFI_CLOSURES #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_LOCKS 1
#define USE_DL_PREFIX 1 #define USE_DL_PREFIX 1