diff options
Diffstat (limited to 'src/lj_mcode.c')
-rw-r--r-- | src/lj_mcode.c | 78 |
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 | ||
67 | static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot) | 68 | static 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) | |||
82 | static int mcode_setprot(void *p, size_t sz, DWORD prot) | 83 | static 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 | ||
100 | static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) | 106 | static 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 | |||
133 | static 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 | |||
139 | static 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 | ||
164 | static void mcode_protect(jit_State *J, int prot) | 152 | static 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. */ |
256 | static void *mcode_alloc(jit_State *J, size_t sz) | 244 | static 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. */ |
332 | MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) | 323 | MCode *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. */ |