aboutsummaryrefslogtreecommitdiff
path: root/src/lj_mcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_mcode.c')
-rw-r--r--src/lj_mcode.c78
1 files changed, 35 insertions, 43 deletions
diff --git a/src/lj_mcode.c b/src/lj_mcode.c
index ac37c1a6..42aab0bc 100644
--- a/src/lj_mcode.c
+++ b/src/lj_mcode.c
@@ -14,6 +14,7 @@
14#include "lj_mcode.h" 14#include "lj_mcode.h"
15#include "lj_trace.h" 15#include "lj_trace.h"
16#include "lj_dispatch.h" 16#include "lj_dispatch.h"
17#include "lj_prng.h"
17#endif 18#endif
18#if LJ_HASJIT || LJ_HASFFI 19#if LJ_HASJIT || LJ_HASFFI
19#include "lj_vm.h" 20#include "lj_vm.h"
@@ -44,7 +45,7 @@ void lj_mcode_sync(void *start, void *end)
44 sys_icache_invalidate(start, (char *)end-(char *)start); 45 sys_icache_invalidate(start, (char *)end-(char *)start);
45#elif LJ_TARGET_PPC 46#elif LJ_TARGET_PPC
46 lj_vm_cachesync(start, end); 47 lj_vm_cachesync(start, end);
47#elif defined(__GNUC__) 48#elif defined(__GNUC__) || defined(__clang__)
48 __clear_cache(start, end); 49 __clear_cache(start, end);
49#else 50#else
50#error "Missing builtin to flush instruction cache" 51#error "Missing builtin to flush instruction cache"
@@ -66,8 +67,8 @@ void lj_mcode_sync(void *start, void *end)
66 67
67static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot) 68static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot)
68{ 69{
69 void *p = VirtualAlloc((void *)hint, sz, 70 void *p = LJ_WIN_VALLOC((void *)hint, sz,
70 MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot); 71 MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot);
71 if (!p && !hint) 72 if (!p && !hint)
72 lj_trace_err(J, LJ_TRERR_MCODEAL); 73 lj_trace_err(J, LJ_TRERR_MCODEAL);
73 return p; 74 return p;
@@ -82,7 +83,7 @@ static void mcode_free(jit_State *J, void *p, size_t sz)
82static int mcode_setprot(void *p, size_t sz, DWORD prot) 83static int mcode_setprot(void *p, size_t sz, DWORD prot)
83{ 84{
84 DWORD oprot; 85 DWORD oprot;
85 return !VirtualProtect(p, sz, prot, &oprot); 86 return !LJ_WIN_VPROTECT(p, sz, prot, &oprot);
86} 87}
87 88
88#elif LJ_TARGET_POSIX 89#elif LJ_TARGET_POSIX
@@ -96,10 +97,15 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot)
96#define MCPROT_RW (PROT_READ|PROT_WRITE) 97#define MCPROT_RW (PROT_READ|PROT_WRITE)
97#define MCPROT_RX (PROT_READ|PROT_EXEC) 98#define MCPROT_RX (PROT_READ|PROT_EXEC)
98#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) 99#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
100#ifdef PROT_MPROTECT
101#define MCPROT_CREATE (PROT_MPROTECT(MCPROT_RWX))
102#else
103#define MCPROT_CREATE 0
104#endif
99 105
100static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) 106static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
101{ 107{
102 void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 108 void *p = mmap((void *)hint, sz, prot|MCPROT_CREATE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
103 if (p == MAP_FAILED) { 109 if (p == MAP_FAILED) {
104 if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); 110 if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL);
105 p = NULL; 111 p = NULL;
@@ -118,52 +124,34 @@ static int mcode_setprot(void *p, size_t sz, int prot)
118 return mprotect(p, sz, prot); 124 return mprotect(p, sz, prot);
119} 125}
120 126
121#elif LJ_64
122
123#error "Missing OS support for explicit placement of executable memory"
124
125#else 127#else
126 128
127/* Fallback allocator. This will fail if memory is not executable by default. */ 129#error "Missing OS support for explicit placement of executable memory"
128#define LUAJIT_UNPROTECT_MCODE
129#define MCPROT_RW 0
130#define MCPROT_RX 0
131#define MCPROT_RWX 0
132
133static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
134{
135 UNUSED(hint); UNUSED(prot);
136 return lj_mem_new(J->L, sz);
137}
138
139static void mcode_free(jit_State *J, void *p, size_t sz)
140{
141 lj_mem_free(J2G(J), p, sz);
142}
143 130
144#endif 131#endif
145 132
146/* -- MCode area protection ----------------------------------------------- */ 133/* -- MCode area protection ----------------------------------------------- */
147 134
148/* Define this ONLY if page protection twiddling becomes a bottleneck. */ 135#if LUAJIT_SECURITY_MCODE == 0
149#ifdef LUAJIT_UNPROTECT_MCODE
150 136
151/* It's generally considered to be a potential security risk to have 137/* Define this ONLY if page protection twiddling becomes a bottleneck.
138**
139** It's generally considered to be a potential security risk to have
152** pages with simultaneous write *and* execute access in a process. 140** pages with simultaneous write *and* execute access in a process.
153** 141**
154** Do not even think about using this mode for server processes or 142** Do not even think about using this mode for server processes or
155** apps handling untrusted external data (such as a browser). 143** apps handling untrusted external data.
156** 144**
157** The security risk is not in LuaJIT itself -- but if an adversary finds 145** The security risk is not in LuaJIT itself -- but if an adversary finds
158** any *other* flaw in your C application logic, then any RWX memory page 146** any *other* flaw in your C application logic, then any RWX memory pages
159** simplifies writing an exploit considerably. 147** simplify writing an exploit considerably.
160*/ 148*/
161#define MCPROT_GEN MCPROT_RWX 149#define MCPROT_GEN MCPROT_RWX
162#define MCPROT_RUN MCPROT_RWX 150#define MCPROT_RUN MCPROT_RWX
163 151
164static void mcode_protect(jit_State *J, int prot) 152static void mcode_protect(jit_State *J, int prot)
165{ 153{
166 UNUSED(J); UNUSED(prot); 154 UNUSED(J); UNUSED(prot); UNUSED(mcode_setprot);
167} 155}
168 156
169#else 157#else
@@ -221,8 +209,8 @@ static void *mcode_alloc(jit_State *J, size_t sz)
221 */ 209 */
222#if LJ_TARGET_MIPS 210#if LJ_TARGET_MIPS
223 /* Use the middle of the 256MB-aligned region. */ 211 /* Use the middle of the 256MB-aligned region. */
224 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) + 212 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler &
225 0x08000000u; 213 ~(uintptr_t)0x0fffffffu) + 0x08000000u;
226#else 214#else
227 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; 215 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff;
228#endif 216#endif
@@ -242,7 +230,7 @@ static void *mcode_alloc(jit_State *J, size_t sz)
242 } 230 }
243 /* Next try probing 64K-aligned pseudo-random addresses. */ 231 /* Next try probing 64K-aligned pseudo-random addresses. */
244 do { 232 do {
245 hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16; 233 hint = lj_prng_u64(&J2G(J)->prng) & ((1u<<LJ_TARGET_JUMPRANGE)-0x10000);
246 } while (!(hint + sz < range+range)); 234 } while (!(hint + sz < range+range));
247 hint = target + hint - range; 235 hint = target + hint - range;
248 } 236 }
@@ -255,7 +243,7 @@ static void *mcode_alloc(jit_State *J, size_t sz)
255/* All memory addresses are reachable by relative jumps. */ 243/* All memory addresses are reachable by relative jumps. */
256static void *mcode_alloc(jit_State *J, size_t sz) 244static void *mcode_alloc(jit_State *J, size_t sz)
257{ 245{
258#ifdef __OpenBSD__ 246#if defined(__OpenBSD__) || defined(__NetBSD__) || LJ_TARGET_UWP
259 /* Allow better executable memory allocation for OpenBSD W^X mode. */ 247 /* Allow better executable memory allocation for OpenBSD W^X mode. */
260 void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN); 248 void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN);
261 if (p && mcode_setprot(p, sz, MCPROT_GEN)) { 249 if (p && mcode_setprot(p, sz, MCPROT_GEN)) {
@@ -286,6 +274,7 @@ static void mcode_allocarea(jit_State *J)
286 ((MCLink *)J->mcarea)->next = oldarea; 274 ((MCLink *)J->mcarea)->next = oldarea;
287 ((MCLink *)J->mcarea)->size = sz; 275 ((MCLink *)J->mcarea)->size = sz;
288 J->szallmcarea += sz; 276 J->szallmcarea += sz;
277 J->mcbot = (MCode *)lj_err_register_mcode(J->mcarea, sz, (uint8_t *)J->mcbot);
289} 278}
290 279
291/* Free all MCode areas. */ 280/* Free all MCode areas. */
@@ -296,7 +285,9 @@ void lj_mcode_free(jit_State *J)
296 J->szallmcarea = 0; 285 J->szallmcarea = 0;
297 while (mc) { 286 while (mc) {
298 MCode *next = ((MCLink *)mc)->next; 287 MCode *next = ((MCLink *)mc)->next;
299 mcode_free(J, mc, ((MCLink *)mc)->size); 288 size_t sz = ((MCLink *)mc)->size;
289 lj_err_deregister_mcode(mc, sz, (uint8_t *)mc + sizeof(MCLink));
290 mcode_free(J, mc, sz);
300 mc = next; 291 mc = next;
301 } 292 }
302} 293}
@@ -331,35 +322,36 @@ void lj_mcode_abort(jit_State *J)
331/* Set/reset protection to allow patching of MCode areas. */ 322/* Set/reset protection to allow patching of MCode areas. */
332MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) 323MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
333{ 324{
334#ifdef LUAJIT_UNPROTECT_MCODE
335 UNUSED(J); UNUSED(ptr); UNUSED(finish);
336 return NULL;
337#else
338 if (finish) { 325 if (finish) {
326#if LUAJIT_SECURITY_MCODE
339 if (J->mcarea == ptr) 327 if (J->mcarea == ptr)
340 mcode_protect(J, MCPROT_RUN); 328 mcode_protect(J, MCPROT_RUN);
341 else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN))) 329 else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN)))
342 mcode_protfail(J); 330 mcode_protfail(J);
331#endif
343 return NULL; 332 return NULL;
344 } else { 333 } else {
345 MCode *mc = J->mcarea; 334 MCode *mc = J->mcarea;
346 /* Try current area first to use the protection cache. */ 335 /* Try current area first to use the protection cache. */
347 if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) { 336 if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) {
337#if LUAJIT_SECURITY_MCODE
348 mcode_protect(J, MCPROT_GEN); 338 mcode_protect(J, MCPROT_GEN);
339#endif
349 return mc; 340 return mc;
350 } 341 }
351 /* Otherwise search through the list of MCode areas. */ 342 /* Otherwise search through the list of MCode areas. */
352 for (;;) { 343 for (;;) {
353 mc = ((MCLink *)mc)->next; 344 mc = ((MCLink *)mc)->next;
354 lua_assert(mc != NULL); 345 lj_assertJ(mc != NULL, "broken MCode area chain");
355 if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) { 346 if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) {
347#if LUAJIT_SECURITY_MCODE
356 if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN))) 348 if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN)))
357 mcode_protfail(J); 349 mcode_protfail(J);
350#endif
358 return mc; 351 return mc;
359 } 352 }
360 } 353 }
361 } 354 }
362#endif
363} 355}
364 356
365/* Limit of MCode reservation reached. */ 357/* Limit of MCode reservation reached. */