From 4329f8c6034ebc563f3d7b101e7fa0b407e504a2 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 26 May 2025 18:48:26 +0100 Subject: [PATCH] x86/boot: Use RSTORSSP to establish SSP Under FRED, SETSSBSY is disallowed, and we want to be setting up FRED prior to setting up shadow stacks. As we still need Supervisor Tokens in IDT mode, we need mode-specific logic to establish SSP. In FRED mode, write a Restore Token, RSTORSSP it, and discard the resulting Previous-SSP token. No change outside of FRED mode. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich (cherry picked from commit 3037d8b7eb3e9c3c9e4a0a257115557c300795fc) --- xen/arch/x86/boot/x86_64.S | 23 +++++++++++++++++++++-- xen/arch/x86/setup.c | 25 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index 11a7e9d3bd..9705d03f84 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -53,17 +53,21 @@ ENTRY(__high_start) mov %rcx, STACK_CPUINFO_FIELD(cr4)(%r15) mov %rcx, %cr4 - /* WARNING! call/ret now fatal (iff SHSTK) until SETSSBSY loads SSP */ + /* WARNING! CALL/RET now fatal (iff SHSTK) until SETSSBSY/RSTORSSP loads SSP */ #if defined(CONFIG_XEN_SHSTK) test $CET_SHSTK_EN, %al jz .L_ap_cet_done - /* Derive the supervisor token address from %rsp. */ + /* Derive the token address from %rsp. */ mov %rsp, %rdx and $~(STACK_SIZE - 1), %rdx or $(PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8, %rdx + /* Establishing SSP differs between IDT or FRED mode. */ + bt $32 /* ilog2(X86_CR4_FRED) */, %rcx + jc .L_fred_shstk + /* * Write a new Supervisor Token. It doesn't matter the first time a * CPU boots, but for S3 resume or hotplug this clears the busy bit so @@ -71,6 +75,21 @@ ENTRY(__high_start) */ wrssq %rdx, (%rdx) setssbsy + jmp .L_ap_cet_done + +.L_fred_shstk: + + /* + * Write a Restore Token, value: &token + 8 + 64BIT (bit 0) at the + * base of the shstk (which isn't in use yet). + */ + lea 9(%rdx), %rdi + wrssq %rdi, (%rdx) + rstorssp (%rdx) + + /* Discard the Previous-SSP Token from the shstk. */ + mov $2, %edx + incsspd %edx #endif /* CONFIG_XEN_SHSTK */ .L_ap_cet_done: diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 872a8c63f9..44da5efa1d 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -908,7 +909,29 @@ static void __init noreturn reinit_bsp_stack(void) if ( cpu_has_xen_shstk ) { wrmsrl(MSR_S_CET, xen_msr_s_cet_value()); - asm volatile ("setssbsy" ::: "memory"); + + /* + * IDT and FRED differ by a Supervisor Token on the shadow stack. + * + * In IDT mode, we use SETSSBSY (itself using MSR_PL0_SSP, configured + * previously) to mark the Supervisor Token as Busy. In FRED mode, + * there is no token, so we need to create a temporary Restore Token + * to establish SSP. + */ + if ( opt_fred ) + { + unsigned long *token = + (void *)stack + (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8; + + wrss((unsigned long)token + 9, token); + asm volatile ( "rstorssp %0" : "+m" (*token) ); + /* + * We need to discard the resulting Previous-SSP Token, but + * reset_stack_and_jump() will do that for us. + */ + } + else + asm volatile ( "setssbsy" ::: "memory" ); } reset_stack_and_jump(init_done);