Skip to content

Commit 15e6722

Browse files
Peter Zijlstrasuryasaimadhu
authored andcommitted
x86: Undo return-thunk damage
Introduce X86_FEATURE_RETHUNK for those afflicted with needing this. [ bp: Do only INT3 padding - simpler. ] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de>
1 parent 0b53c37 commit 15e6722

File tree

6 files changed

+78
-2
lines changed

6 files changed

+78
-2
lines changed

arch/x86/include/asm/alternative.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ extern int alternatives_patched;
7676
extern void alternative_instructions(void);
7777
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
7878
extern void apply_retpolines(s32 *start, s32 *end);
79+
extern void apply_returns(s32 *start, s32 *end);
7980
extern void apply_ibt_endbr(s32 *start, s32 *end);
8081

8182
struct module;

arch/x86/include/asm/cpufeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@
300300
/* FREE! (11*32+11) */
301301
#define X86_FEATURE_RETPOLINE (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
302302
#define X86_FEATURE_RETPOLINE_LFENCE (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
303+
#define X86_FEATURE_RETHUNK (11*32+14) /* "" Use REturn THUNK */
303304

304305
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
305306
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */

arch/x86/include/asm/disabled-features.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
# define DISABLE_RETPOLINE 0
5555
#else
5656
# define DISABLE_RETPOLINE ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
57-
(1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
57+
(1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)) | \
58+
(1 << (X86_FEATURE_RETHUNK & 31)))
5859
#endif
5960

6061
#ifdef CONFIG_INTEL_IOMMU_SVM

arch/x86/kernel/alternative.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
115115
}
116116

117117
extern s32 __retpoline_sites[], __retpoline_sites_end[];
118+
extern s32 __return_sites[], __return_sites_end[];
118119
extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
119120
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
120121
extern s32 __smp_locks[], __smp_locks_end[];
@@ -507,9 +508,67 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
507508
}
508509
}
509510

511+
/*
512+
* Rewrite the compiler generated return thunk tail-calls.
513+
*
514+
* For example, convert:
515+
*
516+
* JMP __x86_return_thunk
517+
*
518+
* into:
519+
*
520+
* RET
521+
*/
522+
static int patch_return(void *addr, struct insn *insn, u8 *bytes)
523+
{
524+
int i = 0;
525+
526+
if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
527+
return -1;
528+
529+
bytes[i++] = RET_INSN_OPCODE;
530+
531+
for (; i < insn->length;)
532+
bytes[i++] = INT3_INSN_OPCODE;
533+
534+
return i;
535+
}
536+
537+
void __init_or_module noinline apply_returns(s32 *start, s32 *end)
538+
{
539+
s32 *s;
540+
541+
for (s = start; s < end; s++) {
542+
void *addr = (void *)s + *s;
543+
struct insn insn;
544+
int len, ret;
545+
u8 bytes[16];
546+
u8 op1;
547+
548+
ret = insn_decode_kernel(&insn, addr);
549+
if (WARN_ON_ONCE(ret < 0))
550+
continue;
551+
552+
op1 = insn.opcode.bytes[0];
553+
if (WARN_ON_ONCE(op1 != JMP32_INSN_OPCODE))
554+
continue;
555+
556+
DPRINTK("return thunk at: %pS (%px) len: %d to: %pS",
557+
addr, addr, insn.length,
558+
addr + insn.length + insn.immediate.value);
559+
560+
len = patch_return(addr, &insn, bytes);
561+
if (len == insn.length) {
562+
DUMP_BYTES(((u8*)addr), len, "%px: orig: ", addr);
563+
DUMP_BYTES(((u8*)bytes), len, "%px: repl: ", addr);
564+
text_poke_early(addr, bytes, len);
565+
}
566+
}
567+
}
510568
#else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */
511569

512570
void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }
571+
void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
513572

514573
#endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */
515574

@@ -860,6 +919,7 @@ void __init alternative_instructions(void)
860919
* those can rewrite the retpoline thunks.
861920
*/
862921
apply_retpolines(__retpoline_sites, __retpoline_sites_end);
922+
apply_returns(__return_sites, __return_sites_end);
863923

864924
/*
865925
* Then patch alternatives, such that those paravirt calls that are in

arch/x86/kernel/module.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ int module_finalize(const Elf_Ehdr *hdr,
253253
{
254254
const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
255255
*para = NULL, *orc = NULL, *orc_ip = NULL,
256-
*retpolines = NULL, *ibt_endbr = NULL;
256+
*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL;
257257
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
258258

259259
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
@@ -271,6 +271,8 @@ int module_finalize(const Elf_Ehdr *hdr,
271271
orc_ip = s;
272272
if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
273273
retpolines = s;
274+
if (!strcmp(".return_sites", secstrings + s->sh_name))
275+
returns = s;
274276
if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
275277
ibt_endbr = s;
276278
}
@@ -287,6 +289,10 @@ int module_finalize(const Elf_Ehdr *hdr,
287289
void *rseg = (void *)retpolines->sh_addr;
288290
apply_retpolines(rseg, rseg + retpolines->sh_size);
289291
}
292+
if (returns) {
293+
void *rseg = (void *)returns->sh_addr;
294+
apply_returns(rseg, rseg + returns->sh_size);
295+
}
290296
if (alt) {
291297
/* patch .altinstructions */
292298
void *aseg = (void *)alt->sh_addr;

arch/x86/kernel/vmlinux.lds.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,13 @@ SECTIONS
283283
*(.retpoline_sites)
284284
__retpoline_sites_end = .;
285285
}
286+
287+
. = ALIGN(8);
288+
.return_sites : AT(ADDR(.return_sites) - LOAD_OFFSET) {
289+
__return_sites = .;
290+
*(.return_sites)
291+
__return_sites_end = .;
292+
}
286293
#endif
287294

288295
#ifdef CONFIG_X86_KERNEL_IBT

0 commit comments

Comments
 (0)