From 4a8087c5838ea1b46233665cdba79f7b14c051bc Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Thu, 20 Nov 2025 12:04:01 +0800 Subject: [PATCH] Replace constant stack canary with per-task random This commit replaces fixed STACK_CANARY (0x33333333U) with per-task random canary generated using xorshift32 PRNG. This prevents trivial canary forgery attacks and significantly improves stack overflow detection. The xorshift32 PRNG provides sufficient entropy for embedded systems without MMU/MPU support. Future enhancements can improve PRNG seeding with hardware entropy sources. Close #8 --- include/sys/task.h | 3 +++ kernel/main.c | 7 +++++++ kernel/task.c | 23 +++++++++++++---------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/sys/task.h b/include/sys/task.h index 33d0b601..dc6410af 100644 --- a/include/sys/task.h +++ b/include/sys/task.h @@ -82,6 +82,9 @@ typedef struct tcb { /* Real-time Scheduling Support */ void *rt_prio; /* Opaque pointer for custom real-time scheduler hook */ + + /* Stack Protection */ + uint32_t canary; /* Random stack canary for overflow detection */ } tcb_t; /* Kernel Control Block (KCB) diff --git a/kernel/main.c b/kernel/main.c index b0f666e0..c1583951 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -24,6 +24,13 @@ int32_t main(void) printf("Heap initialized, %u bytes available\n", (unsigned int) (size_t) &_heap_size); + /* Seed PRNG with hardware entropy for stack canary randomization. + * Combine cycle counter (mcycle) and us timer for unpredictability. This + * prevents fixed canary values across boots. + */ + uint32_t entropy = read_csr(mcycle) ^ (uint32_t) _read_us(); + srand(entropy); + /* Initialize deferred logging system. * Must be done after heap init but before app_main() to ensure * application tasks can use thread-safe printf. diff --git a/kernel/task.c b/kernel/task.c index 59ffdae5..de17913b 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -41,10 +42,6 @@ static volatile uint32_t timer_work_generation = 0; /* counter for coalescing */ /* Stack canary checking frequency - check every N context switches */ #define STACK_CHECK_INTERVAL 32 -/* Magic number written to both ends of a task's stack for corruption detection. - */ -#define STACK_CANARY 0x33333333U - /* Stack check counter for periodic validation (reduces overhead). */ static uint32_t stack_check_counter = 0; #endif /* CONFIG_STACK_PROTECTION */ @@ -153,12 +150,12 @@ static void task_stack_check(void) uint32_t *hi_canary_ptr = (uint32_t *) ((uintptr_t) self->stack + self->stack_sz - sizeof(uint32_t)); - if (unlikely(*lo_canary_ptr != STACK_CANARY || - *hi_canary_ptr != STACK_CANARY)) { + if (unlikely(*lo_canary_ptr != self->canary || + *hi_canary_ptr != self->canary)) { printf("\n*** STACK CORRUPTION: task %u base=%p size=%u\n", self->id, self->stack, (unsigned int) self->stack_sz); printf(" Canary values: low=0x%08x, high=0x%08x (expected 0x%08x)\n", - *lo_canary_ptr, *hi_canary_ptr, STACK_CANARY); + *lo_canary_ptr, *hi_canary_ptr, self->canary); panic(ERR_STACK_CHECK); } } @@ -544,10 +541,16 @@ static bool init_task_stack(tcb_t *tcb, size_t stack_size) } #if CONFIG_STACK_PROTECTION - /* Only initialize essential parts to reduce overhead */ - *(uint32_t *) stack = STACK_CANARY; + /* Generate random canary for this task */ + tcb->canary = (uint32_t) random(); + /* Ensure canary is never zero */ + if (tcb->canary == 0) + tcb->canary = 0xDEADBEEFU; + + /* Write canary to both ends of stack */ + *(uint32_t *) stack = tcb->canary; *(uint32_t *) ((uintptr_t) stack + stack_size - sizeof(uint32_t)) = - STACK_CANARY; + tcb->canary; #endif tcb->stack = stack;