Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e56f0088cf | ||
|
|
6a77b77734 | ||
|
|
f9e6579959 | ||
|
|
aad83ce331 | ||
|
|
1a1a856cfd | ||
|
|
ddf24e79d8 | ||
|
|
57b04934fa | ||
|
|
f83ebf51c1 | ||
|
|
f8d96e12e3 |
14 changed files with 444 additions and 1556 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
sources
2
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
|
||||
|
|
|
|||
88
xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch
Normal file
88
xen.git-60a2c34900373ded0c81dbb7367792178b6c33b9.patch
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
From 60a2c34900373ded0c81dbb7367792178b6c33b9 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
(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
|
||||
|
||||
66
xen.spec
66
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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 4.19.5-1
|
||||
- update to xen 4.19.5
|
||||
remove patches now included or superceded upstream
|
||||
|
||||
* Wed Mar 18 2026 Michael Young <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 4.19.4-1
|
||||
- update to xen-4.19.4
|
||||
remove patches now included or superceded upstream
|
||||
|
||||
* Fri Oct 24 2025 Michael Young <m.a.young@durham.ac.uk> - 4.19.3-8
|
||||
- Incorrect removal of permissions on PCI device unplug [XSA-476,
|
||||
CVE-2025-58149]
|
||||
|
||||
* Tue Oct 21 2025 Michael Young <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 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 <m.a.young@durham.ac.uk> - 4.19.2-4
|
||||
- x86: Indirect Target Selection [XSA-469, CVE-2024-28956]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
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 <asm/alternative-asm.h>
|
||||
#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 */
|
||||
|
||||
|
|
@ -1,314 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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 <xen/linkage.h>
|
||||
+
|
||||
+ .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 <asm/page.h>
|
||||
-#include <asm/asm_defns.h>
|
||||
-#include <public/xen.h>
|
||||
-
|
||||
- .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" ); \
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
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 <asm/asm_defns.h>
|
||||
|
||||
+/* 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, \
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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
|
||||
|
|
@ -1,506 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <jbeulich@suse.com>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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 <xen/linkage.h>
|
||||
+
|
||||
+#include <asm/asm_defns.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
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 <xen/linkage.h>
|
||||
+
|
||||
+#include <asm/asm_defns.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#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
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
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 <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
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__]
|
||||
30
xsa483.patch
Normal file
30
xsa483.patch
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
From: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
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 <andriy.sultanov@vates.tech>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
|
||||
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;
|
||||
89
xsa484.patch
Normal file
89
xsa484.patch
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Gross <jgross@suse.com>
|
||||
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 <andriy.sultanov@vates.tech>
|
||||
Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions")
|
||||
Signed-off-by: Juergen Gross <jgross@suse.com>
|
||||
---
|
||||
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
|
||||
|
||||
181
xsa486.patch
Normal file
181
xsa486.patch
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
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 <rafal.wojtczuk@7bulls.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- 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)
|
||||
{
|
||||
Loading…
Add table
Add a link
Reference in a new issue