diff --git a/.gitignore b/.gitignore index 85e99f7..bc73efe 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ lwip-1.3.0.tar.gz pciutils-2.2.9.tar.bz2 zlib-1.2.3.tar.gz polarssl-1.1.4-gpl.tgz -/xen-4.19.2.tar.gz +/xen-4.19.5.tar.gz diff --git a/sources b/sources index 1e984f8..bbd5e0b 100644 --- a/sources +++ b/sources @@ -4,4 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77 SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5 -SHA512 (xen-4.19.2.tar.gz) = 35147b0d755b5a603915fa5017bc021d4a238ab96ee1139dfee8e0f6ba76e64b89d5f331fbd60549682f45ee983d3d8f1cb95c53eed22373a7fa06074ca8da09 +SHA512 (xen-4.19.5.tar.gz) = 7472a0fcf159b12ac464bba867bea8852de991f136fd5ca5bf20ae8826ef8659a58a5437eeb79800375b7e4be59d3f6c92b2a73bb2d73fcfbf8dea73a5d303dd diff --git a/xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch b/xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch new file mode 100644 index 0000000..19a1e96 --- /dev/null +++ b/xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch @@ -0,0 +1,88 @@ +From 60a2c34900373ded0c81dbb7367792178b6c33b9 Mon Sep 17 00:00:00 2001 +From: Andrew Cooper +Date: Fri, 10 Apr 2026 21:55:46 +0100 +Subject: [PATCH] x86/amd: Mitigate AMD-SN-7053 / FP-DSS +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +This is XSA-488 / CVE-2025-54505 + +Signed-off-by: Andrew Cooper +Reviewed-by: Roger Pau Monné +(cherry picked from commit 99912d346009fda1e7fb1510c9501fbab17e92a0) +--- + xen/arch/x86/cpu/amd.c | 37 ++++++++++++++++++++++++++++ + xen/arch/x86/include/asm/msr-index.h | 1 + + 2 files changed, 38 insertions(+) + +diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c +index ebeed00941..12876de1df 100644 +--- a/xen/arch/x86/cpu/amd.c ++++ b/xen/arch/x86/cpu/amd.c +@@ -982,6 +982,42 @@ void amd_init_de_cfg(const struct cpuinfo_x86 *c) + wrmsrl(MSR_AMD64_DE_CFG, val | new); + } + ++static void amd_init_fp_cfg(const struct cpuinfo_x86 *c) ++{ ++ uint64_t val, new = 0; ++ ++ /* If virtualised, we won't have mutable access even if we can read it. */ ++ if ( cpu_has_hypervisor ) ++ return; ++ ++ /* ++ * On Zen1, mitigate SB-7053 / FP-DSS Floating Point Divider State ++ * Sampling by setting bit 9 as instructed. ++ */ ++ if ( c->x86 == 0x17 && is_zen1_uarch() ) ++ new |= 1 << 9; ++ ++ /* ++ * Avoid reading FP_CFG if we don't intend to change anything. The ++ * register doesn't exist on all families. ++ */ ++ if ( !new ) ++ return; ++ ++ rdmsrl(MSR_AMD64_FP_CFG, val); ++ ++ if ( (val & new) == new ) ++ return; ++ ++ /* ++ * FP_CFG is a Core-scoped MSR, and this write is racy. However, both ++ * threads calculate the new value from state which expected to be ++ * consistent across CPUs and unrelated to the old value, so the result ++ * should be consistent. ++ */ ++ wrmsrl(MSR_AMD64_FP_CFG, val | new); ++} ++ + void __init amd_init_lfence_dispatch(void) + { + struct cpuinfo_x86 *c = &boot_cpu_data; +@@ -1055,6 +1091,7 @@ static void cf_check init_amd(struct cpuinfo_x86 *c) + unsigned long long value; + + amd_init_de_cfg(c); ++ amd_init_fp_cfg(c); + + if (c == &boot_cpu_data) + amd_init_lfence_dispatch(); /* Needs amd_init_de_cfg() */ +diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h +index 6f2c3147e3..70e5f09a2d 100644 +--- a/xen/arch/x86/include/asm/msr-index.h ++++ b/xen/arch/x86/include/asm/msr-index.h +@@ -411,6 +411,7 @@ + #define MSR_AMD64_LS_CFG 0xc0011020U + #define MSR_AMD64_IC_CFG 0xc0011021U + #define MSR_AMD64_DC_CFG 0xc0011022U ++#define MSR_AMD64_FP_CFG 0xc0011028U + #define MSR_AMD64_DE_CFG 0xc0011029U + #define AMD64_DE_CFG_LFENCE_SERIALISE (_AC(1, ULL) << 1) + #define MSR_AMD64_EX_CFG 0xc001102cU +-- +2.39.5 + diff --git a/xen.spec b/xen.spec index 650144d..036e057 100644 --- a/xen.spec +++ b/xen.spec @@ -54,8 +54,8 @@ Summary: Xen is a virtual machine monitor Name: xen -Version: 4.19.2 -Release: 4%{?dist} +Version: 4.19.5 +Release: 2%{?dist} # Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended. License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD URL: http://xen.org/ @@ -111,13 +111,10 @@ Patch43: xen.gcc11.fixes.patch Patch45: xen.gcc12.fixes.patch Patch46: xen.efi.build.patch Patch49: xen.python3.12.patch -Patch50: xsa469-4.19-01.patch -Patch51: xsa469-4.19-02.patch -Patch52: xsa469-4.19-03.patch -Patch53: xsa469-4.19-04.patch -Patch54: xsa469-4.19-05.patch -Patch55: xsa469-4.19-06.patch -Patch56: xsa469-4.19-07.patch +Patch50: xsa483.patch +Patch51: xsa484.patch +Patch52: xsa486.patch +Patch53: xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch %if %build_qemutrad @@ -330,9 +327,6 @@ manage Xen virtual machines. %patch 51 -p1 %patch 52 -p1 %patch 53 -p1 -%patch 54 -p1 -%patch 55 -p1 -%patch 56 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -951,6 +945,54 @@ fi %endif %changelog +* Wed Apr 29 2026 Michael Young - 4.19.5-2 +- oxenstored keeps quota related use counts across domain destruction + [XSA-483, CVE-2026-23556] +- Xenstored DoS via XS_RESET_WATCHES command [XSA-484, CVE-2026-23557] +- grant table v2 race in status page mapping [XSA-486, CVE-2026-23558] +- x86: Floating Point Divider State Sampling [XSA-488, CVE-2025-54505] + +* Fri Mar 27 2026 Michael Young - 4.19.5-1 +- update to xen 4.19.5 + remove patches now included or superceded upstream + +* Wed Mar 18 2026 Michael Young - 4.19.4-3 +- Use after free of paging structures in EPT [XSA-480, CVE-2026-23554] +- Xenstored DoS by unprivileged domain [XSA-481, CVE-2026-23555] + +* Thu Jan 29 2026 Michael Young - 4.19.4-2 + x86: buffer overrun with shadow paging + tracing [XSA-477, CVE-2025-58150] + (#2434045) + x86: incomplete IBPB for vCPU isolation [XSA-479, CVE-2026-23553] + (#2434047) + +* Sat Dec 06 2025 Michael Young - 4.19.4-1 +- update to xen-4.19.4 + remove patches now included or superceded upstream + +* Fri Oct 24 2025 Michael Young - 4.19.3-8 +- Incorrect removal of permissions on PCI device unplug [XSA-476, + CVE-2025-58149] + +* Tue Oct 21 2025 Michael Young - 4.19.3-6 +- x86: Incorrect input sanitisation in Viridian hypercalls [XSA-475, + CVE-2025-58147, CVE-2025-58148] + +* Mon Sep 15 2025 Michael Young - 4.19.3-4 +- Mutiple vulnerabilities in the Viridian interface [XSA-472, + CVE-2025-27466, CVE-2025-58142, CVE-2025-58143] +- Arm issues with page refcounting [XSA-473, CVE-2025-58144, + CVE-2025-58145] + +* Tue Aug 05 2025 Michael Young - 4.19.3-2 +- update to xen-4.19.3 + remove patches now included or superceded upstream + includes patches for + x86: Incorrect stubs exception handling for flags recovery [XSA-470, + CVE-2025-27465] + x86: Transitive Scheduler Attacks [XSA-471, CVE-2024-36350, + CVE-2024-36357] + * Mon May 12 2025 Michael Young - 4.19.2-4 - x86: Indirect Target Selection [XSA-469, CVE-2024-28956] diff --git a/xsa469-4.19-01.patch b/xsa469-4.19-01.patch deleted file mode 100644 index cbbb14f..0000000 --- a/xsa469-4.19-01.patch +++ /dev/null @@ -1,83 +0,0 @@ -From: Andrew Cooper -Subject: x86/alternative: Support replacements when a feature is not present - -Use the top bit of a->cpuid to express inverted polarity. This requires -stripping the top bit back out when performing the sanity checks. - -Despite only being used once, create a replace boolean to express the decision -more clearly in _apply_alternatives(). - -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c -index 1ba35cb9ede9..88c90044c20d 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -197,6 +197,8 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - uint8_t *repl = ALT_REPL_PTR(a); - uint8_t buf[MAX_PATCH_LEN]; - unsigned int total_len = a->orig_len + a->pad_len; -+ unsigned int feat = a->cpuid & ~ALT_FLAG_NOT; -+ bool inv = a->cpuid & ALT_FLAG_NOT, replace; - - if ( a->repl_len > total_len ) - { -@@ -214,11 +216,11 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - return -ENOSPC; - } - -- if ( a->cpuid >= NCAPINTS * 32 ) -+ if ( feat >= NCAPINTS * 32 ) - { - printk(XENLOG_ERR - "Alt for %ps, feature %#x outside of featureset range %#x\n", -- ALT_ORIG_PTR(a), a->cpuid, NCAPINTS * 32); -+ ALT_ORIG_PTR(a), feat, NCAPINTS * 32); - return -ERANGE; - } - -@@ -243,8 +245,14 @@ static int init_or_livepatch _apply_alternatives(struct alt_instr *start, - continue; - } - -+ /* -+ * Should a replacement be performed? Most replacements have positive -+ * polarity, but we support negative polarity too. -+ */ -+ replace = boot_cpu_has(feat) ^ inv; -+ - /* If there is no replacement to make, see about optimising the nops. */ -- if ( !boot_cpu_has(a->cpuid) ) -+ if ( !replace ) - { - /* Origin site site already touched? Don't nop anything. */ - if ( base->priv ) -diff --git a/xen/arch/x86/include/asm/alternative.h b/xen/arch/x86/include/asm/alternative.h -index 69555d781ef9..89b7bdcb82e5 100644 ---- a/xen/arch/x86/include/asm/alternative.h -+++ b/xen/arch/x86/include/asm/alternative.h -@@ -1,6 +1,13 @@ - #ifndef __X86_ALTERNATIVE_H__ - #define __X86_ALTERNATIVE_H__ - -+/* -+ * Common to both C and ASM. Express a replacement when a feature is not -+ * available. -+ */ -+#define ALT_FLAG_NOT (1 << 15) -+#define ALT_NOT(x) (ALT_FLAG_NOT | (x)) -+ - #ifdef __ASSEMBLY__ - #include - #else -@@ -11,7 +18,7 @@ - struct __packed alt_instr { - int32_t orig_offset; /* original instruction */ - int32_t repl_offset; /* offset to replacement instruction */ -- uint16_t cpuid; /* cpuid bit set for replacement */ -+ uint16_t cpuid; /* cpuid bit set for replacement (top bit is polarity) */ - uint8_t orig_len; /* length of original instruction */ - uint8_t repl_len; /* length of new instruction */ - uint8_t pad_len; /* length of build-time padding */ - diff --git a/xsa469-4.19-02.patch b/xsa469-4.19-02.patch deleted file mode 100644 index 5fd285f..0000000 --- a/xsa469-4.19-02.patch +++ /dev/null @@ -1,314 +0,0 @@ -From: Andrew Cooper -Subject: x86/guest: Remove use of the Xen hypercall_page - -In order to protect against ITS, Xen needs to start using return thunks. -Therefore the advice in XSA-466 becomes relevant, and the hypercall_page needs -to be removed. - -Implement early_hypercall(), with infrastructure to figure out the correct -instruction on first use. Use ALTERNATIVE()s to result in inline hypercalls, -including the ALT_NOT() form so we only need a single synthetic feature bit. - -No overall change. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/guest/xen/Makefile b/xen/arch/x86/guest/xen/Makefile -index 26fb4b1007c0..8b3250aa8886 100644 ---- a/xen/arch/x86/guest/xen/Makefile -+++ b/xen/arch/x86/guest/xen/Makefile -@@ -1,4 +1,4 @@ --obj-y += hypercall_page.o -+obj-bin-y += hypercall.init.o - obj-y += xen.o - - obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o -diff --git a/xen/arch/x86/guest/xen/hypercall.S b/xen/arch/x86/guest/xen/hypercall.S -new file mode 100644 -index 000000000000..05e429794cc4 ---- /dev/null -+++ b/xen/arch/x86/guest/xen/hypercall.S -@@ -0,0 +1,50 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+ -+#include -+ -+ .section .init.text, "ax", @progbits -+ -+ /* -+ * Used during early boot, before alternatives have run and inlined -+ * the appropriate instruction. Called using the hypercall ABI. -+ */ -+FUNC(early_hypercall) -+ cmpb $0, early_hypercall_insn(%rip) -+ jl .L_setup -+ je 1f -+ -+ vmmcall -+ ret -+ -+1: vmcall -+ ret -+ -+.L_setup: -+ /* -+ * When setting up the first time around, all registers need -+ * preserving. Save the non-callee-saved ones. -+ */ -+ push %r11 -+ push %r10 -+ push %r9 -+ push %r8 -+ push %rdi -+ push %rsi -+ push %rdx -+ push %rcx -+ push %rax -+ -+ call early_hypercall_setup -+ -+ pop %rax -+ pop %rcx -+ pop %rdx -+ pop %rsi -+ pop %rdi -+ pop %r8 -+ pop %r9 -+ pop %r10 -+ pop %r11 -+ -+ jmp early_hypercall -+END(early_hypercall) -diff --git a/xen/arch/x86/guest/xen/hypercall_page.S b/xen/arch/x86/guest/xen/hypercall_page.S -deleted file mode 100644 -index 7ab55fc1f6e6..000000000000 ---- a/xen/arch/x86/guest/xen/hypercall_page.S -+++ /dev/null -@@ -1,76 +0,0 @@ --#include --#include --#include -- -- .section ".text.page_aligned", "ax", @progbits -- --DATA(hypercall_page, PAGE_SIZE) -- /* Poisoned with `ret` for safety before hypercalls are set up. */ -- .fill PAGE_SIZE, 1, 0xc3 --END(hypercall_page) -- --/* -- * Identify a specific hypercall in the hypercall page -- * @param name Hypercall name. -- */ --#define DECLARE_HYPERCALL(name) \ -- .globl HYPERCALL_ ## name; \ -- .type HYPERCALL_ ## name, STT_FUNC; \ -- .size HYPERCALL_ ## name, 32; \ -- .set HYPERCALL_ ## name, hypercall_page + __HYPERVISOR_ ## name * 32 -- --DECLARE_HYPERCALL(set_trap_table) --DECLARE_HYPERCALL(mmu_update) --DECLARE_HYPERCALL(set_gdt) --DECLARE_HYPERCALL(stack_switch) --DECLARE_HYPERCALL(set_callbacks) --DECLARE_HYPERCALL(fpu_taskswitch) --DECLARE_HYPERCALL(sched_op_compat) --DECLARE_HYPERCALL(platform_op) --DECLARE_HYPERCALL(set_debugreg) --DECLARE_HYPERCALL(get_debugreg) --DECLARE_HYPERCALL(update_descriptor) --DECLARE_HYPERCALL(memory_op) --DECLARE_HYPERCALL(multicall) --DECLARE_HYPERCALL(update_va_mapping) --DECLARE_HYPERCALL(set_timer_op) --DECLARE_HYPERCALL(event_channel_op_compat) --DECLARE_HYPERCALL(xen_version) --DECLARE_HYPERCALL(console_io) --DECLARE_HYPERCALL(physdev_op_compat) --DECLARE_HYPERCALL(grant_table_op) --DECLARE_HYPERCALL(vm_assist) --DECLARE_HYPERCALL(update_va_mapping_otherdomain) --DECLARE_HYPERCALL(iret) --DECLARE_HYPERCALL(vcpu_op) --DECLARE_HYPERCALL(set_segment_base) --DECLARE_HYPERCALL(mmuext_op) --DECLARE_HYPERCALL(xsm_op) --DECLARE_HYPERCALL(nmi_op) --DECLARE_HYPERCALL(sched_op) --DECLARE_HYPERCALL(callback_op) --DECLARE_HYPERCALL(xenoprof_op) --DECLARE_HYPERCALL(event_channel_op) --DECLARE_HYPERCALL(physdev_op) --DECLARE_HYPERCALL(hvm_op) --DECLARE_HYPERCALL(sysctl) --DECLARE_HYPERCALL(domctl) --DECLARE_HYPERCALL(kexec_op) --DECLARE_HYPERCALL(argo_op) --DECLARE_HYPERCALL(xenpmu_op) -- --DECLARE_HYPERCALL(arch_0) --DECLARE_HYPERCALL(arch_1) --DECLARE_HYPERCALL(arch_2) --DECLARE_HYPERCALL(arch_3) --DECLARE_HYPERCALL(arch_4) --DECLARE_HYPERCALL(arch_5) --DECLARE_HYPERCALL(arch_6) --DECLARE_HYPERCALL(arch_7) -- --/* -- * Local variables: -- * tab-width: 8 -- * indent-tabs-mode: nil -- * End: -- */ -diff --git a/xen/arch/x86/guest/xen/xen.c b/xen/arch/x86/guest/xen/xen.c -index 7484b3f73ad3..2c30db05dfa7 100644 ---- a/xen/arch/x86/guest/xen/xen.c -+++ b/xen/arch/x86/guest/xen/xen.c -@@ -26,7 +26,6 @@ - bool __read_mostly xen_guest; - - uint32_t __read_mostly xen_cpuid_base; --extern char hypercall_page[]; - static struct rangeset *mem; - - DEFINE_PER_CPU(unsigned int, vcpu_id); -@@ -35,6 +34,50 @@ static struct vcpu_info *vcpu_info; - static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)]; - DEFINE_PER_CPU(struct vcpu_info *, vcpu_info); - -+/* -+ * Which instruction to use for early hypercalls: -+ * < 0 setup -+ * 0 vmcall -+ * > 0 vmmcall -+ */ -+int8_t __initdata early_hypercall_insn = -1; -+ -+/* -+ * Called once during the first hypercall to figure out which instruction to -+ * use. Error handling options are limited. -+ */ -+void asmlinkage __init early_hypercall_setup(void) -+{ -+ BUG_ON(early_hypercall_insn != -1); -+ -+ if ( !boot_cpu_data.x86_vendor ) -+ { -+ unsigned int eax, ebx, ecx, edx; -+ -+ cpuid(0, &eax, &ebx, &ecx, &edx); -+ -+ boot_cpu_data.x86_vendor = x86_cpuid_lookup_vendor(ebx, ecx, edx); -+ } -+ -+ switch ( boot_cpu_data.x86_vendor ) -+ { -+ case X86_VENDOR_INTEL: -+ case X86_VENDOR_CENTAUR: -+ case X86_VENDOR_SHANGHAI: -+ early_hypercall_insn = 0; -+ setup_force_cpu_cap(X86_FEATURE_USE_VMCALL); -+ break; -+ -+ case X86_VENDOR_AMD: -+ case X86_VENDOR_HYGON: -+ early_hypercall_insn = 1; -+ break; -+ -+ default: -+ BUG(); -+ } -+} -+ - static void __init find_xen_leaves(void) - { - uint32_t eax, ebx, ecx, edx, base; -@@ -337,9 +380,6 @@ const struct hypervisor_ops *__init xg_probe(void) - if ( !xen_cpuid_base ) - return NULL; - -- /* Fill the hypercall page. */ -- wrmsrl(cpuid_ebx(xen_cpuid_base + 2), __pa(hypercall_page)); -- - xen_guest = true; - - return &ops; -diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h -index ba3df174b76e..9e3ed21c026d 100644 ---- a/xen/arch/x86/include/asm/cpufeatures.h -+++ b/xen/arch/x86/include/asm/cpufeatures.h -@@ -42,6 +42,7 @@ XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks * - XEN_CPUFEATURE(XEN_IBT, X86_SYNTH(27)) /* Xen uses CET Indirect Branch Tracking */ - XEN_CPUFEATURE(IBPB_ENTRY_PV, X86_SYNTH(28)) /* MSR_PRED_CMD used by Xen for PV */ - XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for HVM */ -+XEN_CPUFEATURE(USE_VMCALL, X86_SYNTH(30)) /* Use VMCALL instead of VMMCALL */ - - /* Bug words follow the synthetic words. */ - #define X86_NR_BUG 1 -diff --git a/xen/arch/x86/include/asm/guest/xen-hcall.h b/xen/arch/x86/include/asm/guest/xen-hcall.h -index 665b472d05ac..96004dec9909 100644 ---- a/xen/arch/x86/include/asm/guest/xen-hcall.h -+++ b/xen/arch/x86/include/asm/guest/xen-hcall.h -@@ -30,9 +30,11 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__) ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)) \ - : "memory" ); \ - (type)res; \ -@@ -42,10 +44,12 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__) \ - ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)) \ - : "memory" ); \ - (type)res; \ -@@ -55,10 +59,12 @@ - ({ \ - long res, tmp__; \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__) \ - ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)) \ - : "memory" ); \ - (type)res; \ -@@ -69,10 +75,12 @@ - long res, tmp__; \ - register long _a4 asm ("r10") = ((long)(a4)); \ - asm volatile ( \ -- "call hypercall_page + %c[offset]" \ -+ ALTERNATIVE_2("call early_hypercall", \ -+ "vmmcall", ALT_NOT(X86_FEATURE_USE_VMCALL), \ -+ "vmcall", X86_FEATURE_USE_VMCALL) \ - : "=a" (res), "=D" (tmp__), "=S" (tmp__), "=d" (tmp__), \ - "=&r" (tmp__) ASM_CALL_CONSTRAINT \ -- : [offset] "i" (hcall * 32), \ -+ : "0" (hcall), \ - "1" ((long)(a1)), "2" ((long)(a2)), "3" ((long)(a3)), \ - "4" (_a4) \ - : "memory" ); \ diff --git a/xsa469-4.19-03.patch b/xsa469-4.19-03.patch deleted file mode 100644 index 2e944f9..0000000 --- a/xsa469-4.19-03.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Jan Beulich -Subject: x86/thunk: (Mis)align __x86_indirect_thunk_* to mitigate ITS - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -Arrange for __x86_indirect_thunk_* to always be in the second half. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Jan Beulich -Signed-off-by: Andrew Cooper -Reviewed-by: Jan Beulich - -diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S -index fd5493c22b16..c4b978d67b8e 100644 ---- a/xen/arch/x86/indirect-thunk.S -+++ b/xen/arch/x86/indirect-thunk.S -@@ -11,6 +11,10 @@ - - #include - -+/* Alignment is dealt with explicitly here; override the respective macro. */ -+#undef SYM_ALIGN -+#define SYM_ALIGN(align...) -+ - .macro IND_THUNK_RETPOLINE reg:req - call 1f - int3 -@@ -35,6 +39,16 @@ - .macro GEN_INDIRECT_THUNK reg:req - .section .text.__x86_indirect_thunk_\reg, "ax", @progbits - -+ /* -+ * The Indirect Target Selection speculative vulnerability means that -+ * indirect branches (including RETs) are unsafe when in the first -+ * half of a cacheline. Arrange for them to be in the second half. -+ * -+ * Align to 64, then skip 32. -+ */ -+ .balign 64 -+ .fill 32, 1, 0xcc -+ - FUNC(__x86_indirect_thunk_\reg) - ALTERNATIVE_2 __stringify(IND_THUNK_RETPOLINE \reg), \ - __stringify(IND_THUNK_LFENCE \reg), X86_FEATURE_IND_THUNK_LFENCE, \ diff --git a/xsa469-4.19-04.patch b/xsa469-4.19-04.patch deleted file mode 100644 index 81d77a9..0000000 --- a/xsa469-4.19-04.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Andrew Cooper -Subject: x86/thunk: (Mis)align the RETs in clear_bhb_loops() to mitigate ITS - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -clear_bhb_loops() has a precise layout of branches. The alignment for -performance cause the RETs to always be in an unsafe position, and converting -those to return thunks changes the branching pattern. While such a conversion -is believed to be safe, clear_bhb_loops() is also a performance-relevant -fastpath, so (mis)align the RETs to be in a safe position. - -No functional change. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S -index 678c00c5d06f..52625f4e2c17 100644 ---- a/xen/arch/x86/bhb-thunk.S -+++ b/xen/arch/x86/bhb-thunk.S -@@ -50,7 +50,12 @@ END(clear_bhb_tsx) - * ret - * - * The CALL/RETs are necessary to prevent the Loop Stream Detector from -- * interfering. The alignment is for performance and not safety. -+ * interfering. -+ * -+ * The .balign's are for performance, but they cause the RETs to be in unsafe -+ * positions with respect to Indirect Target Selection. The .skips are to -+ * move the RETs into ITS-safe positions, rather than using the slowpath -+ * through __x86_return_thunk. - * - * The "short" sequence (5 and 5) is for CPUs prior to Alder Lake / Sapphire - * Rapids (i.e. Cores prior to Golden Cove and/or Gracemont). -@@ -66,12 +71,14 @@ FUNC(clear_bhb_loops) - jmp 5f - int3 - -- .align 64 -+ .balign 64 -+ .skip 32 - (.Lr1 - 1f), 0xcc - 1: call 2f -- ret -+.Lr1: ret - int3 - -- .align 64 -+ .balign 64 -+ .skip 32 - 18 /* (.Lr2 - 2f) but Clang IAS doesn't like this */, 0xcc - 2: ALTERNATIVE "mov $5, %eax", "mov $7, %eax", X86_SPEC_BHB_LOOPS_LONG - - 3: jmp 4f -@@ -83,7 +90,7 @@ FUNC(clear_bhb_loops) - sub $1, %ecx - jnz 1b - -- ret -+.Lr2: ret - 5: - /* - * The Intel sequence has an LFENCE here. The purpose is to ensure diff --git a/xsa469-4.19-05.patch b/xsa469-4.19-05.patch deleted file mode 100644 index 51a135d..0000000 --- a/xsa469-4.19-05.patch +++ /dev/null @@ -1,506 +0,0 @@ -From: Andrew Cooper -Subject: 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 -Reviewed-by: Roger Pau Monné - -diff --git a/tools/tests/x86_emulator/x86-emulate.h b/tools/tests/x86_emulator/x86-emulate.h -index 8f8accfe3e70..946aaa9d660b 100644 ---- a/tools/tests/x86_emulator/x86-emulate.h -+++ b/tools/tests/x86_emulator/x86-emulate.h -@@ -68,6 +68,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 c1e64278ce85..a7e5a82689de 100644 ---- a/xen/arch/x86/Makefile -+++ b/xen/arch/x86/Makefile -@@ -11,9 +11,7 @@ obj-$(CONFIG_PV) += pv/ - obj-y += x86_64/ - obj-y += x86_emulate/ - --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 -@@ -41,7 +39,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 88c90044c20d..ec451d962c10 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -137,6 +137,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 705cf9eb94ca..1572efa69a00 100644 ---- a/xen/arch/x86/extable.c -+++ b/xen/arch/x86/extable.c -@@ -151,20 +151,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 = X86_EXC_UD }, -- { .opc = { endbr64, 0x90, 0x02, 0x00, 0xc3 }, /* nop; add (%rax),%al */ -+ { .opc = { endbr64, 0x90, 0x02, 0x00 }, /* nop; add (%rax),%al */ - .rax = 0x0123456789abcdef, - .res.fields.trapnr = X86_EXC_GP }, -- { .opc = { endbr64, 0x02, 0x04, 0x04, 0xc3 }, /* add (%rsp,%rax),%al */ -+ { .opc = { endbr64, 0x02, 0x04, 0x04 }, /* add (%rsp,%rax),%al */ - .rax = 0xfedcba9876543210UL, - .res.fields.trapnr = X86_EXC_SS }, -- { .opc = { endbr64, 0xcc, 0xc3, 0xc3, 0xc3 }, /* int3 */ -+ { .opc = { endbr64, 0xcc, 0x90, 0x90 }, /* int3 */ - .res.fields.trapnr = X86_EXC_BP }, - #undef endbr64 - }; -@@ -183,6 +183,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 89b7bdcb82e5..841a63ebf1b6 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 int 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 70150c272276..ff5d1c9f8634 100644 ---- a/xen/arch/x86/pv/emul-priv-op.c -+++ b/xen/arch/x86/pv/emul-priv-op.c -@@ -76,7 +76,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); -@@ -126,11 +125,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/fpu.c b/xen/arch/x86/x86_emulate/fpu.c -index 480d87965705..03612d00a2ce 100644 ---- a/xen/arch/x86/x86_emulate/fpu.c -+++ b/xen/arch/x86/x86_emulate/fpu.c -@@ -32,36 +32,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_) \ -diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c -index b1d192cbbf1e..f40709682484 100644 ---- a/xen/arch/x86/x86_emulate/x86_emulate.c -+++ b/xen/arch/x86/x86_emulate/x86_emulate.c -@@ -1396,7 +1396,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)); - -@@ -3627,7 +3627,7 @@ x86_emulate( - } - 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)); -@@ -3694,7 +3694,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)); -@@ -3768,7 +3768,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("", -@@ -4004,7 +4004,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, X86_EXC_UD); - -@@ -4401,7 +4401,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)); -@@ -4438,7 +4438,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)); -@@ -4633,7 +4633,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) ); -@@ -4967,7 +4967,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); -@@ -5010,7 +5010,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)); -@@ -5040,7 +5040,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; -@@ -5608,7 +5608,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)); -@@ -5726,7 +5726,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. */ -@@ -6006,7 +6006,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); -@@ -6290,7 +6290,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)); -@@ -6389,7 +6389,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)); - -@@ -6459,7 +6459,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)); - -@@ -6515,7 +6515,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)); - -@@ -6580,7 +6580,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)); - -@@ -6594,7 +6594,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); -@@ -6688,7 +6688,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)); - -@@ -6766,7 +6766,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); -@@ -6848,7 +6848,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); -@@ -7058,7 +7058,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)); -@@ -7094,7 +7094,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)); -@@ -7335,7 +7335,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. */ -@@ -7502,7 +7502,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]", "", -@@ -7748,7 +7748,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. */ -@@ -8094,7 +8094,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)); -@@ -8203,7 +8203,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)); - -@@ -8293,12 +8293,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); - } - diff --git a/xsa469-4.19-06.patch b/xsa469-4.19-06.patch deleted file mode 100644 index 724790e..0000000 --- a/xsa469-4.19-06.patch +++ /dev/null @@ -1,375 +0,0 @@ -From: Jan Beulich -Subject: x86/thunk: Build Xen with Return Thunks - -The Indirect Target Selection speculative vulnerability means that indirect -branches (including RETs) are unsafe when in the first half of a cacheline. - -In order to mitigate this, build with return thunks and arrange for -__x86_return_thunk to be (mis)aligned in the same manner as -__x86_indirect_thunk_* so the RET instruction is placed in a safe location. - -place_ret() needs to conditionally emit JMP __x86_return_thunk instead of RET. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Jan Beulich -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig -index 7e03e4bc5546..4542ea8408c7 100644 ---- a/xen/arch/x86/Kconfig -+++ b/xen/arch/x86/Kconfig -@@ -37,9 +37,14 @@ config ARCH_DEFCONFIG - default "arch/x86/configs/x86_64_defconfig" - - config CC_HAS_INDIRECT_THUNK -+ # GCC >= 8 or Clang >= 6 - def_bool $(cc-option,-mindirect-branch-register) || \ - $(cc-option,-mretpoline-external-thunk) - -+config CC_HAS_RETURN_THUNK -+ # GCC >= 8 or Clang >= 15 -+ def_bool $(cc-option,-mfunction-return=thunk-extern) -+ - config HAS_AS_CET_SS - # binutils >= 2.29 or LLVM >= 6 - def_bool $(as-instr,wrssq %rax$(comma)0;setssbsy) -diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile -index a7e5a82689de..27806a81aca8 100644 ---- a/xen/arch/x86/Makefile -+++ b/xen/arch/x86/Makefile -@@ -43,6 +43,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o - obj-y += msi.o - obj-y += msr.o - obj-$(CONFIG_INDIRECT_THUNK) += indirect-thunk.o -+obj-$(CONFIG_RETURN_THUNK) += indirect-thunk.o - obj-$(CONFIG_PV) += ioport_emulate.o - obj-y += irq.o - obj-$(CONFIG_KEXEC) += machine_kexec.o -diff --git a/xen/arch/x86/acpi/wakeup_prot.S b/xen/arch/x86/acpi/wakeup_prot.S -index 66f799339913..97bd676aaee2 100644 ---- a/xen/arch/x86/acpi/wakeup_prot.S -+++ b/xen/arch/x86/acpi/wakeup_prot.S -@@ -133,7 +133,7 @@ ENTRY(s3_resume) - pop %r12 - pop %rbx - pop %rbp -- ret -+ RET - - .data - .align 16 -diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c -index ec451d962c10..1b71ae959abe 100644 ---- a/xen/arch/x86/alternative.c -+++ b/xen/arch/x86/alternative.c -@@ -137,16 +137,45 @@ void init_or_livepatch add_nops(void *insns, unsigned int len) - } - } - -+void nocall __x86_return_thunk(void); -+ - /* - * Place a return at @ptr. @ptr must be in the writable alias of a stub. - * -+ * When CONFIG_RETURN_THUNK is active, this may be a JMP __x86_return_thunk -+ * instead, depending on the safety of @ptr with respect to Indirect Target -+ * Selection. -+ * - * Returns the next position to write into the stub. - */ - void *place_ret(void *ptr) - { -+ unsigned long addr = (unsigned long)ptr; - uint8_t *p = ptr; - -- *p++ = 0xc3; -+ /* -+ * When Return Thunks are used, if a RET would be unsafe at this location -+ * with respect to Indirect Target Selection (i.e. if addr is in the first -+ * half of a cacheline), insert a JMP __x86_return_thunk instead. -+ * -+ * The displacement needs to be relative to the executable alias of the -+ * stub, not to @ptr which is the writeable alias. -+ */ -+ if ( IS_ENABLED(CONFIG_RETURN_THUNK) && !(addr & 0x20) ) -+ { -+ long stub_va = (this_cpu(stubs.addr) & PAGE_MASK) + (addr & ~PAGE_MASK); -+ long disp = (long)__x86_return_thunk - (stub_va + 5); -+ -+ BUG_ON((int32_t)disp != disp); -+ -+ *p++ = 0xe9; -+ *(int32_t *)p = disp; -+ p += 4; -+ } -+ else -+ { -+ *p++ = 0xc3; -+ } - - return p; - } -diff --git a/xen/arch/x86/arch.mk b/xen/arch/x86/arch.mk -index b88d097a844b..85d3e7cbfeeb 100644 ---- a/xen/arch/x86/arch.mk -+++ b/xen/arch/x86/arch.mk -@@ -46,6 +46,9 @@ CFLAGS-$(CONFIG_CC_IS_GCC) += -fno-jump-tables - CFLAGS-$(CONFIG_CC_IS_CLANG) += -mretpoline-external-thunk - endif - -+# Compile with return thunk support if selected. -+CFLAGS-$(CONFIG_RETURN_THUNK) += -mfunction-return=thunk-extern -+ - # Disable the addition of a .note.gnu.property section to object files when - # livepatch support is enabled. The contents of that section can change - # depending on the instructions used, and livepatch-build-tools doesn't know -diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S -index 52625f4e2c17..7f92201a3cbb 100644 ---- a/xen/arch/x86/bhb-thunk.S -+++ b/xen/arch/x86/bhb-thunk.S -@@ -23,7 +23,7 @@ FUNC(clear_bhb_tsx) - 0: .byte 0xc6, 0xf8, 0 /* xabort $0 */ - int3 - 1: -- ret -+ RET - END(clear_bhb_tsx) - - /* -diff --git a/xen/arch/x86/clear_page.S b/xen/arch/x86/clear_page.S -index d6c076f1d8bc..dc3c3c26bfb7 100644 ---- a/xen/arch/x86/clear_page.S -+++ b/xen/arch/x86/clear_page.S -@@ -1,6 +1,8 @@ - .file __FILE__ - - #include -+ -+#include - #include - - FUNC(clear_page_sse2) -@@ -16,5 +18,5 @@ FUNC(clear_page_sse2) - jnz 0b - - sfence -- ret -+ RET - END(clear_page_sse2) -diff --git a/xen/arch/x86/copy_page.S b/xen/arch/x86/copy_page.S -index c3c436545bac..e43e5370c815 100644 ---- a/xen/arch/x86/copy_page.S -+++ b/xen/arch/x86/copy_page.S -@@ -1,6 +1,8 @@ - .file __FILE__ - - #include -+ -+#include - #include - - #define src_reg %rsi -@@ -41,5 +43,5 @@ FUNC(copy_page_sse2) - movnti tmp4_reg, 3*WORD_SIZE(dst_reg) - - sfence -- ret -+ RET - END(copy_page_sse2) -diff --git a/xen/arch/x86/efi/check.c b/xen/arch/x86/efi/check.c -index 9e473faad3c9..23ba30abf330 100644 ---- a/xen/arch/x86/efi/check.c -+++ b/xen/arch/x86/efi/check.c -@@ -3,6 +3,9 @@ int __attribute__((__ms_abi__)) test(int i) - return i; - } - -+/* In case -mfunction-return is in use. */ -+void __x86_return_thunk(void) {}; -+ - /* - * Populate an array with "addresses" of relocatable and absolute values. - * This is to probe ld for (a) emitting base relocations at all and (b) not -diff --git a/xen/arch/x86/include/asm/asm-defns.h b/xen/arch/x86/include/asm/asm-defns.h -index 32d6b4491063..97ebe21298a2 100644 ---- a/xen/arch/x86/include/asm/asm-defns.h -+++ b/xen/arch/x86/include/asm/asm-defns.h -@@ -58,6 +58,12 @@ - .endif - .endm - -+#ifdef CONFIG_RETURN_THUNK -+# define RET jmp __x86_return_thunk -+#else -+# define RET ret -+#endif -+ - #ifdef CONFIG_XEN_IBT - # define ENDBR64 endbr64 - #else -diff --git a/xen/arch/x86/indirect-thunk.S b/xen/arch/x86/indirect-thunk.S -index c4b978d67b8e..26dad15f12c9 100644 ---- a/xen/arch/x86/indirect-thunk.S -+++ b/xen/arch/x86/indirect-thunk.S -@@ -15,6 +15,8 @@ - #undef SYM_ALIGN - #define SYM_ALIGN(align...) - -+#ifdef CONFIG_INDIRECT_THUNK -+ - .macro IND_THUNK_RETPOLINE reg:req - call 1f - int3 -@@ -62,3 +64,25 @@ END(__x86_indirect_thunk_\reg) - .irp reg, ax, cx, dx, bx, bp, si, di, 8, 9, 10, 11, 12, 13, 14, 15 - GEN_INDIRECT_THUNK reg=r\reg - .endr -+ -+#endif /* CONFIG_INDIRECT_THUNK */ -+ -+#ifdef CONFIG_RETURN_THUNK -+ .section .text.entry.__x86_return_thunk, "ax", @progbits -+ -+ /* -+ * The Indirect Target Selection speculative vulnerability means that -+ * indirect branches (including RETs) are unsafe when in the first -+ * half of a cacheline. Arrange for them to be in the second half. -+ * -+ * Align to 64, then skip 32. -+ */ -+ .balign 64 -+ .fill 32, 1, 0xcc -+ -+FUNC(__x86_return_thunk) -+ ret -+ int3 /* Halt straight-line speculation */ -+END(__x86_return_thunk) -+ -+#endif /* CONFIG_RETURN_THUNK */ -diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c -index ff5d1c9f8634..295d847ea24c 100644 ---- a/xen/arch/x86/pv/emul-priv-op.c -+++ b/xen/arch/x86/pv/emul-priv-op.c -@@ -131,7 +131,7 @@ static io_emul_stub_t *io_emul_stub_setup(struct priv_op_ctxt *ctxt, u8 opcode, - BUILD_BUG_ON(STUB_BUF_SIZE / 2 < - (sizeof(prologue) + sizeof(epilogue) + 10 /* 2x call */ + - MAX(3 /* default stub */, IOEMUL_QUIRK_STUB_BYTES) + -- 1 /* ret */)); -+ (IS_ENABLED(CONFIG_RETURN_THUNK) ? 5 : 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/pv/gpr_switch.S b/xen/arch/x86/pv/gpr_switch.S -index 5409ad3b1447..362b5d241623 100644 ---- a/xen/arch/x86/pv/gpr_switch.S -+++ b/xen/arch/x86/pv/gpr_switch.S -@@ -26,7 +26,7 @@ FUNC(load_guest_gprs) - movq UREGS_r15(%rdi), %r15 - movq UREGS_rcx(%rdi), %rcx - movq UREGS_rdi(%rdi), %rdi -- ret -+ RET - END(load_guest_gprs) - - /* Save guest GPRs. Parameter on the stack above the return address. */ -@@ -48,5 +48,5 @@ FUNC(save_guest_gprs) - movq %rbx, UREGS_rbx(%rdi) - movq %rdx, UREGS_rdx(%rdi) - movq %rcx, UREGS_rcx(%rdi) -- ret -+ RET - END(save_guest_gprs) -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 35351044f901..019a0a81f4a7 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -569,6 +569,9 @@ static void __init print_details(enum ind_thunk thunk) - #ifdef CONFIG_INDIRECT_THUNK - " INDIRECT_THUNK" - #endif -+#ifdef CONFIG_RETURN_THUNK -+ " RETURN_THUNK" -+#endif - #ifdef CONFIG_SHADOW_PAGING - " SHADOW_PAGING" - #endif -diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S -index a99646c0cd4e..18f46c78cfbe 100644 ---- a/xen/arch/x86/x86_64/compat/entry.S -+++ b/xen/arch/x86/x86_64/compat/entry.S -@@ -180,7 +180,7 @@ FUNC(cr4_pv32_restore) - or cr4_pv32_mask(%rip), %rax - mov %rax, %cr4 - mov %rax, (%rcx) -- ret -+ RET - 0: - #ifndef NDEBUG - /* Check that _all_ of the bits intended to be set actually are. */ -@@ -198,7 +198,7 @@ FUNC(cr4_pv32_restore) - 1: - #endif - xor %eax, %eax -- ret -+ RET - END(cr4_pv32_restore) - - FUNC(compat_syscall) -@@ -329,7 +329,7 @@ __UNLIKELY_END(compat_bounce_null_selector) - xor %eax, %eax - mov %ax, TRAPBOUNCE_cs(%rdx) - mov %al, TRAPBOUNCE_flags(%rdx) -- ret -+ RET - - .section .fixup,"ax" - .Lfx13: -diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S -index 9b0cdb76408b..eb62e7c329bd 100644 ---- a/xen/arch/x86/x86_64/entry.S -+++ b/xen/arch/x86/x86_64/entry.S -@@ -604,7 +604,7 @@ __UNLIKELY_END(create_bounce_frame_bad_bounce_ip) - xor %eax, %eax - mov %rax, TRAPBOUNCE_eip(%rdx) - mov %al, TRAPBOUNCE_flags(%rdx) -- ret -+ RET - - .pushsection .fixup, "ax", @progbits - # Numeric tags below represent the intended overall %rsi adjustment. -diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S -index 9a1dfe1b340a..506993867502 100644 ---- a/xen/arch/x86/xen.lds.S -+++ b/xen/arch/x86/xen.lds.S -@@ -82,6 +82,7 @@ SECTIONS - . = ALIGN(PAGE_SIZE); - _stextentry = .; - *(.text.entry) -+ *(.text.entry.*) - . = ALIGN(PAGE_SIZE); - _etextentry = .; - -diff --git a/xen/common/Kconfig b/xen/common/Kconfig -index 565ceda741b9..da0fa7527643 100644 ---- a/xen/common/Kconfig -+++ b/xen/common/Kconfig -@@ -130,6 +130,17 @@ config INDIRECT_THUNK - When enabled, indirect branches are implemented using a new construct - called "retpoline" that prevents speculation. - -+config RETURN_THUNK -+ bool "Out-of-line Returns" -+ depends on CC_HAS_RETURN_THUNK -+ default INDIRECT_THUNK -+ help -+ Compile Xen with out-of-line returns. -+ -+ This allows Xen to mitigate a variety of speculative vulnerabilities -+ by choosing a hardware-dependent instruction sequence to implement -+ function returns safely. -+ - config SPECULATIVE_HARDEN_ARRAY - bool "Speculative Array Hardening" - default y diff --git a/xsa469-4.19-07.patch b/xsa469-4.19-07.patch deleted file mode 100644 index 2ba9d48..0000000 --- a/xsa469-4.19-07.patch +++ /dev/null @@ -1,154 +0,0 @@ -From: Andrew Cooper -Subject: x86/spec-ctrl: Synthesise ITS_NO to guests on unaffected hardware - -It is easier to express feature word 17 in terms of word 16 + [32, 64) as -that's how the layout is given in documentation. - -This is part of XSA-469 / CVE-2024-28956 - -Signed-off-by: Andrew Cooper -Reviewed-by: Roger Pau Monné - -diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h -index 9bc553681f4a..1729ba0c3097 100644 ---- a/xen/arch/x86/include/asm/cpufeature.h -+++ b/xen/arch/x86/include/asm/cpufeature.h -@@ -216,6 +216,7 @@ static inline bool boot_cpu_has(unsigned int feat) - #define cpu_has_gds_no boot_cpu_has(X86_FEATURE_GDS_NO) - #define cpu_has_rfds_no boot_cpu_has(X86_FEATURE_RFDS_NO) - #define cpu_has_rfds_clear boot_cpu_has(X86_FEATURE_RFDS_CLEAR) -+#define cpu_has_its_no boot_cpu_has(X86_FEATURE_ITS_NO) - - /* Synthesized. */ - #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) -diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c -index 019a0a81f4a7..94cdbd521c4d 100644 ---- a/xen/arch/x86/spec_ctrl.c -+++ b/xen/arch/x86/spec_ctrl.c -@@ -1781,6 +1781,90 @@ static void __init bhi_calculations(void) - } - } - -+/* -+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/indirect-target-selection.html -+ */ -+static void __init its_calculations(void) -+{ -+ /* -+ * Indirect Target Selection is a Branch Prediction bug whereby certain -+ * indirect branches (including RETs) get predicted using a direct branch -+ * target, rather than a suitable indirect target, bypassing hardware -+ * isolation protections. -+ * -+ * ITS affects Core (but not Atom) processors starting from the -+ * introduction of eIBRS, up to but not including Golden Cove cores -+ * (checked here with BHI_CTRL). -+ * -+ * The ITS_NO feature is not expected to be enumerated by hardware, and is -+ * only for VMMs to synthesise for guests. -+ * -+ * ITS comes in 3 flavours: -+ * -+ * 1) Across-IBPB. Indirect branches after the IBPB can be controlled -+ * by direct targets which existed prior to the IBPB. This is -+ * addressed in the IPU 2025.1 microcode drop, and has no other -+ * software interaction. -+ * -+ * 2) Guest/Host. Indirect branches in the VMM can be controlled by -+ * direct targets from the guest. This applies equally to PV guests -+ * (Ring3) and HVM guests (VMX), and applies to all Skylake-uarch -+ * cores with eIBRS. -+ * -+ * 3) Intra-mode. Indirect branches in the VMM can be controlled by -+ * other execution in the same mode. -+ */ -+ -+ /* -+ * If we can see ITS_NO, or we're virtualised, do nothing. We are or may -+ * migrate somewhere unsafe. -+ */ -+ if ( cpu_has_its_no || cpu_has_hypervisor ) -+ return; -+ -+ /* ITS is only known to affect Intel processors at this time. */ -+ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ) -+ return; -+ -+ /* -+ * ITS does not exist on: -+ * - non-Family 6 CPUs -+ * - those without eIBRS -+ * - those with BHI_CTRL -+ * but we still need to synthesise ITS_NO. -+ */ -+ if ( boot_cpu_data.x86 != 6 || !cpu_has_eibrs || -+ boot_cpu_has(X86_FEATURE_BHI_CTRL) ) -+ goto synthesise; -+ -+ switch ( boot_cpu_data.x86_model ) -+ { -+ /* These Skylake-uarch cores suffer cases #2 and #3. */ -+ case INTEL_FAM6_SKYLAKE_X: -+ case INTEL_FAM6_KABYLAKE_L: -+ case INTEL_FAM6_KABYLAKE: -+ case INTEL_FAM6_COMETLAKE: -+ case INTEL_FAM6_COMETLAKE_L: -+ return; -+ -+ /* These Sunny/Willow/Cypress Cove cores suffer case #3. */ -+ case INTEL_FAM6_ICELAKE_X: -+ case INTEL_FAM6_ICELAKE_D: -+ case INTEL_FAM6_ICELAKE_L: -+ case INTEL_FAM6_TIGERLAKE_L: -+ case INTEL_FAM6_TIGERLAKE: -+ case INTEL_FAM6_ROCKETLAKE: -+ return; -+ -+ default: -+ break; -+ } -+ -+ /* Platforms remaining are not believed to be vulnerable to ITS. */ -+ synthesise: -+ setup_force_cpu_cap(X86_FEATURE_ITS_NO); -+} -+ - void spec_ctrl_init_domain(struct domain *d) - { - bool pv = is_pv_domain(d); -@@ -2331,6 +2415,8 @@ void __init init_speculation_mitigations(void) - - bhi_calculations(); - -+ its_calculations(); -+ - print_details(thunk); - - /* -diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h -index 9c98e4992861..4d9e468af653 100644 ---- a/xen/include/public/arch-x86/cpufeatureset.h -+++ b/xen/include/public/arch-x86/cpufeatureset.h -@@ -365,7 +365,8 @@ XEN_CPUFEATURE(GDS_NO, 16*32+26) /*A No Gather Data Sampling */ - XEN_CPUFEATURE(RFDS_NO, 16*32+27) /*A No Register File Data Sampling */ - XEN_CPUFEATURE(RFDS_CLEAR, 16*32+28) /*!A| Register File(s) cleared by VERW */ - --/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */ -+/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 (express in terms of word 16) */ -+XEN_CPUFEATURE(ITS_NO, 16*32+62) /*!A No Indirect Target Selection */ - - #endif /* XEN_CPUFEATURE */ - -diff --git a/xen/tools/gen-cpuid.py b/xen/tools/gen-cpuid.py -index 601eec608983..dc33ca3181b1 100755 ---- a/xen/tools/gen-cpuid.py -+++ b/xen/tools/gen-cpuid.py -@@ -51,7 +51,7 @@ def parse_definitions(state): - r"\s+/\*([\w!|]*) .*$") - - word_regex = re.compile( -- r"^/\* .* word (\d*) \*/$") -+ r"^/\* .* word (\d*) .*\*/$") - last_word = -1 - - this = sys.modules[__name__] diff --git a/xsa483.patch b/xsa483.patch new file mode 100644 index 0000000..8ecb2e9 --- /dev/null +++ b/xsa483.patch @@ -0,0 +1,30 @@ +From: Andrii Sultanov +Subject: tools/oxenstored: Reset quota when resetting permissions + +The quota object contains both limits and the current node usage counts. + +When a domain is torn down, the node data itself is cleaned up but the node +usage counts are not. A later domain reusing the same domid can create fewer +nodes before being deemed to be over quota. + +Reset the count when the node permissions are cleaned up. + +This is XSA-483 / CVE-2026-23556. + +Signed-off-by: Andrii Sultanov +Signed-off-by: Andrew Cooper + +diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml +index 9b8dd2812df0..aa9204ead3ec 100644 +--- a/tools/ocaml/xenstored/store.ml ++++ b/tools/ocaml/xenstored/store.ml +@@ -465,7 +465,8 @@ let reset_permissions store domid = + if perms <> node.perms then + Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node); + Some { node with Node.perms } +- ) store.root ++ ) store.root; ++ store.quota <- Quota.del store.quota domid + + type ops = { + store: t; diff --git a/xsa484.patch b/xsa484.patch new file mode 100644 index 0000000..522549e --- /dev/null +++ b/xsa484.patch @@ -0,0 +1,89 @@ +From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Mon, 16 Mar 2026 15:06:11 +0100 +Subject: [PATCH] tools/xenstored: make conn_delete_all_transactions() + idempotent + +conn_delete_all_transactions() should be callable in any context, +resetting ALL transaction related data. + +This includes number of active transactions and the transaction +pointer in struct connection. + +So reset conn->trans to NULL in conn_delete_all_transactions() and +do the cleanup for each transaction in destroy_transaction(). + +This avoids triggering the assert() in conn_delete_all_transactions() +in case e.g. ignore_connection() was called while an operation inside +a transaction was performed, or XS_RESET_WATCHES was called in a +transaction. + +This is XSA-484 / CVE-2026-23557. + +Reported-by: Andrii Sultanov +Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions") +Signed-off-by: Juergen Gross +--- + tools/xenstored/transaction.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/tools/xenstored/transaction.c b/tools/xenstored/transaction.c +index 167cd597fd..0825c48859 100644 +--- a/tools/xenstored/transaction.c ++++ b/tools/xenstored/transaction.c +@@ -432,17 +432,23 @@ static int finalize_transaction(struct connection *conn, + static int destroy_transaction(void *_transaction) + { + struct transaction *trans = _transaction; ++ struct connection *conn = trans->conn; + struct accessed_node *i; + + wrl_ntransactions--; + trace_destroy(trans, "transaction"); + while ((i = list_top(&trans->accessed, struct accessed_node, list))) { + if (i->ta_node) +- db_delete(trans->conn, i->trans_name, NULL); ++ db_delete(conn, i->trans_name, NULL); + list_del(&i->list); + talloc_free(i); + } + ++ list_del(&trans->list); ++ domain_transaction_dec(conn); ++ if (list_empty(&conn->transaction_list)) ++ conn->ta_start_time = 0; ++ + return 0; + } + +@@ -523,10 +529,6 @@ int do_transaction_end(const void *ctx, struct connection *conn, + return ENOENT; + + conn->transaction = NULL; +- list_del(&trans->list); +- domain_transaction_dec(conn); +- if (list_empty(&conn->transaction_list)) +- conn->ta_start_time = 0; + + chk_quota = trans->node_created && domain_is_unprivileged(conn); + +@@ -572,14 +574,10 @@ void conn_delete_all_transactions(struct connection *conn) + struct transaction *trans; + + while ((trans = list_top(&conn->transaction_list, +- struct transaction, list))) { +- list_del(&trans->list); ++ struct transaction, list))) + talloc_free(trans); +- } +- +- assert(conn->transaction == NULL); + +- conn->ta_start_time = 0; ++ conn->transaction = NULL; + } + + int check_transactions(struct hashtable *hash) +-- +2.53.0 + diff --git a/xsa486.patch b/xsa486.patch new file mode 100644 index 0000000..654e957 --- /dev/null +++ b/xsa486.patch @@ -0,0 +1,181 @@ +From: Jan Beulich +Subject: gnttab: split gnttab_map_frame() + +If a domain tries to map status frames in parallel to switching grant +table version from 2 to 1, the mapping operation may put in place P2M +entries referencing MFNs which gnttab_unpopulate_status_frames() is in the +process of freeing. + +Ideally we would refcount pages when entered into P2M tables, but that's a +significant change. Extend the grant-table-locked region instead in +xenmem_add_to_physmap_one() (being the sole caller of gnttab_map_frame()), +such that a race with gnttab_unpopulate_status_frames() is no longer +possible. + +This is XSA-486 / CVE-2026-23558. + +Fixes: 5ce8fafa947c ("Dynamic grant-table sizing") +Fixes: a98dc13703e0 ("Introduce a grant_entry_v2 structure") +Reported-by: Rafal Wojtczuk +Signed-off-by: Jan Beulich +Reviewed-by: Roger Pau Monné + +--- a/xen/arch/arm/mm.c ++++ b/xen/arch/arm/mm.c +@@ -174,12 +174,10 @@ int xenmem_add_to_physmap_one( + switch ( space ) + { + case XENMAPSPACE_grant_table: +- rc = gnttab_map_frame(d, idx, gfn, &mfn); ++ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); + if ( rc ) + return rc; + +- /* Need to take care of the reference obtained in gnttab_map_frame(). */ +- page = mfn_to_page(mfn); + t = p2m_ram_rw; + + break; +@@ -281,10 +279,23 @@ int xenmem_add_to_physmap_one( + * to drop the reference we took earlier. In all other cases we need to + * drop any reference we took earlier (perhaps indirectly). + */ +- if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL ) ++ switch ( space ) + { ++ default: ++ if ( page ) ++ put_page(page); ++ break; ++ ++ case XENMAPSPACE_grant_table: ++ gnttab_map_frame_end(d, mfn); ++ break; ++ ++ case XENMAPSPACE_gmfn_foreign: ++ if ( !rc ) ++ break; + ASSERT(page != NULL); + put_page(page); ++ break; + } + + return rc; +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -2009,11 +2009,9 @@ int xenmem_add_to_physmap_one( + break; + + case XENMAPSPACE_grant_table: +- rc = gnttab_map_frame(d, idx, gfn, &mfn); ++ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn); + if ( rc ) + return rc; +- /* Need to take care of the reference obtained in gnttab_map_frame(). */ +- page = mfn_to_page(mfn); + break; + + case XENMAPSPACE_gmfn: +@@ -2095,19 +2093,28 @@ int xenmem_add_to_physmap_one( + put_gfn(d, gfn_x(gfn)); + + put_both: +- /* +- * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top. +- * We also may need to transfer ownership of the page reference to our +- * caller. +- */ +- if ( space == XENMAPSPACE_gmfn ) ++ switch ( space ) + { ++ case XENMAPSPACE_gmfn: ++ /* ++ * We took a ref of the gfn at the top. We also may need to transfer ++ * ownership of the page reference to our caller. ++ */ + put_gfn(d, gmfn); + if ( !rc && extra.ppage ) + { + *extra.ppage = page; + page = NULL; + } ++ break; ++ ++ case XENMAPSPACE_grant_table: ++ /* ++ * We (gnttab_map_frame_begin()) acquired a lock and took a ref of the ++ * page underlying the MFN at the top. ++ */ ++ gnttab_map_frame_end(d, mfn); ++ break; + } + + if ( page ) +--- a/xen/common/grant_table.c ++++ b/xen/common/grant_table.c +@@ -4250,7 +4250,8 @@ int gnttab_acquire_resource( + return rc; + } + +-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) ++int gnttab_map_frame_begin( ++ struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn) + { + int rc = 0; + struct grant_table *gt = d->grant_table; +@@ -4288,11 +4289,19 @@ int gnttab_map_frame(struct domain *d, u + put_page(pg); + } + +- grant_write_unlock(gt); ++ if ( rc ) ++ grant_write_unlock(d->grant_table); + + return rc; + } + ++void gnttab_map_frame_end(struct domain *d, mfn_t mfn) ++{ ++ put_page(mfn_to_page(mfn)); ++ ++ grant_write_unlock(d->grant_table); ++} ++ + static void gnttab_usage_print(struct domain *rd) + { + int first = 1; +--- a/xen/include/xen/grant_table.h ++++ b/xen/include/xen/grant_table.h +@@ -60,8 +60,13 @@ int gnttab_release_mappings(struct domai + int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref, + gfn_t *gfn, uint16_t *status); + +-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, +- mfn_t *mfn); ++/* ++ * These need to be used as a pair, as the first (in the success case) returns ++ * with a lock and page reference held which the second needs to drop. ++ */ ++int gnttab_map_frame_begin(struct domain *d, unsigned long idx, gfn_t gfn, ++ mfn_t *mfn); ++void gnttab_map_frame_end(struct domain *d, mfn_t mfn); + + unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id); + +@@ -100,12 +105,14 @@ static inline int mem_sharing_gref_to_gf + return -EINVAL; + } + +-static inline int gnttab_map_frame(struct domain *d, unsigned long idx, +- gfn_t gfn, mfn_t *mfn) ++static inline int gnttab_map_frame_begin(struct domain *d, unsigned long idx, ++ gfn_t gfn, mfn_t *mfn) + { + return -EINVAL; + } + ++static inline void gnttab_map_frame_end(struct domain *d, mfn_t mfn) {} ++ + static inline unsigned int gnttab_resource_max_frames( + const struct domain *d, unsigned int id) + {