/usr/src/gcc-6/debian/patches/libffi-pax.diff is in gcc-6-source 6.4.0-17ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | From 757876336c183f5b20b6620d674cc9817fd0d280 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20B=C3=BChler?= <buehler@cert.uni-stuttgart.de>
Date: Wed, 7 Sep 2016 15:50:54 +0200
Subject: [PATCH 2/2] always check for PaX MPROTECT on linux, make EMUTRAMP
experimental
- ffi_prep_closure_loc doesn't necessarily generate trampolines recognized by
PaX EMUTRAMP handler; there is no way to check before, and it isn't working
on x86-64 right now -> experimental
- if MPROTECT is enabled use the same workaround as is used for SELinux (double
mmap())
---
configure.ac | 11 +++++++---
src/closures.c | 68 +++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 54 insertions(+), 25 deletions(-)
--- a/src/libffi/configure.ac
+++ b/src/libffi/configure.ac
@@ -177,12 +177,17 @@
;;
esac
-# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC.
+# On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC;
+# if EMUTRAMP is active too ffi could try mapping without PROT_EXEC,
+# but the kernel needs to recognize the trampoline generated by ffi.
+# Otherwise fallback to double mmap trick.
AC_ARG_ENABLE(pax_emutramp,
- [ --enable-pax_emutramp enable pax emulated trampolines, for we can't use PROT_EXEC],
+ [ --enable-pax_emutramp enable pax emulated trampolines (experimental)],
if test "$enable_pax_emutramp" = "yes"; then
+ AC_MSG_WARN([EMUTRAMP is experimental only. Use --enable-pax_emutramp=experimental to enforce.])
+ elif test "$enable_pax_emutramp" = "experimental"; then
AC_DEFINE(FFI_MMAP_EXEC_EMUTRAMP_PAX, 1,
- [Define this if you want to enable pax emulated trampolines])
+ [Define this if you want to enable pax emulated trampolines (experimental)])
fi)
FFI_EXEC_TRAMPOLINE_TABLE=0
--- a/src/libffi/src/closures.c
+++ b/src/libffi/src/closures.c
@@ -53,14 +53,18 @@
# endif
#endif
-#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
-# ifdef __linux__
+#if FFI_MMAP_EXEC_WRIT && defined __linux__
+# if !defined FFI_MMAP_EXEC_SELINUX
/* 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
+# endif /* !defined FFI_MMAP_EXEC_SELINUX */
+# if !defined FFI_MMAP_PAX
+/* Also check for PaX MPROTECT */
+# define FFI_MMAP_PAX 1
+# endif /* !defined FFI_MMAP_PAX */
+#endif /* FFI_MMAP_EXEC_WRIT && defined __linux__ */
#if FFI_CLOSURES
@@ -172,14 +176,18 @@
#endif /* !FFI_MMAP_EXEC_SELINUX */
-/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */
-#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
+/* On PaX enable kernels that have MPROTECT enabled we can't use PROT_EXEC. */
+#if defined FFI_MMAP_PAX
#include <stdlib.h>
-static int emutramp_enabled = -1;
+enum {
+ PAX_MPROTECT = (1 << 0),
+ PAX_EMUTRAMP = (1 << 1),
+};
+static int cached_pax_flags = -1;
static int
-emutramp_enabled_check (void)
+pax_flags_check (void)
{
char *buf = NULL;
size_t len = 0;
@@ -193,9 +201,10 @@
while (getline (&buf, &len, f) != -1)
if (!strncmp (buf, "PaX:", 4))
{
- char emutramp;
- if (sscanf (buf, "%*s %*c%c", &emutramp) == 1)
- ret = (emutramp == 'E');
+ if (NULL != strchr (buf + 4, 'M'))
+ ret |= PAX_MPROTECT;
+ if (NULL != strchr (buf + 4, 'E'))
+ ret |= PAX_EMUTRAMP;
break;
}
free (buf);
@@ -203,9 +212,13 @@
return ret;
}
-#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
- : (emutramp_enabled = emutramp_enabled_check ()))
-#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+#define get_pax_flags() (cached_pax_flags >= 0 ? cached_pax_flags \
+ : (cached_pax_flags = pax_flags_check ()))
+#define has_pax_flags(flags) ((flags) == ((flags) & get_pax_flags ()))
+#define is_mprotect_enabled() (has_pax_flags (PAX_MPROTECT))
+#define is_emutramp_enabled() (has_pax_flags (PAX_EMUTRAMP))
+
+#endif /* defined FFI_MMAP_PAX */
#elif defined (__CYGWIN__) || defined(__INTERIX)
@@ -216,9 +229,10 @@
#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
-#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
-#define is_emutramp_enabled() 0
-#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+#if !defined FFI_MMAP_PAX
+# define is_mprotect_enabled() 0
+# define is_emutramp_enabled() 0
+#endif /* !defined FFI_MMAP_PAX */
/* Declare all functions defined in dlmalloc.c as static. */
static void *dlmalloc(size_t);
@@ -525,13 +539,23 @@
printf ("mapping in %zi\n", length);
#endif
- if (execfd == -1 && is_emutramp_enabled ())
+ /* -1 != execfd hints that we already decided to use dlmmap_locked
+ last time. */
+ if (execfd == -1 && is_mprotect_enabled ())
{
- ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
- return ptr;
+#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
+ if (is_emutramp_enabled ())
+ {
+ /* emutramp requires the kernel recognizing the trampoline pattern
+ generated by ffi_prep_closure_loc; there is no way to test
+ in advance whether this will work, so this is experimental. */
+ ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
+ return ptr;
+ }
+#endif
+ /* fallback to dlmmap_locked. */
}
-
- if (execfd == -1 && !is_selinux_enabled ())
+ else if (execfd == -1 && !is_selinux_enabled ())
{
ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
|