From 1f0223fef131777333a3f0af3837e3d179d334be Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 1 May 2021 08:58:47 -0600 Subject: [PATCH] Chez Scheme: repair to W^X mode Fix single-segment flipping to accomodate write regions that span segments. --- racket/src/ChezScheme/c/alloc.c | 2 +- racket/src/ChezScheme/c/externs.h | 4 ++-- racket/src/ChezScheme/c/fasl.c | 8 ++++---- racket/src/ChezScheme/c/gc.c | 6 +++--- racket/src/ChezScheme/c/prim.c | 8 ++++---- racket/src/ChezScheme/c/prim5.c | 31 ++++++++++++++----------------- racket/src/ChezScheme/c/scheme.c | 4 ++-- racket/src/ChezScheme/c/schsig.c | 6 +++--- racket/src/ChezScheme/c/segment.c | 25 ++++++++++++++++--------- racket/src/ChezScheme/c/thread.c | 4 ++-- racket/src/ChezScheme/c/version.h | 20 +++++++++++++------- 11 files changed, 64 insertions(+), 54 deletions(-) diff --git a/racket/src/ChezScheme/c/alloc.c b/racket/src/ChezScheme/c/alloc.c index d690c0c28a..3af7604bc9 100644 --- a/racket/src/ChezScheme/c/alloc.c +++ b/racket/src/ChezScheme/c/alloc.c @@ -264,7 +264,7 @@ ptr S_find_more_gc_room(thread_gc *tgc, ISPC s, IGEN g, iptr n, ptr old) { /* Ensure allocated code segments are writable. The caller should already have bracketed the writes with calls to start and stop so there is no need for a stop here. */ - S_thread_start_code_write(tgc->tc, 0, 1, NULL); + S_thread_start_code_write(tgc->tc, 0, 1, NULL, 0); } #endif diff --git a/racket/src/ChezScheme/c/externs.h b/racket/src/ChezScheme/c/externs.h index 2a3f34aec3..97cb4a65a3 100644 --- a/racket/src/ChezScheme/c/externs.h +++ b/racket/src/ChezScheme/c/externs.h @@ -395,8 +395,8 @@ extern uptr S_maxmembytes PROTO((void)); extern void S_resetmaxmembytes PROTO((void)); extern void S_adjustmembytes PROTO((iptr amt)); extern void S_move_to_chunk_list PROTO((chunkinfo *chunk, chunkinfo **pchunk_list)); -extern void S_thread_start_code_write PROTO((ptr tc, IGEN maxg, IBOOL current, void *hint)); -extern void S_thread_end_code_write PROTO((ptr tc, IGEN maxg, IBOOL current, void *hint)); +extern void S_thread_start_code_write PROTO((ptr tc, IGEN maxg, IBOOL current, void *hint, uptr hint_len)); +extern void S_thread_end_code_write PROTO((ptr tc, IGEN maxg, IBOOL current, void *hint, uptr hint_len)); /* stats.c */ extern void S_stats_init PROTO((void)); diff --git a/racket/src/ChezScheme/c/fasl.c b/racket/src/ChezScheme/c/fasl.c index 5d9230e2ea..d0e4372412 100644 --- a/racket/src/ChezScheme/c/fasl.c +++ b/racket/src/ChezScheme/c/fasl.c @@ -508,7 +508,7 @@ static ptr fasl_entry(ptr tc, IFASLCODE situation, unbufFaslFile uf, ptr externa Scompact_heap(); } - S_thread_start_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL); + S_thread_start_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL, 0); switch (ty) { case fasl_type_gzip: @@ -557,7 +557,7 @@ static ptr fasl_entry(ptr tc, IFASLCODE situation, unbufFaslFile uf, ptr externa return (ptr)0; } S_flush_instruction_cache(tc); - S_thread_end_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL); + S_thread_end_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL, 0); return x; } else { uf_skipbytes(uf, size); @@ -569,7 +569,7 @@ static ptr bv_fasl_entry(ptr tc, ptr bv, int ty, uptr offset, uptr len, unbufFas ptr x; ptr strbuf = S_G.null_string; struct faslFileObj ffo; - S_thread_start_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL); + S_thread_start_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL, 0); if (ty == fasl_type_vfasl) { x = S_vfasl(bv, NULL, offset, len); @@ -585,7 +585,7 @@ static ptr bv_fasl_entry(ptr tc, ptr bv, int ty, uptr offset, uptr len, unbufFas } S_flush_instruction_cache(tc); - S_thread_end_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL); + S_thread_end_code_write(tc, S_vfasl_boot_mode ? static_generation : 0, 1, NULL, 0); return x; } diff --git a/racket/src/ChezScheme/c/gc.c b/racket/src/ChezScheme/c/gc.c index ad9ba75215..b704dd878f 100644 --- a/racket/src/ChezScheme/c/gc.c +++ b/racket/src/ChezScheme/c/gc.c @@ -870,7 +870,7 @@ ptr GCENTRY(ptr tc, ptr count_roots_ls) { GET_REAL_TIME(astart); - S_thread_start_code_write(tc, MAX_TG, 0, NULL); + S_thread_start_code_write(tc, MAX_TG, 0, NULL, 0); /* flush instruction cache: effectively clear_code_mod but safer */ for (ls = S_threads; ls != Snil; ls = Scdr(ls)) { @@ -1679,7 +1679,7 @@ ptr GCENTRY(ptr tc, ptr count_roots_ls) { if (MAX_CG >= S_G.min_free_gen) S_free_chunks(); S_flush_instruction_cache(tc); - S_thread_end_code_write(tc, MAX_TG, 0, NULL); + S_thread_end_code_write(tc, MAX_TG, 0, NULL, 0); #ifndef NO_DIRTY_NEWSPACE_POINTERS /* mark dirty those newspace cards to which we've added wrong-way pointers */ @@ -2951,7 +2951,7 @@ static s_thread_rv_t start_sweeper(void *_sweeper) { gc_sweeper *sweeper = _sweeper; #if !defined(WRITE_XOR_EXECUTE_CODE) - S_thread_start_code_write((ptr)0, static_generation, 0, NULL); /* never ended */ + S_thread_start_code_write((ptr)0, static_generation, 0, NULL, 0); /* never ended */ #endif (void)s_thread_mutex_lock(&sweep_mutex); diff --git a/racket/src/ChezScheme/c/prim.c b/racket/src/ChezScheme/c/prim.c index 03c210df9d..45812e1f26 100644 --- a/racket/src/ChezScheme/c/prim.c +++ b/racket/src/ChezScheme/c/prim.c @@ -228,7 +228,7 @@ static void s_instantiate_code_object() { cookie = S_get_scheme_arg(tc, 2); proc = S_get_scheme_arg(tc, 3); - S_thread_start_code_write(tc, 0, 0, NULL); + S_thread_start_code_write(tc, 0, 0, NULL, 0); new = S_code(tc, CODETYPE(old), CODELEN(old)); @@ -280,7 +280,7 @@ static void s_instantiate_code_object() { } S_flush_instruction_cache(tc); - S_thread_end_code_write(tc, 0, 0, NULL); + S_thread_end_code_write(tc, 0, 0, NULL, 0); AC0(tc) = new; } @@ -289,7 +289,7 @@ static void s_link_code_object(co, objs) ptr co, objs; { ptr t, tc = get_thread_context(); uptr a, m, n; - S_thread_start_code_write(tc, 0, 0, NULL); + S_thread_start_code_write(tc, 0, 0, NULL, 0); t = CODERELOC(co); m = RELOCSIZE(t); a = 0; @@ -308,7 +308,7 @@ static void s_link_code_object(co, objs) ptr co, objs; { S_set_code_obj("gc", RELOC_TYPE(entry), co, a, Scar(objs), item_off); objs = Scdr(objs); } - S_thread_end_code_write(tc, 0, 0, NULL); + S_thread_end_code_write(tc, 0, 0, NULL, 0); } static INT s_check_heap_enabledp(void) { diff --git a/racket/src/ChezScheme/c/prim5.c b/racket/src/ChezScheme/c/prim5.c index 04ca6a88ef..9ee0df13ce 100644 --- a/racket/src/ChezScheme/c/prim5.c +++ b/racket/src/ChezScheme/c/prim5.c @@ -879,9 +879,9 @@ static ptr s_set_code_byte(p, n, x) ptr p, n, x; { ptr tc = get_thread_context(); a = (I8 *)TO_VOIDP((uptr)p + UNFIX(n)); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I8)); *a = (I8)UNFIX(x); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I8)); return Svoid; } @@ -891,9 +891,9 @@ static ptr s_set_code_word(p, n, x) ptr p, n, x; { ptr tc = get_thread_context(); a = (I16 *)TO_VOIDP((uptr)p + UNFIX(n)); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I16)); *a = (I16)UNFIX(x); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I16)); return Svoid; } @@ -903,9 +903,9 @@ static ptr s_set_code_long(p, n, x) ptr p, n, x; { ptr tc = get_thread_context(); a = (I32 *)TO_VOIDP((uptr)p + UNFIX(n)); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I32)); *a = (I32)(Sfixnump(x) ? UNFIX(x) : Sinteger_value(x)); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I32)); return Svoid; } @@ -915,9 +915,9 @@ static void s_set_code_long2(p, n, h, l) ptr p, n, h, l; { ptr tc = get_thread_context(); a = (I32 *)TO_VOIDP((uptr)p + UNFIX(n)); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I32)); *a = (I32)((UNFIX(h) << 16) + UNFIX(l)); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I32)); } static ptr s_set_code_quad(p, n, x) ptr p, n, x; { @@ -925,21 +925,18 @@ static ptr s_set_code_quad(p, n, x) ptr p, n, x; { ptr tc = get_thread_context(); a = (I64 *)TO_VOIDP((uptr)p + UNFIX(n)); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I64)); *a = Sfixnump(x) ? UNFIX(x) : S_int64_value("\\#set-code-quad!", x); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a)); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(a), sizeof(I64)); return Svoid; } static ptr s_set_reloc(p, n, e) ptr p, n, e; { iptr *a; - ptr tc = get_thread_context(); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(p))); a = (iptr *)(&RELOCIT(CODERELOC(p), UNFIX(n))); *a = Sfixnump(e) ? UNFIX(e) : Sinteger_value(e); - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(p))); return e; } @@ -954,7 +951,7 @@ static ptr s_make_code(flags, free, name, arity_mark, n, info, pinfos) ptr co; ptr tc = get_thread_context(); - S_thread_start_code_write(tc, 0, 0, NULL); + S_thread_start_code_write(tc, 0, 0, NULL, 0); co = S_code(tc, type_code | (flags << code_flags_offset), n); CODEFREE(co) = free; @@ -966,7 +963,7 @@ static ptr s_make_code(flags, free, name, arity_mark, n, info, pinfos) S_G.profile_counters = Scons(S_weak_cons(co, pinfos), S_G.profile_counters); } - S_thread_end_code_write(tc, 0, 0, NULL); + S_thread_end_code_write(tc, 0, 0, NULL, 0); return co; } @@ -974,10 +971,10 @@ static ptr s_make_code(flags, free, name, arity_mark, n, info, pinfos) static ptr s_make_reloc_table(codeobj, n) ptr codeobj, n; { ptr tc = get_thread_context(); - S_thread_start_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(codeobj))); + S_thread_start_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(codeobj)), sizeof(ptr)); CODERELOC(codeobj) = S_relocation_table(UNFIX(n)); RELOCCODE(CODERELOC(codeobj)) = codeobj; - S_thread_end_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(codeobj))); + S_thread_end_code_write(tc, 0, 0, TO_VOIDP(&CODERELOC(codeobj)), sizeof(ptr)); return Svoid; } diff --git a/racket/src/ChezScheme/c/scheme.c b/racket/src/ChezScheme/c/scheme.c index 6220c477e5..58d3cef7a4 100644 --- a/racket/src/ChezScheme/c/scheme.c +++ b/racket/src/ChezScheme/c/scheme.c @@ -108,7 +108,7 @@ static void main_init() { VIRTREG(tc, i) = FIX(0); } - S_thread_start_code_write(tc, 0, 0, NULL); + S_thread_start_code_write(tc, 0, 0, NULL, 0); p = S_code(tc, type_code, size_rp_header); CODERELOC(p) = S_relocation_table(0); CODENAME(p) = Sfalse; @@ -122,7 +122,7 @@ static void main_init() { (uptr)TO_PTR(&RPHEADERTOPLINK(TO_PTR(&CODEIT(p, 0)))) - (uptr)p; S_protect(&S_G.dummy_code_object); S_G.dummy_code_object = p; - S_thread_end_code_write(tc, 0, 0, NULL); + S_thread_end_code_write(tc, 0, 0, NULL, 0); S_protect(&S_G.error_invoke_code_object); S_G.error_invoke_code_object = Snil; diff --git a/racket/src/ChezScheme/c/schsig.c b/racket/src/ChezScheme/c/schsig.c index 5e8f369309..d0aee16dc5 100644 --- a/racket/src/ChezScheme/c/schsig.c +++ b/racket/src/ChezScheme/c/schsig.c @@ -394,7 +394,7 @@ static void do_error(type, who, s, args) iptr type; const char *who, *s; ptr arg #endif /* PTHREADS */ /* in case error is during fasl read: */ - S_thread_end_code_write(tc, static_generation, 0, NULL); + S_thread_end_code_write(tc, static_generation, 0, NULL, 0); TRAP(tc) = (ptr)1; AC0(tc) = (ptr)1; @@ -801,7 +801,7 @@ void S_schsig_init() { S_protect(&S_G.collect_request_pending_id); S_G.collect_request_pending_id = S_intern((const unsigned char *)"$collect-request-pending"); - S_thread_start_code_write(tc, 0, 0, NULL); + S_thread_start_code_write(tc, 0, 0, NULL, 0); p = S_code(tc, type_code | (code_flag_continuation << code_flags_offset), 0); CODERELOC(p) = S_relocation_table(0); CODENAME(p) = Sfalse; @@ -809,7 +809,7 @@ void S_schsig_init() { CODEFREE(p) = 0; CODEINFO(p) = Sfalse; CODEPINFOS(p) = Snil; - S_thread_end_code_write(tc, 0, 0, NULL); + S_thread_end_code_write(tc, 0, 0, NULL, 0); S_set_symbol_value(S_G.null_continuation_id, S_mkcontinuation(space_new, diff --git a/racket/src/ChezScheme/c/segment.c b/racket/src/ChezScheme/c/segment.c index cfbf1a4415..8c1014482d 100644 --- a/racket/src/ChezScheme/c/segment.c +++ b/racket/src/ChezScheme/c/segment.c @@ -46,7 +46,7 @@ static seginfo *sort_seginfo PROTO((seginfo *si, uptr n)); static seginfo *merge_seginfo PROTO((seginfo *si1, seginfo *si2)); #if defined(WRITE_XOR_EXECUTE_CODE) -static void enable_code_write PROTO((ptr tc, IGEN maxg, IBOOL on, IBOOL current, ptr hint)); +static void enable_code_write PROTO((ptr tc, IGEN maxg, IBOOL on, IBOOL current, ptr hint, uptr hint_len)); #endif void S_segment_init() { @@ -586,17 +586,19 @@ static void contract_segment_table(uptr base, uptr end) { being flipped while a thread is executing code off of it. */ -void S_thread_start_code_write(WX_UNUSED ptr tc, WX_UNUSED IGEN maxg, WX_UNUSED IBOOL current, WX_UNUSED void *hint) { +void S_thread_start_code_write(WX_UNUSED ptr tc, WX_UNUSED IGEN maxg, WX_UNUSED IBOOL current, + WX_UNUSED void *hint, WX_UNUSED uptr hint_len) { #if defined(WRITE_XOR_EXECUTE_CODE) - enable_code_write(tc, maxg, 1, current, hint); + enable_code_write(tc, maxg, 1, current, hint, hint_len); #else S_ENABLE_CODE_WRITE(1); #endif } -void S_thread_end_code_write(WX_UNUSED ptr tc, WX_UNUSED IGEN maxg, WX_UNUSED IBOOL current, WX_UNUSED void *hint) { +void S_thread_end_code_write(WX_UNUSED ptr tc, WX_UNUSED IGEN maxg, WX_UNUSED IBOOL current, + WX_UNUSED void *hint, WX_UNUSED uptr hint_len) { #if defined(WRITE_XOR_EXECUTE_CODE) - enable_code_write(tc, maxg, 0, current, hint); + enable_code_write(tc, maxg, 0, current, hint, hint_len); #else S_ENABLE_CODE_WRITE(0); #endif @@ -623,7 +625,7 @@ static IBOOL is_unused_seg(chunkinfo *chunk, seginfo *si) { } # endif -static void enable_code_write(ptr tc, IGEN maxg, IBOOL on, IBOOL current, void *hint) { +static void enable_code_write(ptr tc, IGEN maxg, IBOOL on, IBOOL current, void *hint, uptr hint_len) { thread_gc *tgc; chunkinfo *chunk; seginfo si, *sip; @@ -633,9 +635,14 @@ static void enable_code_write(ptr tc, IGEN maxg, IBOOL on, IBOOL current, void * /* Flip only the segment hinted at by the caller. */ if (maxg == 0 && hint != NULL) { - addr = TO_VOIDP((char*)hint - ((uptr)hint % bytes_per_segment)); - if (mprotect(addr, bytes_per_segment, flags) != 0) { - S_error_abort("bad hint to enable_code_write"); + uptr seg, start_seg, end_seg; + start_seg = addr_get_segment(TO_PTR(hint)); + end_seg = addr_get_segment((uptr)TO_PTR(hint) + hint_len - 1); + for (seg = start_seg; seg <= end_seg; seg++) { + addr = TO_VOIDP(build_ptr(seg, 0)); + if (mprotect(addr, bytes_per_segment, flags) != 0) { + S_error_abort("bad hint to enable_code_write"); + } } return; } diff --git a/racket/src/ChezScheme/c/thread.c b/racket/src/ChezScheme/c/thread.c index a3bf0ecda9..31e01c31d1 100644 --- a/racket/src/ChezScheme/c/thread.c +++ b/racket/src/ChezScheme/c/thread.c @@ -257,7 +257,7 @@ static IBOOL destroy_thread(tc) ptr tc; { S_scan_dirty((ptr *)EAP(tc), (ptr *)REAL_EAP(tc)); /* close off thread-local allocation */ - S_thread_start_code_write(tc, static_generation, 0, NULL); + S_thread_start_code_write(tc, static_generation, 0, NULL, 0); { ISPC s; IGEN g; thread_gc *tgc = THREAD_GC(tc); @@ -266,7 +266,7 @@ static IBOOL destroy_thread(tc) ptr tc; { if (tgc->next_loc[g][s]) S_close_off_thread_local_segment(tc, s, g); } - S_thread_end_code_write(tc, static_generation, 0, NULL); + S_thread_end_code_write(tc, static_generation, 0, NULL, 0); alloc_mutex_release(); diff --git a/racket/src/ChezScheme/c/version.h b/racket/src/ChezScheme/c/version.h index bf2e7cc5fc..8d660d042a 100644 --- a/racket/src/ChezScheme/c/version.h +++ b/racket/src/ChezScheme/c/version.h @@ -248,12 +248,10 @@ typedef int tputsputcchar; /* for both iPhone and iPhoneSimulator */ #if defined(TARGET_OS_IPHONE) # define SYSTEM(s) ((void)s, -1) -# define S_PROT_CODE (PROT_WRITE | PROT_READ) # define WRITE_XOR_EXECUTE_CODE -# define WX_UNUSED #endif #if defined(__arm64__) -# if !defined(TARGET_OS_IPHONE) +# if !defined(WRITE_XOR_EXECUTE_CODE) # define S_MAP_CODE MAP_JIT # define S_ENABLE_CODE_WRITE(on) pthread_jit_write_protect_np(!(on)) # endif @@ -419,7 +417,11 @@ typedef char tputsputcchar; #endif #ifndef S_PROT_CODE -# define S_PROT_CODE (PROT_READ | PROT_WRITE | PROT_EXEC) +# ifdef WRITE_XOR_EXECUTE_CODE +# define S_PROT_CODE (PROT_WRITE | PROT_READ) +# else +# define S_PROT_CODE (PROT_READ | PROT_WRITE | PROT_EXEC) +# endif #endif #ifndef S_MAP_CODE # define S_MAP_CODE 0 @@ -428,10 +430,14 @@ typedef char tputsputcchar; # define S_ENABLE_CODE_WRITE(on) do { } while (0) #endif -/* Signals that an argument is unused when W&X memory pages are - supported. Relevant in relation to WRITE_XOR_EXECUTE_CODE. */ +/* WX_UNUSED indicates that an argument is used only for + WRITE_XOR_EXECUTE_CODE mode */ #ifndef WX_UNUSED -# define WX_UNUSED UNUSED +# ifdef WRITE_XOR_EXECUTE_CODE +# define WX_UNUSED +# else +# define WX_UNUSED UNUSED +# endif #endif #ifdef PTHREADS