Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 9ec7040

Browse files
committed
[[ Bug ]] Fix handler function pointers on newer Android versions
This patch fixes an issue with the generation of handler function pointers on newer versions of Android (starting with 9). The issue is that libffi is failing to generate closure trampolines in memory which has the executable permission bit set. This has been worked around by explicitly changing the memory protection flags to be read/write/exec *after* libffi has created the closure.
1 parent 4bee4a0 commit 9ec7040

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

libfoundation/src/foundation-handler.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,40 @@ static void __exec_closure(ffi_cif *cif, void *ret, void **args, void *user_data
301301
MCValueRelease(t_value_args[i]);
302302
}
303303

304+
#if defined(__ANDROID__)
305+
306+
/* For some reason the current version / config of libffi on newer versions of
307+
* android fails to generate closure trampolines in memory with the exec bit
308+
* set. To work-around this we set the exec bit of the memory page containing
309+
* the function ptr directly. */
310+
311+
#include <sys/mman.h>
312+
313+
static bool ensure_block_is_executable(void *p_block, size_t p_size)
314+
{
315+
/* Round the start of the block pointer down to the nearest page. */
316+
byte_t *t_start_page = (byte_t *)(((uintptr_t)p_block) & ~4095);
317+
318+
/* Round the end of the block pointer up to the nearest page. */
319+
byte_t *t_finish_page = (byte_t *)((((uintptr_t)p_block + p_size) + 4095) & ~4095);
320+
321+
/* Change the protection flags of the page range to read/write/exec. */
322+
return mprotect(t_start_page,
323+
t_finish_page - t_start_page,
324+
PROT_READ|PROT_EXEC|PROT_WRITE) == 0;
325+
}
326+
327+
#else
328+
329+
/* Other platforms do not need any explicit action as libffi works correctly. */
330+
331+
static bool ensure_block_is_executable(void *p_block, size_t p_size)
332+
{
333+
return true;
334+
}
335+
336+
#endif
337+
304338
MC_DLLEXPORT_DEF
305339
bool MCHandlerGetFunctionPtr(MCHandlerRef self, void*& r_function_ptr)
306340
{
@@ -326,6 +360,13 @@ bool MCHandlerGetFunctionPtr(MCHandlerRef self, void*& r_function_ptr)
326360
self -> closure = nil;
327361
return MCErrorThrowGeneric(MCSTR("unexpected libffi failure"));
328362
}
363+
364+
/* Change the protection flags of the page range to read/write/exec. */
365+
if (!ensure_block_is_executable(self->closure,
366+
sizeof(ffi_closure)))
367+
{
368+
return MCErrorThrowGeneric(MCSTR("unable to generate executable closure trampoline"));
369+
}
329370

330371
r_function_ptr = self -> function_ptr;
331372
return true;

0 commit comments

Comments
 (0)