rt: Add a canary value to the end of every stack
Check it on upcall entry and exit, and on stack deletion
This commit is contained in:
@@ -49,6 +49,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#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
|
// Stack size
|
||||||
size_t g_custom_min_stack_size = 0;
|
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
|
// old stack segments, since the act of popping the stack previously
|
||||||
// caused valgrind to consider the whole thing inaccessible.
|
// caused valgrind to consider the whole thing inaccessible.
|
||||||
size_t sz = stk->end - (uintptr_t)&stk->data[0];
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +117,18 @@ free_stk(rust_task *task, stk_seg *stk) {
|
|||||||
task->free(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*
|
static stk_seg*
|
||||||
new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
|
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");
|
stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
|
||||||
LOGPTR(task->sched, "new stk", (uintptr_t)stk);
|
LOGPTR(task->sched, "new stk", (uintptr_t)stk);
|
||||||
memset(stk, 0, sizeof(stk_seg));
|
memset(stk, 0, sizeof(stk_seg));
|
||||||
|
add_stack_canary(stk);
|
||||||
stk->prev = NULL;
|
stk->prev = NULL;
|
||||||
stk->next = task->stk;
|
stk->next = task->stk;
|
||||||
stk->end = (uintptr_t) &stk->data[rust_stk_sz + RED_ZONE_SIZE];
|
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)
|
del_stk(rust_task *task, stk_seg *stk)
|
||||||
{
|
{
|
||||||
assert(stk == task->stk && "Freeing stack segments out of order!");
|
assert(stk == task->stk && "Freeing stack segments out of order!");
|
||||||
|
check_stack_canary(stk);
|
||||||
|
|
||||||
task->stk = stk->next;
|
task->stk = stk->next;
|
||||||
|
|
||||||
@@ -784,6 +805,11 @@ rust_task::on_rust_stack() {
|
|||||||
return sp_in_stk_seg(get_sp(), stk);
|
return sp_in_stk_seg(get_sp(), stk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rust_task::check_stack_canary() {
|
||||||
|
::check_stack_canary(stk);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: C++
|
// mode: C++
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
|
|||||||
void record_stack_limit();
|
void record_stack_limit();
|
||||||
void reset_stack_limit();
|
void reset_stack_limit();
|
||||||
bool on_rust_stack();
|
bool on_rust_stack();
|
||||||
|
void check_stack_canary();
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -27,14 +27,21 @@ check_stack_alignment() __attribute__ ((aligned (16)));
|
|||||||
static void check_stack_alignment() { }
|
static void check_stack_alignment() { }
|
||||||
#endif
|
#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)
|
#define UPCALL_SWITCH_STACK(A, F) call_upcall_on_c_stack((void*)A, (void*)F)
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
call_upcall_on_c_stack(void *args, void *fn_ptr) {
|
call_upcall_on_c_stack(void *args, void *fn_ptr) {
|
||||||
check_stack_alignment();
|
|
||||||
rust_task *task = rust_scheduler::get_task();
|
rust_task *task = rust_scheduler::get_task();
|
||||||
|
do_sanity_check(task);
|
||||||
rust_scheduler *sched = task->sched;
|
rust_scheduler *sched = task->sched;
|
||||||
sched->c_context.call_shim_on_c_stack(args, fn_ptr);
|
sched->c_context.call_shim_on_c_stack(args, fn_ptr);
|
||||||
|
do_sanity_check(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void record_sp(void *limit);
|
extern "C" void record_sp(void *limit);
|
||||||
@@ -48,8 +55,8 @@ extern "C" void record_sp(void *limit);
|
|||||||
*/
|
*/
|
||||||
extern "C" CDECL void
|
extern "C" CDECL void
|
||||||
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
|
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
|
||||||
check_stack_alignment();
|
|
||||||
rust_task *task = rust_scheduler::get_task();
|
rust_task *task = rust_scheduler::get_task();
|
||||||
|
do_sanity_check(task);
|
||||||
|
|
||||||
// FIXME (1226) - The shim functions generated by rustc contain the
|
// FIXME (1226) - The shim functions generated by rustc contain the
|
||||||
// morestack prologue, so we need to let them know they have enough
|
// 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 = rust_scheduler::get_task();
|
||||||
task->record_stack_limit();
|
task->record_stack_limit();
|
||||||
|
do_sanity_check(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
@@ -634,9 +642,10 @@ upcall_del_stack() {
|
|||||||
// needs to acquire the value of the stack pointer
|
// needs to acquire the value of the stack pointer
|
||||||
extern "C" CDECL void
|
extern "C" CDECL void
|
||||||
upcall_reset_stack_limit() {
|
upcall_reset_stack_limit() {
|
||||||
check_stack_alignment();
|
|
||||||
rust_task *task = rust_scheduler::get_task();
|
rust_task *task = rust_scheduler::get_task();
|
||||||
|
do_sanity_check(task);
|
||||||
task->reset_stack_limit();
|
task->reset_stack_limit();
|
||||||
|
do_sanity_check(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user