From 4676db9470cd6c4fb01fa1fb60e8d3630e615d11 Mon Sep 17 00:00:00 2001 From: nick-a-schneider Date: Tue, 5 Aug 2025 17:32:46 -0400 Subject: [PATCH 1/3] apply return guard and stack canary monitoring --- jocktos/src/os.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/jocktos/src/os.c b/jocktos/src/os.c index 88dab4f..34039d3 100644 --- a/jocktos/src/os.c +++ b/jocktos/src/os.c @@ -18,11 +18,20 @@ /* -- Defines ------------------------------------------------------------- */ +#define FILL 0xBABEFACE // for task allocation debugging +#define CANARY 0xDEADBEEF +#define CANARY_SIZE 16 #define TRIGGER_PendSV *(uintptr_t volatile *)0xE000ED04 = (1U << 28) /* -- Types --------------------------------------------------------------- */ /* -- Private Function Declarations --------------------------------------- */ +/** + * \details Safely catches an unexpected return from a task. + * Any task that returns is marked as 'terminated' and moved accordingly. + * + */ +void task_exit_guard(void); /** * \brief Updates the task control blocks stack_usage @@ -182,8 +191,7 @@ void initializeStack(TaskControlBlock* tcb) { // - non-critical registers are initialized to their index *(--stack_ptr) = (1U << 24); ///< Set thumb state bit in EPSR *(--stack_ptr) = (uintptr_t)tcb->task_handle; ///< Set PC to task function handle - *(--stack_ptr) = 0xFFFFFFF9U; ///< Set LR register for MSP thread mode - // *(--stack_ptr) = 0xFFFFFFFDU; ///< Set LR register for PSP thread mode + *(--stack_ptr) = (uintptr_t)task_exit_guard; // LR: Return trap *(--stack_ptr) = 0x0000000CU; ///< Set R12 register deafult to its index *(--stack_ptr) = 0x00000003U; ///< Set R3 register deafult to its index *(--stack_ptr) = 0x00000002U; ///< Set R2 register deafult to its index @@ -201,11 +209,11 @@ void initializeStack(TaskControlBlock* tcb) { *(--stack_ptr) = 0x00000004U; ///< Set R4 register deafult to its index tcb->stack_pointer = stack_ptr; // Fill unused process stack with known value - while (stack_ptr > tcb->stack_overflow + 8) { - *(--stack_ptr) = 0xBABEFACEU; + while (stack_ptr > tcb->stack_overflow + CANARY_SIZE) { + *(--stack_ptr) = FILL; } while (stack_ptr > tcb->stack_overflow) { - *(--stack_ptr) = 0xDEADBEEFU; ///< set top 8 bytes to something else + *(--stack_ptr) = CANARY; ///< set top 8 bytes to something else } } @@ -224,7 +232,17 @@ void SysTick_Handler(void) { uint32_t primask; primask = jock_os_enter_critical_section(); JOCKTOSScheduler.tick_count++; - jock_os_switch_running_task(&JOCKTOSScheduler.ready); + TaskControlBlock** dest = &JOCKTOSScheduler.ready; + TaskControlBlock* tcb = JOCKTOSScheduler.running; + uint32_t* ptr = (uint32_t*)tcb->stack_overflow + CANARY_SIZE; + for (int i = 0; i < CANARY_SIZE; i++) { + if (*(--ptr) != CANARY) { + if (tcb == &usr_main_tcb) break; // ignore stack canary for main [TODO] + dest = &JOCKTOSScheduler.terminated; + break; + } + } + jock_os_switch_running_task(dest); jock_os_leave_critical_section(primask); } @@ -294,7 +312,7 @@ void monitorJOCKTOS(void* arg) { } -void idleJOCKTOS(void* arg) { +void idleJOCKTOS(void* arg __attribute__((unused))) { /* Disable interrupts to make sure that the busy flag does not get modified between the check in the while condition and the system sleep */ @@ -351,4 +369,10 @@ void idleJOCKTOS(void* arg) { // TODO: Figure out how to low power } - +__attribute__((noreturn)) +void task_exit_guard(void) { + uint32_t primask = jock_os_enter_critical_section(); + JOCKTOSScheduler.running->state = TERMINATED; + jock_os_switch_running_task(&JOCKTOSScheduler.terminated); + jock_os_leave_critical_section(primask); +} From afaeaa99326463766e3690f5daf221f214f5dfa4 Mon Sep 17 00:00:00 2001 From: nick-a-schneider Date: Tue, 5 Aug 2025 17:35:34 -0400 Subject: [PATCH 2/3] include os header changes --- jocktos/inc/os.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jocktos/inc/os.h b/jocktos/inc/os.h index 02ac8f6..f1b495b 100644 --- a/jocktos/inc/os.h +++ b/jocktos/inc/os.h @@ -83,9 +83,10 @@ typedef struct { volatile bool pending; volatile uint32_t tick_count; - volatile TaskControlBlock* running; ///< Currently running task - volatile TaskControlBlock* ready; ///< Singly linked list of tasks ready to run, in decending order of priority - volatile TaskControlBlock* suspended; ///< Singly linked list of suspended tasks, in decending order of priority + volatile TaskControlBlock* terminated; ///< Currently running task + volatile TaskControlBlock* running; ///< Currently running task + volatile TaskControlBlock* ready; ///< Singly linked list of tasks ready to run, in decending order of priority + volatile TaskControlBlock* suspended; ///< Singly linked list of suspended tasks, in decending order of priority } Scheduler; /** From ea24aa80bb48fe73dbeea28453369696770efb36 Mon Sep 17 00:00:00 2001 From: nick-a-schneider Date: Tue, 5 Aug 2025 17:37:17 -0400 Subject: [PATCH 3/3] include tcb header changes --- jocktos/inc/tcb.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jocktos/inc/tcb.h b/jocktos/inc/tcb.h index 63a47f8..2edd8da 100644 --- a/jocktos/inc/tcb.h +++ b/jocktos/inc/tcb.h @@ -88,7 +88,8 @@ typedef enum { RUNNING = 0, ///< The task is currently executing on the CPU with priority over others. READY = 1, ///< The task is ready and waiting for execution by the scheduler. BLOCKED = 2, ///< The task is waiting for a resource (e.g., semaphore, mutex) to become available. - SUSPENDED = 3 ///< The task is temporarily inactive and can be reactivated by an event. + SUSPENDED = 3, ///< The task is temporarily inactive and can be reactivated by an event. + TERMINATED = 4 ///< The task has been terminated and is no longer executing. } TaskState; /**