diff --git a/packages/runtime/src/scr_node_island.c b/packages/runtime/src/scr_node_island.c index a3f5e9fe4..aaf03f67a 100644 --- a/packages/runtime/src/scr_node_island.c +++ b/packages/runtime/src/scr_node_island.c @@ -92,6 +92,7 @@ void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); void __lsan_register_root_region(const void *p, size_t size) __attribute__((weak)); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); /* LeakSanitizer's report at exit, with Node loaded: Node keeps its root * certificate stores (the bundled roots, the system's with @@ -940,10 +941,15 @@ static void (*ni_nested_job)(void *) = NULL; static void *ni_nested_arg = NULL; static ucontext_t *ni_nested_return = NULL; +#ifdef NI_ASAN +static uintptr_t ni_nested_top = 0; /* the nested context's stack top */ +#endif + static void ni_nested_trampoline(void) { #ifdef NI_ASAN const void *caller_bottom; size_t caller_size; + uintptr_t top = ni_nested_top; __sanitizer_finish_switch_fiber(NULL, &caller_bottom, &caller_size); #endif void (*job)(void *) = ni_nested_job; @@ -951,7 +957,14 @@ static void ni_nested_trampoline(void) { ucontext_t *back = ni_nested_return; job(arg); #ifdef NI_ASAN - /* This context ends: no fake stack to keep. */ + /* This context ends: no fake stack to keep. Its frame never returns, so + * the redzones ASan poisoned around this frame's locals would stay in + * the shadow of Node's stack, where Node's own frames (uninstrumented) + * later trip over them. Linux's ASan clears a context's stack when it is + * switched to (its swapcontext interceptor); macOS's has none, so this + * frame's part of the stack is unpoisoned here. */ + uintptr_t low = ((uintptr_t)__builtin_frame_address(0) - 4096) & ~(uintptr_t)7; + if (top > low) __asan_unpoison_memory_region((const void *)low, top - low); __sanitizer_start_switch_fiber(NULL, caller_bottom, caller_size); #endif setcontext(back); @@ -970,6 +983,9 @@ static void ni_on_node_stack_below_mark(void (*job)(void *), void *arg) { if (scr_node_stack_low != 0 && scr_node_stack_low < top) top = scr_node_stack_low; uintptr_t hi = (top - 1024) & ~(uintptr_t)15; ni_make_context(&nested, lo, hi - (uintptr_t)lo, ni_nested_trampoline); +#ifdef NI_ASAN + ni_nested_top = hi; +#endif ni_nested_job = job; ni_nested_arg = arg; ni_nested_return = &caller;