From 9dba9c67e52dbe0978c0e86c994891eba480adf0 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 15 May 2024 12:48:04 +0200 Subject: x86/alternatives: Use the correct length when optimizing NOPs Commit in Fixes moved the optimize_nops() call inside apply_relocation() and made it a second optimization pass after the relocations have been done. Since optimize_nops() works only on NOPs, that is fine and it'll simply jump over instructions which are not NOPs. However, it made that call with repl_len as the buffer length to optimize. However, it can happen that there are alternatives calls like this one: alternative("mfence; lfence", "", ALT_NOT(X86_FEATURE_APIC_MSRS_FENCE)); where the replacement length is 0. And using repl_len is wrong because apply_alternatives() expands the buffer size to the length of the source insn that is being patched, by padding it with one-byte NOPs: for (; insn_buff_sz < a->instrlen; insn_buff_sz++) insn_buff[insn_buff_sz] = 0x90; Long story short: pass the length of the original instruction(s) as the length of the temporary buffer which to optimize. Result: SMP alternatives: feat: 11*32+27, old: (lapic_next_deadline+0x9/0x50 (ffffffff81061829) len: 6), repl: (ffffffff89b1cc60, len: 0) flags: 0x1 SMP alternatives: ffffffff81061829: old_insn: 0f ae f0 0f ae e8 SMP alternatives: ffffffff81061829: final_insn: 90 90 90 90 90 90 => SMP alternatives: feat: 11*32+27, old: (lapic_next_deadline+0x9/0x50 (ffffffff81061839) len: 6), repl: (ffffffff89b1cc60, len: 0) flags: 0x1 SMP alternatives: ffffffff81061839: [0:6) optimized NOPs: 66 0f 1f 44 00 00 SMP alternatives: ffffffff81061839: old_insn: 0f ae f0 0f ae e8 SMP alternatives: ffffffff81061839: final_insn: 66 0f 1f 44 00 00 Fixes: da8f9cf7e721 ("x86/alternatives: Get rid of __optimize_nops()") Signed-off-by: Borislav Petkov (AMD) Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20240515104804.32004-1-bp@kernel.org --- arch/x86/kernel/alternative.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/kernel/alternative.c') diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 7555c15b7183..89de61243272 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -372,7 +372,7 @@ static void __apply_relocation(u8 *buf, const u8 * const instr, size_t instrlen, void apply_relocation(u8 *buf, const u8 * const instr, size_t instrlen, u8 *repl, size_t repl_len) { __apply_relocation(buf, instr, instrlen, repl, repl_len); - optimize_nops(instr, buf, repl_len); + optimize_nops(instr, buf, instrlen); } /* Low-level backend functions usable from alternative code replacements. */ -- cgit v1.2.3