Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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) <peterz@infradead.org>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Acked-by: Sean Christopherson <seanjc@google.com>
Link: https://lkml.kernel.org/r/20250714103441.011387946@infradead.org

+30 -31
+30 -31
arch/x86/hyperv/hv_init.c
··· 17 17 #include <asm/desc.h> 18 18 #include <asm/e820/api.h> 19 19 #include <asm/sev.h> 20 - #include <asm/ibt.h> 21 20 #include <asm/hypervisor.h> 22 21 #include <hyperv/hvhdk.h> 23 22 #include <asm/mshyperv.h> ··· 38 39 void *hv_hypercall_pg; 39 40 40 41 #ifdef CONFIG_X86_64 42 + static u64 __hv_hyperfail(u64 control, u64 param1, u64 param2) 43 + { 44 + return U64_MAX; 45 + } 46 + 47 + DEFINE_STATIC_CALL(__hv_hypercall, __hv_hyperfail); 48 + 41 49 u64 hv_std_hypercall(u64 control, u64 param1, u64 param2) 42 50 { 43 51 u64 hv_status; 44 52 45 - if (!hv_hypercall_pg) 46 - return U64_MAX; 47 - 48 53 register u64 __r8 asm("r8") = param2; 49 - asm volatile (CALL_NOSPEC 54 + asm volatile ("call " STATIC_CALL_TRAMP_STR(__hv_hypercall) 50 55 : "=a" (hv_status), ASM_CALL_CONSTRAINT, 51 56 "+c" (control), "+d" (param1), "+r" (__r8) 52 - : THUNK_TARGET(hv_hypercall_pg) 53 - : "cc", "memory", "r9", "r10", "r11"); 57 + : : "cc", "memory", "r9", "r10", "r11"); 54 58 55 59 return hv_status; 56 60 } 61 + 62 + typedef u64 (*hv_hypercall_f)(u64 control, u64 param1, u64 param2); 63 + 64 + static inline void hv_set_hypercall_pg(void *ptr) 65 + { 66 + hv_hypercall_pg = ptr; 67 + 68 + if (!ptr) 69 + ptr = &__hv_hyperfail; 70 + static_call_update(__hv_hypercall, (hv_hypercall_f)ptr); 71 + } 57 72 #else 73 + static inline void hv_set_hypercall_pg(void *ptr) 74 + { 75 + hv_hypercall_pg = ptr; 76 + } 58 77 EXPORT_SYMBOL_GPL(hv_hypercall_pg); 59 78 #endif 60 79 ··· 367 350 * pointer is restored on resume. 368 351 */ 369 352 hv_hypercall_pg_saved = hv_hypercall_pg; 370 - hv_hypercall_pg = NULL; 353 + hv_set_hypercall_pg(NULL); 371 354 372 355 /* Disable the hypercall page in the hypervisor */ 373 356 rdmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); ··· 393 376 vmalloc_to_pfn(hv_hypercall_pg_saved); 394 377 wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); 395 378 396 - hv_hypercall_pg = hv_hypercall_pg_saved; 379 + hv_set_hypercall_pg(hv_hypercall_pg_saved); 397 380 hv_hypercall_pg_saved = NULL; 398 381 399 382 /* ··· 513 496 if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present) 514 497 goto skip_hypercall_pg_init; 515 498 516 - hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, 517 - VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, 499 + hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, MODULES_VADDR, 500 + MODULES_END, GFP_KERNEL, PAGE_KERNEL_ROX, 518 501 VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, 519 502 __builtin_return_address(0)); 520 503 if (hv_hypercall_pg == NULL) ··· 552 535 wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); 553 536 } 554 537 555 - skip_hypercall_pg_init: 556 - /* 557 - * Some versions of Hyper-V that provide IBT in guest VMs have a bug 558 - * in that there's no ENDBR64 instruction at the entry to the 559 - * hypercall page. Because hypercalls are invoked via an indirect call 560 - * to the hypercall page, all hypercall attempts fail when IBT is 561 - * enabled, and Linux panics. For such buggy versions, disable IBT. 562 - * 563 - * Fixed versions of Hyper-V always provide ENDBR64 on the hypercall 564 - * page, so if future Linux kernel versions enable IBT for 32-bit 565 - * builds, additional hypercall page hackery will be required here 566 - * to provide an ENDBR32. 567 - */ 568 - #ifdef CONFIG_X86_KERNEL_IBT 569 - if (cpu_feature_enabled(X86_FEATURE_IBT) && 570 - *(u32 *)hv_hypercall_pg != gen_endbr()) { 571 - setup_clear_cpu_cap(X86_FEATURE_IBT); 572 - pr_warn("Disabling IBT because of Hyper-V bug\n"); 573 - } 574 - #endif 538 + hv_set_hypercall_pg(hv_hypercall_pg); 575 539 540 + skip_hypercall_pg_init: 576 541 /* 577 542 * hyperv_init() is called before LAPIC is initialized: see 578 543 * apic_intr_mode_init() -> x86_platform.apic_post_init() and