summaryrefslogtreecommitdiff
path: root/girepository
diff options
context:
space:
mode:
authorOwen W. Taylor <otaylor@fishsoup.net>2010-04-07 17:48:52 -0400
committerOwen W. Taylor <otaylor@fishsoup.net>2010-04-08 10:50:04 -0400
commit024d7d9c94fd533472a6abdcced94ee638c0d7fc (patch)
treec2bc02cc50de507cc5455919a1b40ea72ebb2226 /girepository
parent921ad0677d29979f5f7cec9267deb434c750fb94 (diff)
downloadgobject-introspection-024d7d9c94fd533472a6abdcced94ee638c0d7fc.tar.gz
Correctly use ffi_closure_alloc(), fixing mmap permissions error
This restores the reverted-commit ed8634d: Author: Dan Winship <danw@gnome.org> 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
Diffstat (limited to 'girepository')
-rw-r--r--girepository/girffi.c44
1 files changed, 22 insertions, 22 deletions
diff --git a/girepository/girffi.c b/girepository/girffi.c
index 88cafec9..3f0b6705 100644
--- a/girepository/girffi.c
+++ b/girepository/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);
}