On Thu, Oct 19, 2023 at 04:39:51PM +0200, Borislav Petkov wrote: > On Thu, Oct 19, 2023 at 02:21:40PM +0000, Kaplan, David wrote: > > The return thunk is used for all functions though, including assembly > > coded functions which may use non-standard calling conventions and > > aren't visible to gcc. I think the only safe thing would be to > > preserve all GPRs across the call to check_thunks. Something like > > PUSH_REGS/call check_thunks/POP_REGS. > > That call nop will be inside the return thunk. I.e., something like > this: > > SYM_CODE_START(__x86_return_thunk) > UNWIND_HINT_FUNC > ANNOTATE_NOENDBR > ANNOTATE_UNRET_SAFE > ALTERNATIVE CALL nop, check_thunks, X86_FEATURE_ALWAYS > ret > int3 > SYM_CODE_END(__x86_return_thunk) > EXPORT_SYMBOL(__x86_return_thunk) > > I suspect that gcc doesn't know that there is a function call in the asm > there, which is also what you hint at - I need to ask a compiler guy. > > But yeah, if it doesn't, then we'll need to push/pop regs as you > suggest. GCC doesn't read asm. Even if it did that wouldn't fix things for callers of custom-ABI return-thunk-using functions. The below seems to work. diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index 27b5da2111ac..54c043e010f9 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -46,3 +46,5 @@ THUNK preempt_schedule_thunk, preempt_schedule THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace EXPORT_SYMBOL(preempt_schedule_thunk) EXPORT_SYMBOL(preempt_schedule_notrace_thunk) + +THUNK warn_thunk_thunk, __warn_thunk diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 14cd3cd5f85a..315e3f9410b2 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -357,6 +357,8 @@ extern void entry_ibpb(void); extern void (*x86_return_thunk)(void); +extern void __warn_thunk(void); + #ifdef CONFIG_CALL_DEPTH_TRACKING extern void call_depth_return_thunk(void); diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index bb0ab8466b91..7d89fe7a2e69 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -2849,3 +2849,8 @@ ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *bu return cpu_show_common(dev, attr, buf, X86_BUG_GDS); } #endif + +void __warn_thunk(void) +{ + WARN_ONCE(1, "unpatched return thunk"); +} diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index fe05c139db48..389662b88e19 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -360,13 +360,14 @@ SYM_FUNC_END(call_depth_return_thunk) * 'JMP __x86_return_thunk' sites are changed to something else by * apply_returns(). * - * This thunk is turned into a ud2 to ensure it is never used at runtime. - * Alternative instructions are applied after apply_returns(). + * The RET is replaced with a WARN_ONCE() to ensure it is never used at + * runtime. Alternative instructions are applied after apply_returns(). */ SYM_CODE_START(__x86_return_thunk) UNWIND_HINT_FUNC ANNOTATE_NOENDBR - ALTERNATIVE __stringify(ANNOTATE_UNRET_SAFE;ret),"ud2", X86_FEATURE_ALWAYS + ALTERNATIVE __stringify(ANNOTATE_UNRET_SAFE; ret), \ + "jmp warn_thunk_thunk", X86_FEATURE_ALWAYS int3 SYM_CODE_END(__x86_return_thunk) EXPORT_SYMBOL(__x86_return_thunk)