From 784713ec683c7cce0a1d4aa712a376317384d62c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 20 Dec 2011 11:20:54 -0800 Subject: [PATCH] rt: Add a canary value to the end of every stack Check it on upcall entry and exit, and on stack deletion --- src/rt/rust_task.cpp | 28 +++++++++++++++++++++++++++- src/rt/rust_task.h | 1 + src/rt/rust_upcall.cpp | 15 ++++++++++++--- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 23bd6647a048..125a2900ca02 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -49,6 +49,12 @@ #endif #endif +// A value that goes at the end of the stack and must not be touched +const uint8_t stack_canary[] = {0xAB, 0xCD, 0xAB, 0xCD, + 0xAB, 0xCD, 0xAB, 0xCD, + 0xAB, 0xCD, 0xAB, 0xCD, + 0xAB, 0xCD, 0xAB, 0xCD}; + // Stack size size_t g_custom_min_stack_size = 0; @@ -95,7 +101,8 @@ config_valgrind_stack(stk_seg *stk) { // old stack segments, since the act of popping the stack previously // caused valgrind to consider the whole thing inaccessible. size_t sz = stk->end - (uintptr_t)&stk->data[0]; - VALGRIND_MAKE_MEM_UNDEFINED(stk->data, sz); + VALGRIND_MAKE_MEM_UNDEFINED(stk->data + sizeof(stack_canary), + sz - sizeof(stack_canary)); #endif } @@ -110,6 +117,18 @@ free_stk(rust_task *task, stk_seg *stk) { task->free(stk); } +static void +add_stack_canary(stk_seg *stk) { + memcpy(stk->data, stack_canary, sizeof(stack_canary)); + assert(sizeof(stack_canary) == 16 && "Stack canary was not the expected size"); +} + +static void +check_stack_canary(stk_seg *stk) { + assert(!memcmp(stk->data, stack_canary, sizeof(stack_canary)) + && "Somebody killed the canary"); +} + static stk_seg* new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz) { @@ -151,6 +170,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz) stk_seg *stk = (stk_seg *)task->malloc(sz, "stack"); LOGPTR(task->sched, "new stk", (uintptr_t)stk); memset(stk, 0, sizeof(stk_seg)); + add_stack_canary(stk); stk->prev = NULL; stk->next = task->stk; stk->end = (uintptr_t) &stk->data[rust_stk_sz + RED_ZONE_SIZE]; @@ -165,6 +185,7 @@ static void del_stk(rust_task *task, stk_seg *stk) { assert(stk == task->stk && "Freeing stack segments out of order!"); + check_stack_canary(stk); task->stk = stk->next; @@ -784,6 +805,11 @@ rust_task::on_rust_stack() { return sp_in_stk_seg(get_sp(), stk); } +void +rust_task::check_stack_canary() { + ::check_stack_canary(stk); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 51ae00a6b707..1f924793e3dd 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -203,6 +203,7 @@ rust_task : public kernel_owned, rust_cond void record_stack_limit(); void reset_stack_limit(); bool on_rust_stack(); + void check_stack_canary(); }; // diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 867f9cd58b62..f70f01ef983e 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -27,14 +27,21 @@ check_stack_alignment() __attribute__ ((aligned (16))); static void check_stack_alignment() { } #endif +static inline void +do_sanity_check(rust_task *task) { + check_stack_alignment(); + task->check_stack_canary(); +} + #define UPCALL_SWITCH_STACK(A, F) call_upcall_on_c_stack((void*)A, (void*)F) inline void call_upcall_on_c_stack(void *args, void *fn_ptr) { - check_stack_alignment(); rust_task *task = rust_scheduler::get_task(); + do_sanity_check(task); rust_scheduler *sched = task->sched; sched->c_context.call_shim_on_c_stack(args, fn_ptr); + do_sanity_check(task); } extern "C" void record_sp(void *limit); @@ -48,8 +55,8 @@ extern "C" void record_sp(void *limit); */ extern "C" CDECL void upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { - check_stack_alignment(); rust_task *task = rust_scheduler::get_task(); + do_sanity_check(task); // FIXME (1226) - The shim functions generated by rustc contain the // morestack prologue, so we need to let them know they have enough @@ -65,6 +72,7 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { task = rust_scheduler::get_task(); task->record_stack_limit(); + do_sanity_check(task); } /**********************************************************************/ @@ -634,9 +642,10 @@ upcall_del_stack() { // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { - check_stack_alignment(); rust_task *task = rust_scheduler::get_task(); + do_sanity_check(task); task->reset_stack_limit(); + do_sanity_check(task); } //