diff options
Diffstat (limited to 'src/lj_mcode.c')
| -rw-r--r-- | src/lj_mcode.c | 320 |
1 files changed, 198 insertions, 122 deletions
diff --git a/src/lj_mcode.c b/src/lj_mcode.c index 6e8457ba..edcc4bd9 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" |
| @@ -28,6 +29,11 @@ | |||
| 28 | #include <valgrind/valgrind.h> | 29 | #include <valgrind/valgrind.h> |
| 29 | #endif | 30 | #endif |
| 30 | 31 | ||
| 32 | #if LJ_TARGET_WINDOWS | ||
| 33 | #define WIN32_LEAN_AND_MEAN | ||
| 34 | #include <windows.h> | ||
| 35 | #endif | ||
| 36 | |||
| 31 | #if LJ_TARGET_IOS | 37 | #if LJ_TARGET_IOS |
| 32 | void sys_icache_invalidate(void *start, size_t len); | 38 | void sys_icache_invalidate(void *start, size_t len); |
| 33 | #endif | 39 | #endif |
| @@ -40,11 +46,13 @@ void lj_mcode_sync(void *start, void *end) | |||
| 40 | #endif | 46 | #endif |
| 41 | #if LJ_TARGET_X86ORX64 | 47 | #if LJ_TARGET_X86ORX64 |
| 42 | UNUSED(start); UNUSED(end); | 48 | UNUSED(start); UNUSED(end); |
| 49 | #elif LJ_TARGET_WINDOWS | ||
| 50 | FlushInstructionCache(GetCurrentProcess(), start, (char *)end-(char *)start); | ||
| 43 | #elif LJ_TARGET_IOS | 51 | #elif LJ_TARGET_IOS |
| 44 | sys_icache_invalidate(start, (char *)end-(char *)start); | 52 | sys_icache_invalidate(start, (char *)end-(char *)start); |
| 45 | #elif LJ_TARGET_PPC | 53 | #elif LJ_TARGET_PPC |
| 46 | lj_vm_cachesync(start, end); | 54 | lj_vm_cachesync(start, end); |
| 47 | #elif defined(__GNUC__) | 55 | #elif defined(__GNUC__) || defined(__clang__) |
| 48 | __clear_cache(start, end); | 56 | __clear_cache(start, end); |
| 49 | #else | 57 | #else |
| 50 | #error "Missing builtin to flush instruction cache" | 58 | #error "Missing builtin to flush instruction cache" |
| @@ -55,34 +63,46 @@ void lj_mcode_sync(void *start, void *end) | |||
| 55 | 63 | ||
| 56 | #if LJ_HASJIT | 64 | #if LJ_HASJIT |
| 57 | 65 | ||
| 58 | #if LJ_TARGET_WINDOWS | 66 | #if LUAJIT_SECURITY_MCODE != 0 |
| 67 | /* Protection twiddling failed. Probably due to kernel security. */ | ||
| 68 | static LJ_NORET LJ_NOINLINE void mcode_protfail(jit_State *J) | ||
| 69 | { | ||
| 70 | lua_CFunction panic = J2G(J)->panic; | ||
| 71 | if (panic) { | ||
| 72 | lua_State *L = J->L; | ||
| 73 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_JITPROT)); | ||
| 74 | panic(L); | ||
| 75 | } | ||
| 76 | exit(EXIT_FAILURE); | ||
| 77 | } | ||
| 78 | #endif | ||
| 59 | 79 | ||
| 60 | #define WIN32_LEAN_AND_MEAN | 80 | #if LJ_TARGET_WINDOWS |
| 61 | #include <windows.h> | ||
| 62 | 81 | ||
| 63 | #define MCPROT_RW PAGE_READWRITE | 82 | #define MCPROT_RW PAGE_READWRITE |
| 64 | #define MCPROT_RX PAGE_EXECUTE_READ | 83 | #define MCPROT_RX PAGE_EXECUTE_READ |
| 65 | #define MCPROT_RWX PAGE_EXECUTE_READWRITE | 84 | #define MCPROT_RWX PAGE_EXECUTE_READWRITE |
| 66 | 85 | ||
| 67 | static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot) | 86 | static void *mcode_alloc_at(uintptr_t hint, size_t sz, DWORD prot) |
| 68 | { | 87 | { |
| 69 | void *p = VirtualAlloc((void *)hint, sz, | 88 | return LJ_WIN_VALLOC((void *)hint, sz, |
| 70 | MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot); | 89 | MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot); |
| 71 | if (!p && !hint) | ||
| 72 | lj_trace_err(J, LJ_TRERR_MCODEAL); | ||
| 73 | return p; | ||
| 74 | } | 90 | } |
| 75 | 91 | ||
| 76 | static void mcode_free(jit_State *J, void *p, size_t sz) | 92 | static void mcode_free(void *p, size_t sz) |
| 77 | { | 93 | { |
| 78 | UNUSED(J); UNUSED(sz); | 94 | UNUSED(sz); |
| 79 | VirtualFree(p, 0, MEM_RELEASE); | 95 | VirtualFree(p, 0, MEM_RELEASE); |
| 80 | } | 96 | } |
| 81 | 97 | ||
| 82 | static int mcode_setprot(void *p, size_t sz, DWORD prot) | 98 | static void mcode_setprot(jit_State *J, void *p, size_t sz, DWORD prot) |
| 83 | { | 99 | { |
| 100 | #if LUAJIT_SECURITY_MCODE != 0 | ||
| 84 | DWORD oprot; | 101 | DWORD oprot; |
| 85 | return !VirtualProtect(p, sz, prot, &oprot); | 102 | if (!LJ_WIN_VPROTECT(p, sz, prot, &oprot)) mcode_protfail(J); |
| 103 | #else | ||
| 104 | UNUSED(J); UNUSED(p); UNUSED(sz); UNUSED(prot); | ||
| 105 | #endif | ||
| 86 | } | 106 | } |
| 87 | 107 | ||
| 88 | #elif LJ_TARGET_POSIX | 108 | #elif LJ_TARGET_POSIX |
| @@ -93,70 +113,119 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot) | |||
| 93 | #define MAP_ANONYMOUS MAP_ANON | 113 | #define MAP_ANONYMOUS MAP_ANON |
| 94 | #endif | 114 | #endif |
| 95 | 115 | ||
| 116 | /* Check for macOS hardened runtime. */ | ||
| 117 | #if defined(LUAJIT_ENABLE_OSX_HRT) && LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000 | ||
| 118 | #include <pthread.h> | ||
| 119 | #define MCMAP_CREATE MAP_JIT | ||
| 120 | #else | ||
| 121 | #define MCMAP_CREATE 0 | ||
| 122 | #endif | ||
| 123 | |||
| 96 | #define MCPROT_RW (PROT_READ|PROT_WRITE) | 124 | #define MCPROT_RW (PROT_READ|PROT_WRITE) |
| 97 | #define MCPROT_RX (PROT_READ|PROT_EXEC) | 125 | #define MCPROT_RX (PROT_READ|PROT_EXEC) |
| 98 | #define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) | 126 | #define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) |
| 127 | #ifdef PROT_MPROTECT | ||
| 128 | #define MCPROT_CREATE (PROT_MPROTECT(MCPROT_RWX)) | ||
| 129 | #elif MCMAP_CREATE | ||
| 130 | #define MCPROT_CREATE PROT_EXEC | ||
| 131 | #else | ||
| 132 | #define MCPROT_CREATE 0 | ||
| 133 | #endif | ||
| 99 | 134 | ||
| 100 | static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) | 135 | static void *mcode_alloc_at(uintptr_t hint, size_t sz, int prot) |
| 101 | { | 136 | { |
| 102 | void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | 137 | void *p = mmap((void *)hint, sz, prot|MCPROT_CREATE, MAP_PRIVATE|MAP_ANONYMOUS|MCMAP_CREATE, -1, 0); |
| 103 | if (p == MAP_FAILED) { | 138 | if (p == MAP_FAILED) return NULL; |
| 104 | if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); | 139 | #if MCMAP_CREATE |
| 105 | p = NULL; | 140 | pthread_jit_write_protect_np(0); |
| 106 | } | 141 | #endif |
| 107 | return p; | 142 | return p; |
| 108 | } | 143 | } |
| 109 | 144 | ||
| 110 | static void mcode_free(jit_State *J, void *p, size_t sz) | 145 | static void mcode_free(void *p, size_t sz) |
| 111 | { | 146 | { |
| 112 | UNUSED(J); | ||
| 113 | munmap(p, sz); | 147 | munmap(p, sz); |
| 114 | } | 148 | } |
| 115 | 149 | ||
| 116 | static int mcode_setprot(void *p, size_t sz, int prot) | 150 | static void mcode_setprot(jit_State *J, void *p, size_t sz, int prot) |
| 117 | { | 151 | { |
| 118 | return mprotect(p, sz, prot); | 152 | #if LUAJIT_SECURITY_MCODE != 0 |
| 153 | #if MCMAP_CREATE | ||
| 154 | UNUSED(J); UNUSED(p); UNUSED(sz); | ||
| 155 | pthread_jit_write_protect_np((prot & PROT_EXEC)); | ||
| 156 | return 0; | ||
| 157 | #else | ||
| 158 | if (mprotect(p, sz, prot)) mcode_protfail(J); | ||
| 159 | #endif | ||
| 160 | #else | ||
| 161 | UNUSED(J); UNUSED(p); UNUSED(sz); UNUSED(prot); | ||
| 162 | #endif | ||
| 119 | } | 163 | } |
| 120 | 164 | ||
| 121 | #elif LJ_64 | ||
| 122 | |||
| 123 | #error "Missing OS support for explicit placement of executable memory" | ||
| 124 | |||
| 125 | #else | 165 | #else |
| 126 | 166 | ||
| 127 | /* Fallback allocator. This will fail if memory is not executable by default. */ | 167 | #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 | 168 | ||
| 133 | static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) | 169 | #endif |
| 134 | { | ||
| 135 | UNUSED(hint); UNUSED(prot); | ||
| 136 | return lj_mem_new(J->L, sz); | ||
| 137 | } | ||
| 138 | 170 | ||
| 139 | static void mcode_free(jit_State *J, void *p, size_t sz) | 171 | #ifdef LUAJIT_MCODE_TEST |
| 172 | /* Test wrapper for mcode allocation. DO NOT ENABLE in production! Try: | ||
| 173 | ** LUAJIT_MCODE_TEST=hhhhhhhhhhhhhhhh luajit -jv main.lua | ||
| 174 | ** LUAJIT_MCODE_TEST=F luajit -jv main.lua | ||
| 175 | */ | ||
| 176 | static void *mcode_alloc_at_TEST(jit_State *J, uintptr_t hint, size_t sz, int prot) | ||
| 140 | { | 177 | { |
| 141 | lj_mem_free(J2G(J), p, sz); | 178 | static int test_ofs = 0; |
| 179 | static const char *test_str; | ||
| 180 | if (!test_str) { | ||
| 181 | test_str = getenv("LUAJIT_MCODE_TEST"); | ||
| 182 | if (!test_str) test_str = ""; | ||
| 183 | } | ||
| 184 | switch (test_str[test_ofs]) { | ||
| 185 | case 'a': /* OK for one allocation. */ | ||
| 186 | test_ofs++; | ||
| 187 | /* fallthrough */ | ||
| 188 | case '\0': /* EOS: OK for any further allocations. */ | ||
| 189 | break; | ||
| 190 | case 'h': /* Ignore one hint. */ | ||
| 191 | test_ofs++; | ||
| 192 | /* fallthrough */ | ||
| 193 | case 'H': /* Ignore any further hints. */ | ||
| 194 | hint = 0u; | ||
| 195 | break; | ||
| 196 | case 'r': /* Randomize one hint. */ | ||
| 197 | test_ofs++; | ||
| 198 | /* fallthrough */ | ||
| 199 | case 'R': /* Randomize any further hints. */ | ||
| 200 | hint = lj_prng_u64(&J2G(J)->prng) & ~(uintptr_t)0xffffu; | ||
| 201 | hint &= ((uintptr_t)1 << (LJ_64 ? 47 : 31)) - 1; | ||
| 202 | break; | ||
| 203 | case 'f': /* Fail one allocation. */ | ||
| 204 | test_ofs++; | ||
| 205 | /* fallthrough */ | ||
| 206 | default: /* 'F' or unknown: Fail any further allocations. */ | ||
| 207 | return NULL; | ||
| 208 | } | ||
| 209 | return mcode_alloc_at(hint, sz, prot); | ||
| 142 | } | 210 | } |
| 143 | 211 | #define mcode_alloc_at(hint, sz, prot) mcode_alloc_at_TEST(J, hint, sz, prot) | |
| 144 | #endif | 212 | #endif |
| 145 | 213 | ||
| 146 | /* -- MCode area protection ----------------------------------------------- */ | 214 | /* -- MCode area protection ----------------------------------------------- */ |
| 147 | 215 | ||
| 148 | /* Define this ONLY if page protection twiddling becomes a bottleneck. */ | 216 | #if LUAJIT_SECURITY_MCODE == 0 |
| 149 | #ifdef LUAJIT_UNPROTECT_MCODE | ||
| 150 | 217 | ||
| 151 | /* It's generally considered to be a potential security risk to have | 218 | /* Define this ONLY if page protection twiddling becomes a bottleneck. |
| 219 | ** | ||
| 220 | ** It's generally considered to be a potential security risk to have | ||
| 152 | ** pages with simultaneous write *and* execute access in a process. | 221 | ** pages with simultaneous write *and* execute access in a process. |
| 153 | ** | 222 | ** |
| 154 | ** Do not even think about using this mode for server processes or | 223 | ** Do not even think about using this mode for server processes or |
| 155 | ** apps handling untrusted external data (such as a browser). | 224 | ** apps handling untrusted external data. |
| 156 | ** | 225 | ** |
| 157 | ** The security risk is not in LuaJIT itself -- but if an adversary finds | 226 | ** 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 | 227 | ** any *other* flaw in your C application logic, then any RWX memory pages |
| 159 | ** simplifies writing an exploit considerably. | 228 | ** simplify writing an exploit considerably. |
| 160 | */ | 229 | */ |
| 161 | #define MCPROT_GEN MCPROT_RWX | 230 | #define MCPROT_GEN MCPROT_RWX |
| 162 | #define MCPROT_RUN MCPROT_RWX | 231 | #define MCPROT_RUN MCPROT_RWX |
| @@ -179,24 +248,11 @@ static void mcode_protect(jit_State *J, int prot) | |||
| 179 | #define MCPROT_GEN MCPROT_RW | 248 | #define MCPROT_GEN MCPROT_RW |
| 180 | #define MCPROT_RUN MCPROT_RX | 249 | #define MCPROT_RUN MCPROT_RX |
| 181 | 250 | ||
| 182 | /* Protection twiddling failed. Probably due to kernel security. */ | ||
| 183 | static LJ_NORET LJ_NOINLINE void mcode_protfail(jit_State *J) | ||
| 184 | { | ||
| 185 | lua_CFunction panic = J2G(J)->panic; | ||
| 186 | if (panic) { | ||
| 187 | lua_State *L = J->L; | ||
| 188 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_JITPROT)); | ||
| 189 | panic(L); | ||
| 190 | } | ||
| 191 | exit(EXIT_FAILURE); | ||
| 192 | } | ||
| 193 | |||
| 194 | /* Change protection of MCode area. */ | 251 | /* Change protection of MCode area. */ |
| 195 | static void mcode_protect(jit_State *J, int prot) | 252 | static void mcode_protect(jit_State *J, int prot) |
| 196 | { | 253 | { |
| 197 | if (J->mcprot != prot) { | 254 | if (J->mcprot != prot) { |
| 198 | if (LJ_UNLIKELY(mcode_setprot(J->mcarea, J->szmcarea, prot))) | 255 | mcode_setprot(J, J->mcarea, J->szmcarea, prot); |
| 199 | mcode_protfail(J); | ||
| 200 | J->mcprot = prot; | 256 | J->mcprot = prot; |
| 201 | } | 257 | } |
| 202 | } | 258 | } |
| @@ -205,47 +261,74 @@ static void mcode_protect(jit_State *J, int prot) | |||
| 205 | 261 | ||
| 206 | /* -- MCode area allocation ----------------------------------------------- */ | 262 | /* -- MCode area allocation ----------------------------------------------- */ |
| 207 | 263 | ||
| 208 | #if LJ_64 | ||
| 209 | #define mcode_validptr(p) (p) | ||
| 210 | #else | ||
| 211 | #define mcode_validptr(p) ((p) && (uintptr_t)(p) < 0xffff0000) | ||
| 212 | #endif | ||
| 213 | |||
| 214 | #ifdef LJ_TARGET_JUMPRANGE | 264 | #ifdef LJ_TARGET_JUMPRANGE |
| 215 | 265 | ||
| 216 | /* Get memory within relative jump distance of our code in 64 bit mode. */ | 266 | #define MCODE_RANGE64 ((1u << LJ_TARGET_JUMPRANGE) - 0x10000u) |
| 217 | static void *mcode_alloc(jit_State *J, size_t sz) | 267 | |
| 268 | /* Set a memory range for mcode allocation with addr in the middle. */ | ||
| 269 | static void mcode_setrange(jit_State *J, uintptr_t addr) | ||
| 218 | { | 270 | { |
| 219 | /* Target an address in the static assembler code (64K aligned). | ||
| 220 | ** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB. | ||
| 221 | ** Use half the jump range so every address in the range can reach any other. | ||
| 222 | */ | ||
| 223 | #if LJ_TARGET_MIPS | 271 | #if LJ_TARGET_MIPS |
| 224 | /* Use the middle of the 256MB-aligned region. */ | 272 | /* Use the whole 256MB-aligned region. */ |
| 225 | uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) + | 273 | J->mcmin = addr & ~(uintptr_t)((1u << LJ_TARGET_JUMPRANGE) - 1); |
| 226 | 0x08000000u; | 274 | J->mcmax = J->mcmin + (1u << LJ_TARGET_JUMPRANGE); |
| 227 | #else | 275 | #else |
| 228 | uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; | 276 | /* Every address in the 64KB-aligned range should be able to reach |
| 277 | ** any other, so MCODE_RANGE64 is only half the (signed) branch range. | ||
| 278 | */ | ||
| 279 | J->mcmin = (addr - (MCODE_RANGE64 >> 1) + 0xffffu) & ~(uintptr_t)0xffffu; | ||
| 280 | J->mcmax = J->mcmin + MCODE_RANGE64; | ||
| 229 | #endif | 281 | #endif |
| 230 | const uintptr_t range = (1u << (LJ_TARGET_JUMPRANGE-1)) - (1u << 21); | 282 | /* Avoid wrap-around and the 64KB corners. */ |
| 231 | /* First try a contiguous area below the last one. */ | 283 | if (addr < J->mcmin || !J->mcmin) J->mcmin = 0x10000u; |
| 232 | uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0; | 284 | if (addr > J->mcmax) J->mcmax = ~(uintptr_t)0xffffu; |
| 233 | int i; | 285 | } |
| 234 | /* Limit probing iterations, depending on the available pool size. */ | 286 | |
| 235 | for (i = 0; i < LJ_TARGET_JUMPRANGE; i++) { | 287 | /* Check if an address is in range of the mcode allocation range. */ |
| 236 | if (mcode_validptr(hint)) { | 288 | static LJ_AINLINE int mcode_inrange(jit_State *J, uintptr_t addr, size_t sz) |
| 237 | void *p = mcode_alloc_at(J, hint, sz, MCPROT_GEN); | 289 | { |
| 238 | 290 | /* Take care of unsigned wrap-around of addr + sz, too. */ | |
| 239 | if (mcode_validptr(p) && | 291 | return addr >= J->mcmin && addr + sz >= J->mcmin && addr + sz <= J->mcmax; |
| 240 | ((uintptr_t)p + sz - target < range || target - (uintptr_t)p < range)) | 292 | } |
| 241 | return p; | 293 | |
| 242 | if (p) mcode_free(J, p, sz); /* Free badly placed area. */ | 294 | /* Get memory within a specific jump range in 64 bit mode. */ |
| 243 | } | 295 | static void *mcode_alloc(jit_State *J, size_t sz) |
| 244 | /* Next try probing 64K-aligned pseudo-random addresses. */ | 296 | { |
| 297 | uintptr_t hint; | ||
| 298 | int i = 0, j; | ||
| 299 | if (!J->mcmin) /* Place initial range near the interpreter code. */ | ||
| 300 | mcode_setrange(J, (uintptr_t)(void *)lj_vm_exit_handler); | ||
| 301 | else if (!J->mcmax) /* Switch to a new range (already flushed). */ | ||
| 302 | goto newrange; | ||
| 303 | /* First try a contiguous area below the last one (if in range). */ | ||
| 304 | hint = (uintptr_t)J->mcarea - sz; | ||
| 305 | if (!mcode_inrange(J, hint, sz)) /* Also takes care of NULL J->mcarea. */ | ||
| 306 | goto probe; | ||
| 307 | for (; i < 16; i++) { | ||
| 308 | void *p = mcode_alloc_at(hint, sz, MCPROT_GEN); | ||
| 309 | if (mcode_inrange(J, (uintptr_t)p, sz)) | ||
| 310 | return p; /* Success. */ | ||
| 311 | else if (p) | ||
| 312 | mcode_free(p, sz); /* Free badly placed area. */ | ||
| 313 | probe: | ||
| 314 | /* Next try probing 64KB-aligned pseudo-random addresses. */ | ||
| 315 | j = 0; | ||
| 245 | do { | 316 | do { |
| 246 | hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16; | 317 | hint = J->mcmin + (lj_prng_u64(&J2G(J)->prng) & MCODE_RANGE64); |
| 247 | } while (!(hint + sz < range+range)); | 318 | if (++j > 15) goto fail; |
| 248 | hint = target + hint - range; | 319 | } while (!mcode_inrange(J, hint, sz)); |
| 320 | } | ||
| 321 | fail: | ||
| 322 | if (!J->mcarea) { /* Switch to a new range now. */ | ||
| 323 | void *p; | ||
| 324 | newrange: | ||
| 325 | p = mcode_alloc_at(0, sz, MCPROT_GEN); | ||
| 326 | if (p) { | ||
| 327 | mcode_setrange(J, (uintptr_t)p + (sz >> 1)); | ||
| 328 | return p; /* Success. */ | ||
| 329 | } | ||
| 330 | } else { | ||
| 331 | J->mcmax = 0; /* Switch to a new range after the flush. */ | ||
| 249 | } | 332 | } |
| 250 | lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */ | 333 | lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */ |
| 251 | return NULL; | 334 | return NULL; |
| @@ -256,17 +339,15 @@ static void *mcode_alloc(jit_State *J, size_t sz) | |||
| 256 | /* All memory addresses are reachable by relative jumps. */ | 339 | /* All memory addresses are reachable by relative jumps. */ |
| 257 | static void *mcode_alloc(jit_State *J, size_t sz) | 340 | static void *mcode_alloc(jit_State *J, size_t sz) |
| 258 | { | 341 | { |
| 259 | #ifdef __OpenBSD__ | 342 | #if defined(__OpenBSD__) || defined(__NetBSD__) || LJ_TARGET_UWP |
| 260 | /* Allow better executable memory allocation for OpenBSD W^X mode. */ | 343 | /* Allow better executable memory allocation for OpenBSD W^X mode. */ |
| 261 | void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN); | 344 | void *p = mcode_alloc_at(0, sz, MCPROT_RUN); |
| 262 | if (p && mcode_setprot(p, sz, MCPROT_GEN)) { | 345 | if (p) mcode_setprot(J, p, sz, MCPROT_GEN); |
| 263 | mcode_free(J, p, sz); | ||
| 264 | return NULL; | ||
| 265 | } | ||
| 266 | return p; | ||
| 267 | #else | 346 | #else |
| 268 | return mcode_alloc_at(J, 0, sz, MCPROT_GEN); | 347 | void *p = mcode_alloc_at(0, sz, MCPROT_GEN); |
| 269 | #endif | 348 | #endif |
| 349 | if (!p) lj_trace_err(J, LJ_TRERR_MCODEAL); | ||
| 350 | return p; | ||
| 270 | } | 351 | } |
| 271 | 352 | ||
| 272 | #endif | 353 | #endif |
| @@ -278,7 +359,6 @@ static void mcode_allocarea(jit_State *J) | |||
| 278 | { | 359 | { |
| 279 | MCode *oldarea = J->mcarea; | 360 | MCode *oldarea = J->mcarea; |
| 280 | size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10; | 361 | size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10; |
| 281 | sz = (sz + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1); | ||
| 282 | J->mcarea = (MCode *)mcode_alloc(J, sz); | 362 | J->mcarea = (MCode *)mcode_alloc(J, sz); |
| 283 | J->szmcarea = sz; | 363 | J->szmcarea = sz; |
| 284 | J->mcprot = MCPROT_GEN; | 364 | J->mcprot = MCPROT_GEN; |
| @@ -287,6 +367,7 @@ static void mcode_allocarea(jit_State *J) | |||
| 287 | ((MCLink *)J->mcarea)->next = oldarea; | 367 | ((MCLink *)J->mcarea)->next = oldarea; |
| 288 | ((MCLink *)J->mcarea)->size = sz; | 368 | ((MCLink *)J->mcarea)->size = sz; |
| 289 | J->szallmcarea += sz; | 369 | J->szallmcarea += sz; |
| 370 | J->mcbot = (MCode *)lj_err_register_mcode(J->mcarea, sz, (uint8_t *)J->mcbot); | ||
| 290 | } | 371 | } |
| 291 | 372 | ||
| 292 | /* Free all MCode areas. */ | 373 | /* Free all MCode areas. */ |
| @@ -297,7 +378,9 @@ void lj_mcode_free(jit_State *J) | |||
| 297 | J->szallmcarea = 0; | 378 | J->szallmcarea = 0; |
| 298 | while (mc) { | 379 | while (mc) { |
| 299 | MCode *next = ((MCLink *)mc)->next; | 380 | MCode *next = ((MCLink *)mc)->next; |
| 300 | mcode_free(J, mc, ((MCLink *)mc)->size); | 381 | size_t sz = ((MCLink *)mc)->size; |
| 382 | lj_err_deregister_mcode(mc, sz, (uint8_t *)mc + sizeof(MCLink)); | ||
| 383 | mcode_free(mc, sz); | ||
| 301 | mc = next; | 384 | mc = next; |
| 302 | } | 385 | } |
| 303 | } | 386 | } |
| @@ -332,35 +415,29 @@ void lj_mcode_abort(jit_State *J) | |||
| 332 | /* Set/reset protection to allow patching of MCode areas. */ | 415 | /* Set/reset protection to allow patching of MCode areas. */ |
| 333 | MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) | 416 | MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) |
| 334 | { | 417 | { |
| 335 | #ifdef LUAJIT_UNPROTECT_MCODE | ||
| 336 | UNUSED(J); UNUSED(ptr); UNUSED(finish); | ||
| 337 | return NULL; | ||
| 338 | #else | ||
| 339 | if (finish) { | 418 | if (finish) { |
| 340 | if (J->mcarea == ptr) | 419 | if (J->mcarea == ptr) |
| 341 | mcode_protect(J, MCPROT_RUN); | 420 | mcode_protect(J, MCPROT_RUN); |
| 342 | else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN))) | 421 | else |
| 343 | mcode_protfail(J); | 422 | mcode_setprot(J, ptr, ((MCLink *)ptr)->size, MCPROT_RUN); |
| 344 | return NULL; | 423 | return NULL; |
| 345 | } else { | 424 | } else { |
| 346 | MCode *mc = J->mcarea; | 425 | uintptr_t base = (uintptr_t)J->mcarea, addr = (uintptr_t)ptr; |
| 347 | /* Try current area first to use the protection cache. */ | 426 | /* Try current area first to use the protection cache. */ |
| 348 | if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) { | 427 | if (addr >= base && addr < base + J->szmcarea) { |
| 349 | mcode_protect(J, MCPROT_GEN); | 428 | mcode_protect(J, MCPROT_GEN); |
| 350 | return mc; | 429 | return (MCode *)base; |
| 351 | } | 430 | } |
| 352 | /* Otherwise search through the list of MCode areas. */ | 431 | /* Otherwise search through the list of MCode areas. */ |
| 353 | for (;;) { | 432 | for (;;) { |
| 354 | mc = ((MCLink *)mc)->next; | 433 | base = (uintptr_t)(((MCLink *)base)->next); |
| 355 | lua_assert(mc != NULL); | 434 | lj_assertJ(base != 0, "broken MCode area chain"); |
| 356 | if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) { | 435 | if (addr >= base && addr < base + ((MCLink *)base)->size) { |
| 357 | if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN))) | 436 | mcode_setprot(J, (MCode *)base, ((MCLink *)base)->size, MCPROT_GEN); |
| 358 | mcode_protfail(J); | 437 | return (MCode *)base; |
| 359 | return mc; | ||
| 360 | } | 438 | } |
| 361 | } | 439 | } |
| 362 | } | 440 | } |
| 363 | #endif | ||
| 364 | } | 441 | } |
| 365 | 442 | ||
| 366 | /* Limit of MCode reservation reached. */ | 443 | /* Limit of MCode reservation reached. */ |
| @@ -369,7 +446,6 @@ void lj_mcode_limiterr(jit_State *J, size_t need) | |||
| 369 | size_t sizemcode, maxmcode; | 446 | size_t sizemcode, maxmcode; |
| 370 | lj_mcode_abort(J); | 447 | lj_mcode_abort(J); |
| 371 | sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10; | 448 | sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10; |
| 372 | sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1); | ||
| 373 | maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10; | 449 | maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10; |
| 374 | if (need * sizeof(MCode) > sizemcode) | 450 | if (need * sizeof(MCode) > sizemcode) |
| 375 | lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */ | 451 | lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */ |
