x86/alternative: Try inline spectre_v2=retpoline,amd
commit bbe2df3f6b6da7848398d55b1311d58a16ec21e4 upstream. Try and replace retpoline thunk calls with: LFENCE CALL *%\reg for spectre_v2=retpoline,amd. Specifically, the sequence above is 5 bytes for the low 8 registers, but 6 bytes for the high 8 registers. This means that unless the compilers prefix stuff the call with higher registers this replacement will fail. Luckily GCC strongly favours RAX for the indirect calls and most (95%+ for defconfig-x86_64) will be converted. OTOH clang strongly favours R11 and almost nothing gets converted. Note: it will also generate a correct replacement for the Jcc.d32 case, except unless the compilers start to prefix stuff that, it'll never fit. Specifically: Jncc.d8 1f LFENCE JMP *%\reg 1: is 7-8 bytes long, where the original instruction in unpadded form is only 6 bytes. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Borislav Petkov <bp@suse.de> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Tested-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/r/20211026120310.359986601@infradead.org [cascardo: RETPOLINE_AMD was renamed to RETPOLINE_LFENCE] Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
b0e2dc9506
commit
3d13ee0d41
@@ -544,6 +544,7 @@ static int emit_indirect(int op, int reg, u8 *bytes)
|
|||||||
*
|
*
|
||||||
* CALL *%\reg
|
* CALL *%\reg
|
||||||
*
|
*
|
||||||
|
* It also tries to inline spectre_v2=retpoline,amd when size permits.
|
||||||
*/
|
*/
|
||||||
static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
||||||
{
|
{
|
||||||
@@ -560,7 +561,8 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
|||||||
/* If anyone ever does: CALL/JMP *%rsp, we're in deep trouble. */
|
/* If anyone ever does: CALL/JMP *%rsp, we're in deep trouble. */
|
||||||
BUG_ON(reg == 4);
|
BUG_ON(reg == 4);
|
||||||
|
|
||||||
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE))
|
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE) &&
|
||||||
|
!cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
op = insn->opcode.bytes[0];
|
op = insn->opcode.bytes[0];
|
||||||
@@ -573,8 +575,9 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
|||||||
* into:
|
* into:
|
||||||
*
|
*
|
||||||
* Jncc.d8 1f
|
* Jncc.d8 1f
|
||||||
|
* [ LFENCE ]
|
||||||
* JMP *%\reg
|
* JMP *%\reg
|
||||||
* NOP
|
* [ NOP ]
|
||||||
* 1:
|
* 1:
|
||||||
*/
|
*/
|
||||||
/* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
|
/* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
|
||||||
@@ -589,6 +592,15 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
|||||||
op = JMP32_INSN_OPCODE;
|
op = JMP32_INSN_OPCODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For RETPOLINE_AMD: prepend the indirect CALL/JMP with an LFENCE.
|
||||||
|
*/
|
||||||
|
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
|
||||||
|
bytes[i++] = 0x0f;
|
||||||
|
bytes[i++] = 0xae;
|
||||||
|
bytes[i++] = 0xe8; /* LFENCE */
|
||||||
|
}
|
||||||
|
|
||||||
ret = emit_indirect(op, reg, bytes + i);
|
ret = emit_indirect(op, reg, bytes + i);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user