Skip to content

Commit 2f0cbb2

Browse files
author
Peter Zijlstra
committed
x86/alternative: Handle Jcc __x86_indirect_thunk_\reg
Handle the rare cases where the compiler (clang) does an indirect conditional tail-call using: Jcc __x86_indirect_thunk_\reg For the !RETPOLINE case this can be rewritten to fit the original (6 byte) instruction like: Jncc.d8 1f JMP *%\reg NOP 1: 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 7508500 commit 2f0cbb2

File tree

1 file changed

+36
-4
lines changed

1 file changed

+36
-4
lines changed

arch/x86/kernel/alternative.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ static int emit_indirect(int op, int reg, u8 *bytes)
393393
static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
394394
{
395395
retpoline_thunk_t *target;
396-
int reg, i = 0;
396+
int reg, ret, i = 0;
397+
u8 op, cc;
397398

398399
target = addr + insn->length + insn->immediate.value;
399400
reg = target - __x86_indirect_thunk_array;
@@ -407,9 +408,36 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
407408
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE))
408409
return -1;
409410

410-
i = emit_indirect(insn->opcode.bytes[0], reg, bytes);
411-
if (i < 0)
412-
return i;
411+
op = insn->opcode.bytes[0];
412+
413+
/*
414+
* Convert:
415+
*
416+
* Jcc.d32 __x86_indirect_thunk_\reg
417+
*
418+
* into:
419+
*
420+
* Jncc.d8 1f
421+
* JMP *%\reg
422+
* NOP
423+
* 1:
424+
*/
425+
/* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
426+
if (op == 0x0f && (insn->opcode.bytes[1] & 0xf0) == 0x80) {
427+
cc = insn->opcode.bytes[1] & 0xf;
428+
cc ^= 1; /* invert condition */
429+
430+
bytes[i++] = 0x70 + cc; /* Jcc.d8 */
431+
bytes[i++] = insn->length - 2; /* sizeof(Jcc.d8) == 2 */
432+
433+
/* Continue as if: JMP.d32 __x86_indirect_thunk_\reg */
434+
op = JMP32_INSN_OPCODE;
435+
}
436+
437+
ret = emit_indirect(op, reg, bytes + i);
438+
if (ret < 0)
439+
return ret;
440+
i += ret;
413441

414442
for (; i < insn->length;)
415443
bytes[i++] = BYTES_NOP1;
@@ -443,6 +471,10 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
443471
case JMP32_INSN_OPCODE:
444472
break;
445473

474+
case 0x0f: /* escape */
475+
if (op2 >= 0x80 && op2 <= 0x8f)
476+
break;
477+
fallthrough;
446478
default:
447479
WARN_ON_ONCE(1);
448480
continue;

0 commit comments

Comments
 (0)