summaryrefslogtreecommitdiff
path: root/debian/patches/libffi-pax.diff
blob: 14a70496544d5b26a88258057e975171c0b2566b (plain)
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
@@ -176,12 +176,17 @@ case "$TARGET" in
     ;;
 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 @@ selinux_enabled_check (void)
 
 #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 @@ emutramp_enabled_check (void)
   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 @@ emutramp_enabled_check (void)
   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 @@ emutramp_enabled_check (void)
 
 #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 @@ dlmmap (void *start, size_t length, int
   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);