diff --git a/src/cpu/x86/smm/smm_module_handler.c b/src/cpu/x86/smm/smm_module_handler.c index c2001ec9e2..6dff9411de 100644 --- a/src/cpu/x86/smm/smm_module_handler.c +++ b/src/cpu/x86/smm/smm_module_handler.c @@ -122,10 +122,13 @@ asmlinkage void smm_handler_start(void *arg) const struct smm_module_params *p; const struct smm_runtime *runtime; int cpu; + uintptr_t actual_canary; + uintptr_t expected_canary; p = arg; runtime = p->runtime; cpu = p->cpu; + expected_canary = (uintptr_t)p->canary; /* Make sure to set the global runtime. It's OK to race as the value * will be the same across CPUs as well as multiple SMIs. */ @@ -171,6 +174,17 @@ asmlinkage void smm_handler_start(void *arg) smi_restore_pci_address(); + actual_canary = *p->canary; + + if (actual_canary != expected_canary) { + printk(BIOS_DEBUG, "canary 0x%lx != 0x%lx\n", actual_canary, + expected_canary); + + // Don't die if we can't indicate an error. + if (IS_ENABLED(CONFIG_DEBUG_SMI)) + die("SMM Handler caused a stack overflow\n"); + } + smi_release_lock(); /* De-assert SMI# signal to allow another SMI */ diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S index ba66db9179..eb890df150 100644 --- a/src/cpu/x86/smm/smm_stub.S +++ b/src/cpu/x86/smm/smm_stub.S @@ -136,6 +136,11 @@ smm_trampoline32: subl %eax, %ebx /* global_stack_top - offset = stack_top */ mov %ebx, %esp + /* Write canary to the bottom of the stack */ + movl stack_size, %eax + subl %eax, %ebx /* %ebx(stack_top) - size = %ebx(stack_bottom) */ + movl %ebx, (%ebx) + /* Create stack frame by pushing a NULL stack base pointer */ pushl $0x0 mov %esp, %ebp @@ -166,14 +171,18 @@ smm_trampoline32: fxsave (%edi) 1: - /* Align stack to 16 bytes. Another 16 bytes are pushed below. */ + /* Align stack to 16 bytes. Another 32 bytes are pushed below. */ andl $0xfffffff0, %esp /* Call into the c-based SMM relocation function with the platform * parameters. Equivalent to: - * struct arg = { c_handler_params, cpu_num, smm_runtime }; + * struct arg = { c_handler_params, cpu_num, smm_runtime, canary }; * c_handler(&arg) */ + push $0x0 /* Padding */ + push $0x0 /* Padding */ + push $0x0 /* Padding */ + push %ebx /* uintptr_t *canary */ push $(smm_runtime) push %ecx /* int cpu */ push c_handler_arg /* void *arg */ diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index 7dcf4d70e2..9942772f0e 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -527,6 +527,10 @@ struct smm_module_params { void *arg; int cpu; const struct smm_runtime *runtime; + /* A canary value that has been placed at the end of the stack. + * If (uintptr_t)canary != *canary then a stack overflow has occurred. + */ + const uintptr_t *canary; }; /* smm_handler_t is called with arg of smm_module_params pointer. */