summaryrefslogtreecommitdiff
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 7013cd7d..94767937 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
@@ -222,8 +210,8 @@ static void *mcode_alloc(jit_State *J, size_t sz)
222 */ 210 */
223#if LJ_TARGET_MIPS 211#if LJ_TARGET_MIPS
224 /* Use the middle of the 256MB-aligned region. */ 212 /* Use the middle of the 256MB-aligned region. */
225 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) + 213 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler &
226 0x08000000u; 214 ~(uintptr_t)0x0fffffffu) + 0x08000000u;
227#else 215#else
228 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; 216 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff;
229#endif 217#endif
@@ -243,7 +231,7 @@ static void *mcode_alloc(jit_State *J, size_t sz)
243 } 231 }
244 /* Next try probing 64K-aligned pseudo-random addresses. */ 232 /* Next try probing 64K-aligned pseudo-random addresses. */
245 do { 233 do {
246 hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16; 234 hint = lj_prng_u64(&J2G(J)->prng) & ((1u<<LJ_TARGET_JUMPRANGE)-0x10000);
247 } while (!(hint + sz < range+range)); 235 } while (!(hint + sz < range+range));
248 hint = target + hint - range; 236 hint = target + hint - range;
249 } 237 }
@@ -256,7 +244,7 @@ static void *mcode_alloc(jit_State *J, size_t sz)
256/* All memory addresses are reachable by relative jumps. */ 244/* All memory addresses are reachable by relative jumps. */
257static void *mcode_alloc(jit_State *J, size_t sz) 245static void *mcode_alloc(jit_State *J, size_t sz)
258{ 246{
259#ifdef __OpenBSD__ 247#if defined(__OpenBSD__) || defined(__NetBSD__) || LJ_TARGET_UWP
260 /* Allow better executable memory allocation for OpenBSD W^X mode. */ 248 /* Allow better executable memory allocation for OpenBSD W^X mode. */
261 void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN); 249 void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN);
262 if (p && mcode_setprot(p, sz, MCPROT_GEN)) { 250 if (p && mcode_setprot(p, sz, MCPROT_GEN)) {
@@ -287,6 +275,7 @@ static void mcode_allocarea(jit_State *J)
287 ((MCLink *)J->mcarea)->next = oldarea; 275 ((MCLink *)J->mcarea)->next = oldarea;
288 ((MCLink *)J->mcarea)->size = sz; 276 ((MCLink *)J->mcarea)->size = sz;
289 J->szallmcarea += sz; 277 J->szallmcarea += sz;
278 J->mcbot = (MCode *)lj_err_register_mcode(J->mcarea, sz, (uint8_t *)J->mcbot);
290} 279}
291 280
292/* Free all MCode areas. */ 281/* Free all MCode areas. */
@@ -297,7 +286,9 @@ void lj_mcode_free(jit_State *J)
297 J->szallmcarea = 0; 286 J->szallmcarea = 0;
298 while (mc) { 287 while (mc) {
299 MCode *next = ((MCLink *)mc)->next; 288 MCode *next = ((MCLink *)mc)->next;
300 mcode_free(J, mc, ((MCLink *)mc)->size); 289 size_t sz = ((MCLink *)mc)->size;
290 lj_err_deregister_mcode(mc, sz, (uint8_t *)mc + sizeof(MCLink));
291 mcode_free(J, mc, sz);
301 mc = next; 292 mc = next;
302 } 293 }
303} 294}
@@ -332,35 +323,36 @@ void lj_mcode_abort(jit_State *J)
332/* Set/reset protection to allow patching of MCode areas. */ 323/* Set/reset protection to allow patching of MCode areas. */
333MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) 324MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
334{ 325{
335#ifdef LUAJIT_UNPROTECT_MCODE
336 UNUSED(J); UNUSED(ptr); UNUSED(finish);
337 return NULL;
338#else
339 if (finish) { 326 if (finish) {
327#if LUAJIT_SECURITY_MCODE
340 if (J->mcarea == ptr) 328 if (J->mcarea == ptr)
341 mcode_protect(J, MCPROT_RUN); 329 mcode_protect(J, MCPROT_RUN);
342 else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN))) 330 else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN)))
343 mcode_protfail(J); 331 mcode_protfail(J);
332#endif
344 return NULL; 333 return NULL;
345 } else { 334 } else {
346 MCode *mc = J->mcarea; 335 MCode *mc = J->mcarea;
347 /* Try current area first to use the protection cache. */ 336 /* Try current area first to use the protection cache. */
348 if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) { 337 if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) {
338#if LUAJIT_SECURITY_MCODE
349 mcode_protect(J, MCPROT_GEN); 339 mcode_protect(J, MCPROT_GEN);
340#endif
350 return mc; 341 return mc;
351 } 342 }
352 /* Otherwise search through the list of MCode areas. */ 343 /* Otherwise search through the list of MCode areas. */
353 for (;;) { 344 for (;;) {
354 mc = ((MCLink *)mc)->next; 345 mc = ((MCLink *)mc)->next;
355 lua_assert(mc != NULL); 346 lj_assertJ(mc != NULL, "broken MCode area chain");
356 if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) { 347 if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) {
348#if LUAJIT_SECURITY_MCODE
357 if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN))) 349 if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN)))
358 mcode_protfail(J); 350 mcode_protfail(J);
351#endif
359 return mc; 352 return mc;
360 } 353 }
361 } 354 }
362 } 355 }
363#endif
364} 356}
365 357
366/* Limit of MCode reservation reached. */ 358/* Limit of MCode reservation reached. */