Skip to content

Commit c8ed081

Browse files
author
Peter Zijlstra
committed
x86/hyperv: Use direct call to hypercall-page
Instead of using an indirect call to the hypercall page, use a direct call instead. This avoids all CFI problems, including the one where the hypercall page doesn't have IBT on. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Michael Kelley <[email protected]> Acked-by: Sean Christopherson <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 0e20f1f commit c8ed081

1 file changed

Lines changed: 30 additions & 31 deletions

File tree

arch/x86/hyperv/hv_init.c

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <asm/desc.h>
1818
#include <asm/e820/api.h>
1919
#include <asm/sev.h>
20-
#include <asm/ibt.h>
2120
#include <asm/hypervisor.h>
2221
#include <hyperv/hvhdk.h>
2322
#include <asm/mshyperv.h>
@@ -39,23 +38,41 @@
3938
void *hv_hypercall_pg;
4039

4140
#ifdef CONFIG_X86_64
41+
static u64 __hv_hyperfail(u64 control, u64 param1, u64 param2)
42+
{
43+
return U64_MAX;
44+
}
45+
46+
DEFINE_STATIC_CALL(__hv_hypercall, __hv_hyperfail);
47+
4248
u64 hv_std_hypercall(u64 control, u64 param1, u64 param2)
4349
{
4450
u64 hv_status;
4551

46-
if (!hv_hypercall_pg)
47-
return U64_MAX;
48-
4952
register u64 __r8 asm("r8") = param2;
50-
asm volatile (CALL_NOSPEC
53+
asm volatile ("call " STATIC_CALL_TRAMP_STR(__hv_hypercall)
5154
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
5255
"+c" (control), "+d" (param1), "+r" (__r8)
53-
: THUNK_TARGET(hv_hypercall_pg)
54-
: "cc", "memory", "r9", "r10", "r11");
56+
: : "cc", "memory", "r9", "r10", "r11");
5557

5658
return hv_status;
5759
}
60+
61+
typedef u64 (*hv_hypercall_f)(u64 control, u64 param1, u64 param2);
62+
63+
static inline void hv_set_hypercall_pg(void *ptr)
64+
{
65+
hv_hypercall_pg = ptr;
66+
67+
if (!ptr)
68+
ptr = &__hv_hyperfail;
69+
static_call_update(__hv_hypercall, (hv_hypercall_f)ptr);
70+
}
5871
#else
72+
static inline void hv_set_hypercall_pg(void *ptr)
73+
{
74+
hv_hypercall_pg = ptr;
75+
}
5976
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
6077
#endif
6178

@@ -350,7 +367,7 @@ static int hv_suspend(void)
350367
* pointer is restored on resume.
351368
*/
352369
hv_hypercall_pg_saved = hv_hypercall_pg;
353-
hv_hypercall_pg = NULL;
370+
hv_set_hypercall_pg(NULL);
354371

355372
/* Disable the hypercall page in the hypervisor */
356373
rdmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@@ -376,7 +393,7 @@ static void hv_resume(void)
376393
vmalloc_to_pfn(hv_hypercall_pg_saved);
377394
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
378395

379-
hv_hypercall_pg = hv_hypercall_pg_saved;
396+
hv_set_hypercall_pg(hv_hypercall_pg_saved);
380397
hv_hypercall_pg_saved = NULL;
381398

382399
/*
@@ -496,8 +513,8 @@ void __init hyperv_init(void)
496513
if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present)
497514
goto skip_hypercall_pg_init;
498515

499-
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START,
500-
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
516+
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, MODULES_VADDR,
517+
MODULES_END, GFP_KERNEL, PAGE_KERNEL_ROX,
501518
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
502519
__builtin_return_address(0));
503520
if (hv_hypercall_pg == NULL)
@@ -535,27 +552,9 @@ void __init hyperv_init(void)
535552
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
536553
}
537554

538-
skip_hypercall_pg_init:
539-
/*
540-
* Some versions of Hyper-V that provide IBT in guest VMs have a bug
541-
* in that there's no ENDBR64 instruction at the entry to the
542-
* hypercall page. Because hypercalls are invoked via an indirect call
543-
* to the hypercall page, all hypercall attempts fail when IBT is
544-
* enabled, and Linux panics. For such buggy versions, disable IBT.
545-
*
546-
* Fixed versions of Hyper-V always provide ENDBR64 on the hypercall
547-
* page, so if future Linux kernel versions enable IBT for 32-bit
548-
* builds, additional hypercall page hackery will be required here
549-
* to provide an ENDBR32.
550-
*/
551-
#ifdef CONFIG_X86_KERNEL_IBT
552-
if (cpu_feature_enabled(X86_FEATURE_IBT) &&
553-
*(u32 *)hv_hypercall_pg != gen_endbr()) {
554-
setup_clear_cpu_cap(X86_FEATURE_IBT);
555-
pr_warn("Disabling IBT because of Hyper-V bug\n");
556-
}
557-
#endif
555+
hv_set_hypercall_pg(hv_hypercall_pg);
558556

557+
skip_hypercall_pg_init:
559558
/*
560559
* hyperv_init() is called before LAPIC is initialized: see
561560
* apic_intr_mode_init() -> x86_platform.apic_post_init() and

0 commit comments

Comments
 (0)