This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] W^X Java closure fixes
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, java-patches at gcc dot gnu dot org
- Cc: Alexandre Oliva <aoliva at redhat dot com>
- Date: Thu, 29 Mar 2007 17:31:36 -0500
- Subject: [PATCH] W^X Java closure fixes
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
libjava now (thanks to Alex) uses ffi_closure_{alloc,free} to allocate
trampolines separately. But boehm-gc's default hasn't been changed, which
means all GC memory is still executable (where allowed) or just will fail
to mmap (if e.g. SELinux policy disallows PROT_WRITE|PROT_EXEC mappings).
The following patch changes that, by setting NO_EXECUTE_PERMISSION always
to 1 in gcc's boehm-gc (not sure what should boehm-gc's upstream do here,
it can't be so sure nobody uses GC memory for code).
Additionally, the patch has a quick check for SELinux presence on Linux
and will skip the PROT_READ|PROT_WRITE|PROT_EXEC mmap if it is (while try it
if SELinux is not present or on other OSes), because such mmap would trigger
annoying audit messages.
Ok for trunk?
2007-03-29 Jakub Jelinek <jakub@redhat.com>
* src/closures.c: Include sys/statfs.h.
(_GNU_SOURCE): Define on Linux.
(FFI_MMAP_EXEC_SELINUX): Define.
(selinux_enabled): New variable.
(selinux_enabled_check): New function.
(is_selinux_enabled): Define.
(dlmmap): Use it.
* configure.ac (NO_EXECUTE_PERMISSION): Set by default.
* configure: Rebuilt.
--- libffi/src/closures.c.jj 2007-03-27 15:57:33.000000000 +0200
+++ libffi/src/closures.c 2007-03-27 16:29:34.000000000 +0200
@@ -23,6 +23,10 @@
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
+#if defined __linux__ && !defined _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
#include <ffi.h>
#include <ffi_common.h>
@@ -39,6 +43,15 @@
# endif
#endif
+#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
+# ifdef __linux__
+/* When defined to 1 check for SELinux and if SELinux is active,
+ don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
+ might cause audit messages. */
+# define FFI_MMAP_EXEC_SELINUX 1
+# endif
+#endif
+
#if FFI_CLOSURES
# if FFI_MMAP_EXEC_WRIT
@@ -87,6 +100,55 @@
#include <sys/mman.h>
#define LACKS_SYS_MMAN_H 1
+#if FFI_MMAP_EXEC_SELINUX
+#include <sys/statfs.h>
+#include <stdlib.h>
+
+static int selinux_enabled = -1;
+
+static int
+selinux_enabled_check (void)
+{
+ struct statfs sfs;
+ FILE *f;
+ char *buf = NULL;
+ size_t len = 0;
+
+ if (statfs ("/selinux", &sfs) >= 0
+ && (unsigned int) sfs.f_type == 0xf97cff8cU)
+ return 1;
+ f = fopen ("/proc/mounts", "r");
+ if (f == NULL)
+ return 0;
+ while (getline (&buf, &len, f) >= 0)
+ {
+ char *p = strchr (buf, ' ');
+ if (p == NULL)
+ break;
+ p = strchr (p + 1, ' ');
+ if (p == NULL)
+ break;
+ if (strncmp (p + 1, "selinuxfs ", 10) != 0)
+ {
+ free (buf);
+ fclose (f);
+ return 1;
+ }
+ }
+ free (buf);
+ fclose (f);
+ return 0;
+}
+
+#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
+ : (selinux_enabled = selinux_enabled_check ()))
+
+#else
+
+#define is_selinux_enabled() 0
+
+#endif
+
#define MAYBE_UNUSED __attribute__((__unused__))
/* Declare all functions defined in dlmalloc.c as static. */
@@ -358,7 +420,7 @@ dlmmap (void *start, size_t length, int
printf ("mapping in %zi\n", length);
#endif
- if (execfd == -1)
+ if (execfd == -1 && !is_selinux_enabled ())
{
ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
--- boehm-gc/configure.ac.jj 2007-02-20 22:39:56.000000000 +0100
+++ boehm-gc/configure.ac 2007-03-29 12:30:30.000000000 +0200
@@ -338,11 +338,9 @@ LIBS="$oldLIBS"
# Configuration of machine-dependent code
#
-# We don't set NO_EXECUTE_PERMISSION by default because gcj (and
-# anything else that creates trampolines in gc-allocated memory)
-# always needs exec permission. The exceptions to this are IA-64 and
-# some variations of Power PC, where trampolines don't contain
-# executable code.
+# Set NO_EXECUTE_PERMISSION by default because gcj already uses
+# ffi_closure_{alloc,free} which takes care of allocating trampolines
+# in executable memory.
#
AC_MSG_CHECKING(which machine-dependent code should be used)
machdep=
@@ -385,10 +383,10 @@ case "$host" in
machdep="sparc_mach_dep.lo"
;;
ia64-*-*)
- AC_DEFINE(NO_EXECUTE_PERMISSION,1,[cause some or all of the heap to not have execute permission])
machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
;;
esac
+AC_DEFINE(NO_EXECUTE_PERMISSION,1,[cause some or all of the heap to not have execute permission])
if test x"$machdep" = x; then
AC_MSG_RESULT($machdep)
machdep="mach_dep.lo"
--- boehm-gc/configure.jj 2007-02-20 22:39:56.000000000 +0100
+++ boehm-gc/configure 2007-03-29 12:31:25.000000000 +0200
@@ -6560,11 +6560,9 @@ LIBS="$oldLIBS"
# Configuration of machine-dependent code
#
-# We don't set NO_EXECUTE_PERMISSION by default because gcj (and
-# anything else that creates trampolines in gc-allocated memory)
-# always needs exec permission. The exceptions to this are IA-64 and
-# some variations of Power PC, where trampolines don't contain
-# executable code.
+# Set NO_EXECUTE_PERMISSION by default because gcj already uses
+# ffi_closure_{alloc,free} which takes care of allocating trampolines
+# in executable memory.
#
echo "$as_me:$LINENO: checking which machine-dependent code should be used" >&5
echo $ECHO_N "checking which machine-dependent code should be used... $ECHO_C" >&6
@@ -6625,14 +6623,14 @@ _ACEOF
machdep="sparc_mach_dep.lo"
;;
ia64-*-*)
+ machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
+ ;;
+esac
cat >>confdefs.h <<\_ACEOF
#define NO_EXECUTE_PERMISSION 1
_ACEOF
- machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
- ;;
-esac
if test x"$machdep" = x; then
echo "$as_me:$LINENO: result: $machdep" >&5
echo "${ECHO_T}$machdep" >&6
Jakub