[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.17] x86/stubs: Introduce place_ret() to abstract away raw 0xc3's
commit ddc5c1e0aafb9b21faa6da94d74be89bc0158ed8 Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Sun May 4 22:44:42 2025 +0100 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Mon May 12 17:32:24 2025 +0100 x86/stubs: Introduce place_ret() to abstract away raw 0xc3's The Indirect Target Selection speculative vulnerability means that indirect branches (including RETs) are unsafe when in the first half of a cacheline. This means it's not safe for logic using the stubs to write raw 0xc3's. Introduce place_ret() which, for now, writes a raw 0xc3 but will contain additional logic when return thunks are in use. stub_selftest() doesn't strictly need to be converted as they only run on boot, but doing so gets us a partial test of place_ret() too. No functional change. This is part of XSA-469 / CVE-2024-28956 Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> (cherry picked from commit 2eb1132f796386e4524fb25dd0ed349e14ca35dd) --- tools/tests/x86_emulator/x86-emulate.h | 6 +++ xen/arch/x86/Makefile | 6 +-- xen/arch/x86/alternative.c | 14 ++++++ xen/arch/x86/extable.c | 11 ++--- xen/arch/x86/include/asm/alternative.h | 2 + xen/arch/x86/pv/emul-priv-op.c | 5 ++- xen/arch/x86/x86_emulate/x86_emulate.c | 82 ++++++++++++++++++---------------- 7 files changed, 77 insertions(+), 49 deletions(-) diff --git a/tools/tests/x86_emulator/x86-emulate.h b/tools/tests/x86_emulator/x86-emulate.h index 58760f096d..65ae95e624 100644 --- a/tools/tests/x86_emulator/x86-emulate.h +++ b/tools/tests/x86_emulator/x86-emulate.h @@ -67,6 +67,12 @@ #define is_canonical_address(x) (((int64_t)(x) >> 47) == ((int64_t)(x) >> 63)) +static inline void *place_ret(void *ptr) +{ + *(uint8_t *)ptr = 0xc3; + return ptr + 1; +} + extern uint32_t mxcsr_mask; extern struct cpu_policy cp; diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 6a070a8cf8..882408ccaf 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -10,9 +10,7 @@ obj-$(CONFIG_XENOPROF) += oprofile/ obj-$(CONFIG_PV) += pv/ obj-y += x86_64/ -alternative-y := alternative.init.o -alternative-$(CONFIG_LIVEPATCH) := -obj-bin-y += $(alternative-y) +obj-y += alternative.o obj-y += apic.o obj-y += bhb-thunk.o obj-y += bitops.o @@ -40,7 +38,7 @@ obj-y += hypercall.o obj-y += i387.o obj-y += i8259.o obj-y += io_apic.o -obj-$(CONFIG_LIVEPATCH) += alternative.o livepatch.o +obj-$(CONFIG_LIVEPATCH) += livepatch.o obj-y += msi.o obj-y += msr.o obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c index 6eee6e501a..88082f68a9 100644 --- a/xen/arch/x86/alternative.c +++ b/xen/arch/x86/alternative.c @@ -149,6 +149,20 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) } } +/* + * Place a return at @ptr. @ptr must be in the writable alias of a stub. + * + * Returns the next position to write into the stub. + */ +void *place_ret(void *ptr) +{ + uint8_t *p = ptr; + + *p++ = 0xc3; + + return p; +} + /* * text_poke - Update instructions on a live kernel or non-executed code. * @addr: address to modify diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c index f05c16def6..adfd439d3a 100644 --- a/xen/arch/x86/extable.c +++ b/xen/arch/x86/extable.c @@ -135,20 +135,20 @@ search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) int __init cf_check stub_selftest(void) { static const struct { - uint8_t opc[8]; + uint8_t opc[7]; uint64_t rax; union stub_exception_token res; } tests[] __initconst = { #define endbr64 0xf3, 0x0f, 0x1e, 0xfa - { .opc = { endbr64, 0x0f, 0xb9, 0xc3, 0xc3 }, /* ud1 */ + { .opc = { endbr64, 0x0f, 0xb9, 0x90 }, /* ud1 */ .res.fields.trapnr = TRAP_invalid_op }, - { .opc = { endbr64, 0x90, 0x02, 0x00, 0xc3 }, /* nop; add (%rax),%al */ + { .opc = { endbr64, 0x90, 0x02, 0x00 }, /* nop; add (%rax),%al */ .rax = 0x0123456789abcdef, .res.fields.trapnr = TRAP_gp_fault }, - { .opc = { endbr64, 0x02, 0x04, 0x04, 0xc3 }, /* add (%rsp,%rax),%al */ + { .opc = { endbr64, 0x02, 0x04, 0x04 }, /* add (%rsp,%rax),%al */ .rax = 0xfedcba9876543210, .res.fields.trapnr = TRAP_stack_error }, - { .opc = { endbr64, 0xcc, 0xc3, 0xc3, 0xc3 }, /* int3 */ + { .opc = { endbr64, 0xcc, 0x90, 0x90 }, /* int3 */ .res.fields.trapnr = TRAP_int3 }, #undef endbr64 }; @@ -167,6 +167,7 @@ int __init cf_check stub_selftest(void) memset(ptr, 0xcc, STUB_BUF_SIZE / 2); memcpy(ptr, tests[i].opc, ARRAY_SIZE(tests[i].opc)); + place_ret(ptr + ARRAY_SIZE(tests[i].opc)); unmap_domain_page(ptr); asm volatile ( "INDIRECT_CALL %[stb]\n" diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h index 388e595786..28e69e988a 100644 --- a/xen/arch/x86/include/asm/alternative.h +++ b/xen/arch/x86/include/asm/alternative.h @@ -30,6 +30,8 @@ struct __packed alt_instr { #define ALT_REPL_PTR(a) __ALT_PTR(a, repl_offset) extern void add_nops(void *insns, unsigned int len); +void *place_ret(void *ptr); + /* Similar to alternative_instructions except it can be run with IRQs enabled. */ extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); extern void alternative_instructions(void); diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c index f216c26412..28ea7cc580 100644 --- a/xen/arch/x86/pv/emul-priv-op.c +++ b/xen/arch/x86/pv/emul-priv-op.c @@ -88,7 +88,6 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, 0x41, 0x5c, /* pop %r12 */ 0x5d, /* pop %rbp */ 0x5b, /* pop %rbx */ - 0xc3, /* ret */ }; const struct stubs *this_stubs = &this_cpu(stubs); @@ -138,11 +137,13 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, APPEND_CALL(save_guest_gprs); APPEND_BUFF(epilogue); + p = place_ret(p); /* Build-time best effort attempt to catch problems. */ BUILD_BUG_ON(STUB_BUF_SIZE / 2 < (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + - MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES))); + MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + + 1 /* ret */)); /* Runtime confirmation that we haven't clobbered an adjacent stub. */ BUG_ON(STUB_BUF_SIZE / 2 < (p - ctxt->io_emul_stub)); diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 995670cbc8..b5eca13410 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1533,36 +1533,42 @@ static inline bool fpu_check_write(void) #define emulate_fpu_insn_memdst(opc, ext, arg) \ do { \ + void *_p = get_stub(stub); \ /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ insn_bytes = 2; \ - memcpy(get_stub(stub), \ - ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ + place_ret(_p); \ invoke_stub("", "", "+m" (arg) : "a" (&(arg))); \ put_stub(stub); \ } while (0) #define emulate_fpu_insn_memsrc(opc, ext, arg) \ do { \ + void *_p = get_stub(stub); \ /* ModRM: mod=0, reg=ext, rm=0, i.e. a (%rax) operand */ \ - memcpy(get_stub(stub), \ - ((uint8_t[]){ opc, ((ext) & 7) << 3, 0xc3 }), 3); \ + memcpy(_p, ((uint8_t[]){ opc, ((ext) & 7) << 3 }), 2); _p += 2; \ + place_ret(_p); \ invoke_stub("", "", "=m" (dummy) : "m" (arg), "a" (&(arg))); \ put_stub(stub); \ } while (0) #define emulate_fpu_insn_stub(bytes...) \ do { \ + void *_p = get_stub(stub); \ unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ - memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ + memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ + place_ret(_p); \ invoke_stub("", "", "=m" (dummy) : "i" (0)); \ put_stub(stub); \ } while (0) #define emulate_fpu_insn_stub_eflags(bytes...) \ do { \ + void *_p = get_stub(stub); \ unsigned int nr_ = sizeof((uint8_t[]){ bytes }); \ unsigned long tmp_; \ - memcpy(get_stub(stub), ((uint8_t[]){ bytes, 0xc3 }), nr_ + 1); \ + memcpy(_p, ((uint8_t[]){ bytes }), nr_); _p += nr_; \ + place_ret(_p); \ invoke_stub(_PRE_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ _POST_EFLAGS("[eflags]", "[mask]", "[tmp]"), \ [eflags] "+g" (_regs.eflags), [tmp] "=&r" (tmp_) \ @@ -3852,7 +3858,7 @@ x86_emulate( stb[3] = 0x91; stb[4] = evex.opmsk << 3; insn_bytes = 5; - stb[5] = 0xc3; + place_ret(&stb[5]); invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); @@ -6751,7 +6757,7 @@ x86_emulate( evex.lr = 0; opc[1] = (modrm & 0x38) | 0xc0; insn_bytes = EVEX_PFX_BYTES + 2; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_EVEX(opc, evex); invoke_stub("", "", "=g" (dummy) : "a" (src.val)); @@ -6816,7 +6822,7 @@ x86_emulate( insn_bytes = PFX_BYTES + 2; copy_REX_VEX(opc, rex_prefix, vex); } - opc[2] = 0xc3; + place_ret(&opc[2]); ea.reg = decode_gpr(&_regs, modrm_reg); invoke_stub("", "", "=a" (*ea.reg) : "c" (mmvalp), "m" (*mmvalp)); @@ -6884,7 +6890,7 @@ x86_emulate( insn_bytes = PFX_BYTES + 2; copy_REX_VEX(opc, rex_prefix, vex); } - opc[2] = 0xc3; + place_ret(&opc[2]); _regs.eflags &= ~EFLAGS_MASK; invoke_stub("", @@ -7113,7 +7119,7 @@ x86_emulate( opc[1] = modrm & 0xc7; insn_bytes = PFX_BYTES + 2; simd_0f_to_gpr: - opc[insn_bytes - PFX_BYTES] = 0xc3; + place_ret(&opc[insn_bytes - PFX_BYTES]); generate_exception_if(ea.type != OP_REG, EXC_UD); @@ -7510,7 +7516,7 @@ x86_emulate( vex.w = 0; opc[1] = modrm & 0x38; insn_bytes = PFX_BYTES + 2; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_REX_VEX(opc, rex_prefix, vex); invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); @@ -7538,7 +7544,7 @@ x86_emulate( evex.w = 0; opc[1] = modrm & 0x38; insn_bytes = EVEX_PFX_BYTES + 2; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_EVEX(opc, evex); invoke_stub("", "", "+m" (src.val) : "a" (&src.val)); @@ -7733,7 +7739,7 @@ x86_emulate( #endif /* X86EMUL_NO_SIMD */ simd_0f_reg_only: - opc[insn_bytes - PFX_BYTES] = 0xc3; + place_ret(&opc[insn_bytes - PFX_BYTES]); copy_REX_VEX(opc, rex_prefix, vex); invoke_stub("", "", [dummy_out] "=g" (dummy) : [dummy_in] "i" (0) ); @@ -8058,7 +8064,7 @@ x86_emulate( if ( !mode_64bit() ) vex.w = 0; opc[1] = modrm & 0xf8; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_VEX(opc, vex); ea.reg = decode_gpr(&_regs, modrm_rm); @@ -8101,7 +8107,7 @@ x86_emulate( if ( !mode_64bit() ) vex.w = 0; opc[1] = modrm & 0xc7; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_VEX(opc, vex); invoke_stub("", "", "=a" (dst.val) : [dummy] "i" (0)); @@ -8131,7 +8137,7 @@ x86_emulate( opc = init_prefixes(stub); opc[0] = b; opc[1] = modrm; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_VEX(opc, vex); _regs.eflags &= ~EFLAGS_MASK; @@ -9027,7 +9033,7 @@ x86_emulate( if ( !mode_64bit() ) vex.w = 0; opc[1] = modrm & 0xc7; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_REX_VEX(opc, rex_prefix, vex); invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); @@ -9145,7 +9151,7 @@ x86_emulate( opc[1] &= 0x38; } insn_bytes = PFX_BYTES + 2; - opc[2] = 0xc3; + place_ret(&opc[2]); if ( vex.opcx == vex_none ) { /* Cover for extra prefix byte. */ @@ -9424,7 +9430,7 @@ x86_emulate( pvex->b = !mode_64bit() || (vex.reg >> 3); opc[1] = 0xc0 | (~vex.reg & 7); pvex->reg = 0xf; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "=a" (ea.val) : [dummy] "i" (0)); put_stub(stub); @@ -9684,7 +9690,7 @@ x86_emulate( evex.w = 0; opc[1] = modrm & 0xf8; insn_bytes = EVEX_PFX_BYTES + 2; - opc[2] = 0xc3; + place_ret(&opc[2]); copy_EVEX(opc, evex); invoke_stub("", "", "=g" (dummy) : "a" (src.val)); @@ -9783,7 +9789,7 @@ x86_emulate( pvex->b = 1; opc[1] = (modrm_reg & 7) << 3; pvex->reg = 0xf; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); @@ -9853,7 +9859,7 @@ x86_emulate( pvex->b = 1; opc[1] = (modrm_reg & 7) << 3; pvex->reg = 0xf; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); @@ -9909,7 +9915,7 @@ x86_emulate( pevex->b = 1; opc[1] = (modrm_reg & 7) << 3; pevex->RX = 1; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); @@ -9974,7 +9980,7 @@ x86_emulate( pevex->b = 1; opc[1] = (modrm_reg & 7) << 3; pevex->RX = 1; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "+m" (*mmvalp) : "a" (mmvalp)); @@ -9988,7 +9994,7 @@ x86_emulate( opc[2] = 0x90; /* Use (%rax) as source. */ opc[3] = evex.opmsk << 3; - opc[4] = 0xc3; + place_ret(&opc[4]); invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); put_stub(stub); @@ -10082,7 +10088,7 @@ x86_emulate( pevex->b = 1; opc[1] = (modrm_reg & 7) << 3; pevex->RX = 1; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "=m" (*mmvalp) : "a" (mmvalp)); @@ -10160,7 +10166,7 @@ x86_emulate( opc[2] = 0x90; /* Use (%rax) as source. */ opc[3] = evex.opmsk << 3; - opc[4] = 0xc3; + place_ret(&opc[4]); invoke_stub("", "", "+m" (op_mask) : "a" (&op_mask)); put_stub(stub); @@ -10229,7 +10235,7 @@ x86_emulate( pevex->r = !mode_64bit() || !(state->sib_index & 0x08); pevex->R = !mode_64bit() || !(state->sib_index & 0x10); pevex->RX = 1; - opc[2] = 0xc3; + place_ret(&opc[2]); invoke_stub("", "", "=m" (index) : "a" (&index)); put_stub(stub); @@ -10404,7 +10410,7 @@ x86_emulate( pvex->reg = 0xf; /* rAX */ buf[3] = b; buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ - buf[5] = 0xc3; + place_ret(&buf[5]); src.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val), "a" (*src.reg)); @@ -10438,7 +10444,7 @@ x86_emulate( pvex->reg = 0xf; /* rAX */ buf[3] = b; buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ - buf[5] = 0xc3; + place_ret(&buf[5]); dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); emulate_stub("=&a" (dst.val), "c" (&src.val)); @@ -10670,7 +10676,7 @@ x86_emulate( evex.w = vex.w = 0; opc[1] = modrm & 0x38; opc[2] = imm1; - opc[3] = 0xc3; + place_ret(&opc[3]); if ( vex.opcx == vex_none ) { /* Cover for extra prefix byte. */ @@ -10837,7 +10843,7 @@ x86_emulate( insn_bytes = PFX_BYTES + 3; copy_VEX(opc, vex); } - opc[3] = 0xc3; + place_ret(&opc[3]); /* Latch MXCSR - we may need to restore it below. */ invoke_stub("stmxcsr %[mxcsr]", "", @@ -11065,7 +11071,7 @@ x86_emulate( } opc[2] = imm1; insn_bytes = PFX_BYTES + 3; - opc[3] = 0xc3; + place_ret(&opc[3]); if ( vex.opcx == vex_none ) { /* Cover for extra prefix byte. */ @@ -11225,7 +11231,7 @@ x86_emulate( pxop->reg = 0xf; /* rAX */ buf[3] = b; buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */ - buf[5] = 0xc3; + place_ret(&buf[5]); dst.reg = decode_vex_gpr(vex.reg, &_regs, ctxt); emulate_stub([dst] "=&a" (dst.val), "c" (&src.val)); @@ -11334,7 +11340,7 @@ x86_emulate( buf[3] = b; buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */ *(uint32_t *)(buf + 5) = imm1; - buf[9] = 0xc3; + place_ret(&buf[9]); emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val)); @@ -11401,12 +11407,12 @@ x86_emulate( BUG(); if ( evex_encoded() ) { - opc[insn_bytes - EVEX_PFX_BYTES] = 0xc3; + place_ret(&opc[insn_bytes - EVEX_PFX_BYTES]); copy_EVEX(opc, evex); } else { - opc[insn_bytes - PFX_BYTES] = 0xc3; + place_ret(&opc[insn_bytes - PFX_BYTES]); copy_REX_VEX(opc, rex_prefix, vex); } -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.17
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |