Skip to content

Commit bbe2df3

Browse files
author
Peter Zijlstra
committed
x86/alternative: Try inline spectre_v2=retpoline,amd
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) <[email protected]> Reviewed-by: Borislav Petkov <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Tested-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2f0cbb2 commit bbe2df3

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

arch/x86/kernel/alternative.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ static int emit_indirect(int op, int reg, u8 *bytes)
389389
*
390390
* CALL *%\reg
391391
*
392+
* It also tries to inline spectre_v2=retpoline,amd when size permits.
392393
*/
393394
static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
394395
{
@@ -405,7 +406,8 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
405406
/* If anyone ever does: CALL/JMP *%rsp, we're in deep trouble. */
406407
BUG_ON(reg == 4);
407408

408-
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE))
409+
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE) &&
410+
!cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD))
409411
return -1;
410412

411413
op = insn->opcode.bytes[0];
@@ -418,8 +420,9 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
418420
* into:
419421
*
420422
* Jncc.d8 1f
423+
* [ LFENCE ]
421424
* JMP *%\reg
422-
* NOP
425+
* [ NOP ]
423426
* 1:
424427
*/
425428
/* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
@@ -434,6 +437,15 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
434437
op = JMP32_INSN_OPCODE;
435438
}
436439

440+
/*
441+
* For RETPOLINE_AMD: prepend the indirect CALL/JMP with an LFENCE.
442+
*/
443+
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD)) {
444+
bytes[i++] = 0x0f;
445+
bytes[i++] = 0xae;
446+
bytes[i++] = 0xe8; /* LFENCE */
447+
}
448+
437449
ret = emit_indirect(op, reg, bytes + i);
438450
if (ret < 0)
439451
return ret;

0 commit comments

Comments
 (0)