From 9d2fd90f0aecdeabc22133dc6722209956a19520 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Wed, 7 Apr 2010 17:48:52 -0400 Subject: [PATCH] Correctly use ffi_closure_alloc(), fixing mmap permissions error This restores the reverted-commit ed8634d: Author: Dan Winship Date: Mon Apr 5 14:05:52 2010 -0400 g_callable_info_prepare_closure: handle mmap permissions error When SELinux or similar is active, a process may not be able to mmap() a segment that is both writable and executable, which would causing g_callable_info_prepare_closure() to fail. Libffi has a workaround for this problem though (it maps the same non-anonymous region twice, once writable and once executable, and returns two separate pointers to it), so use that. But with an added fix, when using ffi_closure_alloc(), we need to use ffi_prep_closure_loc() so we can pass in the executable address of the trampoline separately from the writable address, rather than the deprecated ffi_prep_closure(). https://bugzilla.gnome.org/show_bug.cgi?id=615105 --- girffi.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/girffi.c b/girffi.c index 88cafec90..3f0b67058 100644 --- a/girffi.c +++ b/girffi.c @@ -297,6 +297,11 @@ g_function_invoker_destroy (GIFunctionInvoker *invoker) g_free (invoker->cif.arg_types); } +typedef struct { + ffi_closure ffi_closure; + gpointer writable_self; +} GIClosureWrapper; + /** * g_callable_info_prepare_closure: * @callable_info: a callable info from a typelib @@ -306,11 +311,8 @@ g_function_invoker_destroy (GIFunctionInvoker *invoker) * * Prepares a callback for ffi invocation. * - * Note: this function requires the heap to be executable, which - * might not function properly on systems with SELinux enabled. - * * Return value: the ffi_closure or NULL on error. - * The return value should be freed by calling g_callable_info_prepare_closure(). + * The return value should be freed by calling g_callable_info_free_closure(). */ ffi_closure * g_callable_info_prepare_closure (GICallableInfo *callable_info, @@ -318,21 +320,21 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info, GIFFIClosureCallback callback, gpointer user_data) { - ffi_closure *closure; + gpointer exec_ptr; + GIClosureWrapper *closure; ffi_status status; g_return_val_if_fail (callable_info != NULL, FALSE); g_return_val_if_fail (cif != NULL, FALSE); g_return_val_if_fail (callback != NULL, FALSE); - closure = mmap (NULL, sizeof (ffi_closure), - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE)); + closure = ffi_closure_alloc (sizeof (GIClosureWrapper), &exec_ptr); if (!closure) { - g_warning("mmap failed: %s\n", strerror(errno)); + g_warning ("could not allocate closure\n"); return NULL; } + closure->writable_self = closure; status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, g_callable_info_get_n_args (callable_info), @@ -340,27 +342,23 @@ g_callable_info_prepare_closure (GICallableInfo *callable_info, g_callable_info_get_ffi_arg_types (callable_info)); if (status != FFI_OK) { - g_warning("ffi_prep_cif failed: %d\n", status); - munmap(closure, sizeof (closure)); + g_warning ("ffi_prep_cif failed: %d\n", status); + ffi_closure_free (closure); return NULL; } - status = ffi_prep_closure (closure, cif, callback, user_data); + status = ffi_prep_closure_loc (&closure->ffi_closure, cif, callback, user_data, exec_ptr); if (status != FFI_OK) { g_warning ("ffi_prep_closure failed: %d\n", status); - munmap(closure, sizeof (closure)); + ffi_closure_free (closure); return NULL; } - if (mprotect(closure, sizeof (closure), PROT_READ | PROT_EXEC) == -1) - { - g_warning ("ffi_prep_closure failed: %s\n", strerror(errno)); - munmap(closure, sizeof (closure)); - return NULL; - } - - return closure; + /* Return exec_ptr, which points to the same underlying memory as + * closure, but via an executable-non-writable mapping. + */ + return exec_ptr; } /** @@ -374,5 +372,7 @@ void g_callable_info_free_closure (GICallableInfo *callable_info, ffi_closure *closure) { - munmap(closure, sizeof (closure)); + GIClosureWrapper *wrapper = (GIClosureWrapper *)closure; + + ffi_closure_free (wrapper->writable_self); }