Ensure that VM_PROT_EXECUTE is set on the trampoline page. (#718)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
diff --git a/src/closures.c b/src/closures.c
index f7bead6..db7ec94 100644
--- a/src/closures.c
+++ b/src/closures.c
@@ -134,7 +134,7 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
# define HAVE_MNTENT 1
# endif
# if defined(_WIN32) || defined(__OS2__)
-/* Windows systems may have Data Execution Protection (DEP) enabled,
+/* Windows systems may have Data Execution Protection (DEP) enabled,
which requires the use of VirtualMalloc/VirtualFree to alloc/free
executable memory. */
# define FFI_MMAP_EXEC_WRIT 1
@@ -230,12 +230,24 @@ ffi_trampoline_table_alloc (void)
kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0,
VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template,
FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
- if (kt != KERN_SUCCESS || !(cur_prot & VM_PROT_EXECUTE))
+ if (kt != KERN_SUCCESS)
{
vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
return NULL;
}
+ if (!(cur_prot & VM_PROT_EXECUTE))
+ {
+ /* If VM_PROT_EXECUTE isn't set on the remapped trampoline page, set it */
+ kt = vm_protect (mach_task_self (), trampoline_page, PAGE_MAX_SIZE,
+ FALSE, cur_prot | VM_PROT_EXECUTE);
+ if (kt != KERN_SUCCESS)
+ {
+ vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
+ return NULL;
+ }
+ }
+
/* We have valid trampoline and config pages */
table = calloc (1, sizeof (ffi_trampoline_table));
table->free_count = FFI_TRAMPOLINE_COUNT;