x86/its: Add support for ITS-safe return thunk
authorPawan Gupta <pawan.kumar.gupta@linux.intel.com>
Sat, 22 Jun 2024 04:17:21 +0000 (21:17 -0700)
committerDave Hansen <dave.hansen@linux.intel.com>
Fri, 9 May 2025 20:22:05 +0000 (13:22 -0700)
RETs in the lower half of cacheline may be affected by ITS bug,
specifically when the RSB-underflows. Use ITS-safe return thunk for such
RETs.

RETs that are not patched:

- RET in retpoline sequence does not need to be patched, because the
  sequence itself fills an RSB before RET.
- RET in Call Depth Tracking (CDT) thunks __x86_indirect_{call|jump}_thunk
  and call_depth_return_thunk are not patched because CDT by design
  prevents RSB-underflow.
- RETs in .init section are not reachable after init.
- RETs that are explicitly marked safe with ANNOTATE_UNRET_SAFE.

Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org>
Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com>
arch/x86/include/asm/alternative.h
arch/x86/include/asm/nospec-branch.h
arch/x86/kernel/alternative.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/static_call.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/lib/retpoline.S
arch/x86/net/bpf_jit_comp.c

index 4a37a8bd87fdfa310f03fd42349c175a451e8602..4037c611537c85a1f97f1b6d5baa91fd942c29cf 100644 (file)
@@ -124,6 +124,20 @@ static __always_inline int x86_call_depth_emit_accounting(u8 **pprog,
 }
 #endif
 
+#if defined(CONFIG_MITIGATION_RETHUNK) && defined(CONFIG_OBJTOOL)
+extern bool cpu_wants_rethunk(void);
+extern bool cpu_wants_rethunk_at(void *addr);
+#else
+static __always_inline bool cpu_wants_rethunk(void)
+{
+       return false;
+}
+static __always_inline bool cpu_wants_rethunk_at(void *addr)
+{
+       return false;
+}
+#endif
+
 #ifdef CONFIG_SMP
 extern void alternatives_smp_module_add(struct module *mod, char *name,
                                        void *locks, void *locks_end,
index a5eb0cd93c9273ddfcf6d20c3583cb02e9f2a8fa..7d04ade3354115f10e80c3bf65136fb42a28d406 100644 (file)
@@ -367,6 +367,12 @@ static inline void srso_return_thunk(void) {}
 static inline void srso_alias_return_thunk(void) {}
 #endif
 
+#ifdef CONFIG_MITIGATION_ITS
+extern void its_return_thunk(void);
+#else
+static inline void its_return_thunk(void) {}
+#endif
+
 extern void retbleed_return_thunk(void);
 extern void srso_return_thunk(void);
 extern void srso_alias_return_thunk(void);
index 333c0295b0a522b70bf6945fed630d831d590bd3..3e67e72bffdc98997ff3ccec7270e7229fee7a24 100644 (file)
@@ -814,6 +814,21 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
 
 #ifdef CONFIG_MITIGATION_RETHUNK
 
+bool cpu_wants_rethunk(void)
+{
+       return cpu_feature_enabled(X86_FEATURE_RETHUNK);
+}
+
+bool cpu_wants_rethunk_at(void *addr)
+{
+       if (!cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               return false;
+       if (x86_return_thunk != its_return_thunk)
+               return true;
+
+       return !((unsigned long)addr & 0x20);
+}
+
 /*
  * Rewrite the compiler generated return thunk tail-calls.
  *
@@ -830,7 +845,7 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes)
        int i = 0;
 
        /* Patch the custom return thunks... */
-       if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
+       if (cpu_wants_rethunk_at(addr)) {
                i = JMP32_INSN_SIZE;
                __text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i);
        } else {
@@ -847,7 +862,7 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end)
 {
        s32 *s;
 
-       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+       if (cpu_wants_rethunk())
                static_call_force_reinit();
 
        for (s = start; s < end; s++) {
index cace6e8d7cc77a14a6213cab63b90de08d6b0929..5eb1514af5593edc1f971aed1257a3f61301fa57 100644 (file)
@@ -354,7 +354,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
                goto fail;
 
        ip = trampoline + size;
-       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+       if (cpu_wants_rethunk_at(ip))
                __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE);
        else
                memcpy(ip, retq, sizeof(retq));
index a59c72e7764522bb0e19fae79b51e0d12f9ca0bf..c3d7ff44b29adc609a858c9262d697eca2ba9a77 100644 (file)
@@ -81,7 +81,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type,
                break;
 
        case RET:
-               if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               if (cpu_wants_rethunk_at(insn))
                        code = text_gen_insn(JMP32_INSN_OPCODE, insn, x86_return_thunk);
                else
                        code = &retinsn;
@@ -90,7 +90,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type,
        case JCC:
                if (!func) {
                        func = __static_call_return;
-                       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+                       if (cpu_wants_rethunk())
                                func = x86_return_thunk;
                }
 
index c3e048e7e161aa3e485b838898e3256aff3b166c..e97f5773c8df2408d00d5ee5c291d040bc1ca5f5 100644 (file)
@@ -503,6 +503,10 @@ PROVIDE(__ref_stack_chk_guard = __stack_chk_guard);
 . = ASSERT(__x86_indirect_its_thunk_array == __x86_indirect_its_thunk_rax, "Gap in ITS thunk array");
 #endif
 
+#if defined(CONFIG_MITIGATION_ITS) && !defined(CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B)
+. = ASSERT(its_return_thunk & 0x20, "its_return_thunk not in second half of cacheline");
+#endif
+
 #endif /* CONFIG_X86_64 */
 
 /*
index a06891892853f90ce5e2b570a114eac82c27e99d..ebca28fe7e3133f76815eadbfc697df46cb30fbe 100644 (file)
@@ -393,7 +393,18 @@ SYM_CODE_START(__x86_indirect_its_thunk_array)
        .align 64, 0xcc
 SYM_CODE_END(__x86_indirect_its_thunk_array)
 
-#endif
+.align 64, 0xcc
+.skip 32, 0xcc
+SYM_CODE_START(its_return_thunk)
+       UNWIND_HINT_FUNC
+       ANNOTATE_NOENDBR
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
+SYM_CODE_END(its_return_thunk)
+EXPORT_SYMBOL(its_return_thunk)
+
+#endif /* CONFIG_MITIGATION_ITS */
 
 /*
  * This function name is magical and is used by -mfunction-return=thunk-extern
index 01e8119db5dbaffaa1aed33c0692327d5cecdc2c..a5b65c09910babd5ef3b89055cb5b9aa9f89a8c5 100644 (file)
@@ -686,7 +686,7 @@ static void emit_return(u8 **pprog, u8 *ip)
 {
        u8 *prog = *pprog;
 
-       if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
+       if (cpu_wants_rethunk()) {
                emit_jump(&prog, x86_return_thunk, ip);
        } else {
                EMIT1(0xC3);            /* ret */