]> www.infradead.org Git - users/hch/misc.git/commitdiff
x86/alternative: Simplify callthunk patching
authorPeter Zijlstra <peterz@infradead.org>
Fri, 7 Feb 2025 12:15:35 +0000 (13:15 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 14 Feb 2025 09:32:06 +0000 (10:32 +0100)
Now that paravirt call patching is implemented using alternatives, it
is possible to avoid having to patch the alternative sites by
including the altinstr_replacement calls in the call_sites list.

This means we're now stacking relative adjustments like so:

  callthunks_patch_builtin_calls():
    patches all function calls to target: func() -> func()-10
    since the CALL accounting lives in the CALL_PADDING.

    This explicitly includes .altinstr_replacement

  alt_replace_call():
    patches: x86_BUG() -> target()

    this patching is done in a relative manner, and will preserve
    the above adjustment, meaning that with calldepth patching it
    will do: x86_BUG()-10 -> target()-10

  apply_relocation():
    does code relocation, and adjusts all RIP-relative instructions
    to the new location, also in a relative manner.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
Link: https://lore.kernel.org/r/20250207122546.617187089@infradead.org
arch/x86/include/asm/alternative.h
arch/x86/kernel/alternative.c
arch/x86/kernel/callthunks.c
arch/x86/kernel/module.c
tools/objtool/arch/x86/decode.c
tools/objtool/check.c

index a2141665239b5ad1283a2ccd356142dcec5dc1e4..853fbcf68719b59af63b0f68dcaf87a3e68c4323 100644 (file)
@@ -100,7 +100,6 @@ struct module;
 
 struct callthunk_sites {
        s32                             *call_start, *call_end;
-       struct alt_instr                *alt_start, *alt_end;
 };
 
 #ifdef CONFIG_CALL_THUNKS
index e914a65ff15419be950ea9f905e55430162397a3..fda11df1e650176296b5fbf1e59e4a96b3047bf0 100644 (file)
@@ -1705,14 +1705,14 @@ void __init alternative_instructions(void)
        apply_retpolines(__retpoline_sites, __retpoline_sites_end);
        apply_returns(__return_sites, __return_sites_end);
 
-       apply_alternatives(__alt_instructions, __alt_instructions_end);
-
        /*
-        * Now all calls are established. Apply the call thunks if
-        * required.
+        * Adjust all CALL instructions to point to func()-10, including
+        * those in .altinstr_replacement.
         */
        callthunks_patch_builtin_calls();
 
+       apply_alternatives(__alt_instructions, __alt_instructions_end);
+
        /*
         * Seal all functions that do not have their address taken.
         */
index 8418a892d195a99ff9dfb5473c3d5afbded5b221..25ae5425011243385d6f908f8576db8141de6401 100644 (file)
@@ -239,22 +239,11 @@ patch_call_sites(s32 *start, s32 *end, const struct core_text *ct)
                patch_call((void *)s + *s, ct);
 }
 
-static __init_or_module void
-patch_alt_call_sites(struct alt_instr *start, struct alt_instr *end,
-                    const struct core_text *ct)
-{
-       struct alt_instr *a;
-
-       for (a = start; a < end; a++)
-               patch_call((void *)&a->instr_offset + a->instr_offset, ct);
-}
-
 static __init_or_module void
 callthunks_setup(struct callthunk_sites *cs, const struct core_text *ct)
 {
        prdbg("Patching call sites %s\n", ct->name);
        patch_call_sites(cs->call_start, cs->call_end, ct);
-       patch_alt_call_sites(cs->alt_start, cs->alt_end, ct);
        prdbg("Patching call sites done%s\n", ct->name);
 }
 
@@ -263,8 +252,6 @@ void __init callthunks_patch_builtin_calls(void)
        struct callthunk_sites cs = {
                .call_start     = __call_sites,
                .call_end       = __call_sites_end,
-               .alt_start      = __alt_instructions,
-               .alt_end        = __alt_instructions_end
        };
 
        if (!cpu_feature_enabled(X86_FEATURE_CALL_DEPTH))
index 837450b6e882f7367960cbd5ec164d23bd11a9d8..cb9d295e67cbfee50944dc9bb7a6b0e3794e42a2 100644 (file)
@@ -275,12 +275,7 @@ int module_finalize(const Elf_Ehdr *hdr,
                void *rseg = (void *)returns->sh_addr;
                apply_returns(rseg, rseg + returns->sh_size);
        }
-       if (alt) {
-               /* patch .altinstructions */
-               void *aseg = (void *)alt->sh_addr;
-               apply_alternatives(aseg, aseg + alt->sh_size);
-       }
-       if (calls || alt) {
+       if (calls) {
                struct callthunk_sites cs = {};
 
                if (calls) {
@@ -288,13 +283,13 @@ int module_finalize(const Elf_Ehdr *hdr,
                        cs.call_end = (void *)calls->sh_addr + calls->sh_size;
                }
 
-               if (alt) {
-                       cs.alt_start = (void *)alt->sh_addr;
-                       cs.alt_end = (void *)alt->sh_addr + alt->sh_size;
-               }
-
                callthunks_patch_module_calls(&cs, me);
        }
+       if (alt) {
+               /* patch .altinstructions */
+               void *aseg = (void *)alt->sh_addr;
+               apply_alternatives(aseg, aseg + alt->sh_size);
+       }
        if (ibt_endbr) {
                void *iseg = (void *)ibt_endbr->sh_addr;
                apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
index fe1362c345647e966e7f20969ae0f7720055c66e..181aa604f8cdfdb5b574d97a9085953b5dea1ea7 100644 (file)
@@ -850,5 +850,6 @@ bool arch_is_rethunk(struct symbol *sym)
 bool arch_is_embedded_insn(struct symbol *sym)
 {
        return !strcmp(sym->name, "retbleed_return_thunk") ||
+              !strcmp(sym->name, "srso_alias_safe_ret") ||
               !strcmp(sym->name, "srso_safe_ret");
 }
index 753dbc4f81985368dd2b6b7ff580f3c329ef9763..26f2c1b8e099ca518a888033258c359ca756aa75 100644 (file)
@@ -1283,15 +1283,6 @@ static void annotate_call_site(struct objtool_file *file,
        if (!sym)
                sym = reloc->sym;
 
-       /*
-        * Alternative replacement code is just template code which is
-        * sometimes copied to the original instruction. For now, don't
-        * annotate it. (In the future we might consider annotating the
-        * original instruction if/when it ever makes sense to do so.)
-        */
-       if (!strcmp(insn->sec->name, ".altinstr_replacement"))
-               return;
-
        if (sym->static_call_tramp) {
                list_add_tail(&insn->call_node, &file->static_call_list);
                return;
@@ -1349,7 +1340,8 @@ static void annotate_call_site(struct objtool_file *file,
                return;
        }
 
-       if (insn->type == INSN_CALL && !insn->sec->init)
+       if (insn->type == INSN_CALL && !insn->sec->init &&
+           !insn->_call_dest->embedded_insn)
                list_add_tail(&insn->call_node, &file->call_list);
 
        if (!sibling && dead_end_function(file, sym))