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>
This commit is contained in:
Andrew Cooper committed 2025-05-12 17:17:38 +01:00
1 parent 328ed39c59
commit ef30ffe0a0
6 files changed
+112 -89

No files matched your search

+1 -1
View File
@@ -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
+50
View File
@@ -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)
-76
View File
@@ -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:
*/
+44 -4
View File
@@ -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;
+1
View File
@@ -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
+16 -8
View File
@@ -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" ); \
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.