From d89af8f6d5f3b971dda663081c03d790437c2f03 Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 24 Jan 2015 20:04:20 -0500 Subject: Add function to deal with mprotecting RW and back. A bit more complex than the minimum would be... (and minor build fixes) --- lib/darwin/execmem.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 lib/darwin/execmem.c (limited to 'lib/darwin/execmem.c') diff --git a/lib/darwin/execmem.c b/lib/darwin/execmem.c new file mode 100644 index 0000000..c707db5 --- /dev/null +++ b/lib/darwin/execmem.c @@ -0,0 +1,57 @@ +#include "execmem.h" +#include "darwin/manual-syscall.h" +#include "substitute.h" +#include +#include +#include +#include +#include + +int execmem_write(void *dest, const void *src, size_t len) { + /* Use vm_region to determine the original protection, so we can mprotect + * it back afterwards. (Note: PROT_* are equal to VM_PROT_*.) */ + vm_address_t region = (vm_address_t) dest; + vm_size_t region_len = 0; + struct vm_region_submap_short_info_64 info; + mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + natural_t max_depth = 99999; + kern_return_t kr = vm_region_recurse_64(mach_task_self(), ®ion, ®ion_len, + &max_depth, + (vm_region_recurse_info_t) &info, + &info_count); + if (kr) { + /* Weird; this probably means the region doesn't exist, but we should + * have already read from the memory in order to generate the patch. */ + errno = 0; + return SUBSTITUTE_ERR_VM; + } + + uintptr_t lopage = (uintptr_t) dest & ~PAGE_MASK; + uintptr_t hipage = ((uintptr_t) dest + len + PAGE_MASK) & ~PAGE_MASK; + + /* We do the syscall manually just in case the user is trying to write to + * the mprotect syscall stub itself, or one of the functions it calls. + * (Obviously, it will still break if the user targets some libsubstitute + * function within the same page as this one, though.) */ + int ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage, + PROT_READ | PROT_WRITE, 0, 0); + if (ret) { + errno = ret; + return SUBSTITUTE_ERR_VM; + } + + /* volatile to avoid compiler transformation to call to memcpy */ + volatile uint8_t *d8 = dest; + const uint8_t *s8 = src; + while (len--) + *d8++ = *s8++; + + int oldprot = info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC); + ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage, + oldprot, 0, 0); + if (ret) { + errno = ret; + return SUBSTITUTE_ERR_VM; + } + return SUBSTITUTE_OK; +} -- cgit v1.2.3