VMware accepts a structured guest-crash event, but a host configured with backdoor.coredumpOnCrash may terminate the VM before the hypercall returns. Sending the event from a panic notifier could prevent later kmsg dumpers and a loaded crash kernel from running.
Register a second panic-only kmsg dumper with late_initcall_sync(). Kmsg dumpers run in registration order, placing the report after the early VMware logger and built-in dumpers registered by then. This leaves no report before the late initcall, but avoids losing dump output to a terminating host. Skip the event when a crash kernel is loaded. The earlier logger can still write panic text to vmware.log before __crash_kexec(). If kdump later fails, no structured event is sent; issuing it first could prevent kdump from running at all. Issue the event at most once. With CONFIG_PRINTK=n, install a late INT_MIN panic notifier. An unexpected dumper registration failure with printk enabled leaves reporting disabled because a notifier fallback would overtake working dumpers. Link: https://lore.kernel.org/r/[email protected] Co-developed-by: Brennan Lamoreaux <[email protected]> Signed-off-by: Brennan Lamoreaux <[email protected]> Co-developed-by: Alexey Makhalov <[email protected]> Signed-off-by: Alexey Makhalov <[email protected]> Signed-off-by: Zack Rusin <[email protected]> --- arch/x86/include/asm/vmware.h | 1 + arch/x86/kernel/cpu/vmware.c | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h index 598d4cd448ec..ea2ce5272a00 100644 --- a/arch/x86/include/asm/vmware.h +++ b/arch/x86/include/asm/vmware.h @@ -61,6 +61,7 @@ #define VMWARE_CMD_GETHZ 45 #define VMWARE_CMD_GETVCPU_INFO 68 #define VMWARE_CMD_STEALCLOCK 91 +#define VMWARE_CMD_REPORTGUESTCRASH 102 /* * Hypercall command mask: * bits [6:0] command, range [0, 127] diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 3848811550e9..c21fc835537f 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -22,10 +22,14 @@ */ #include <linux/dmi.h> +#include <linux/atomic.h> +#include <linux/crash_core.h> #include <linux/init.h> #include <linux/export.h> #include <linux/kmsg_dump.h> +#include <linux/limits.h> #include <linux/mm.h> +#include <linux/panic_notifier.h> #include <linux/clocksource.h> #include <linux/cpu.h> #include <linux/efi.h> @@ -323,6 +327,65 @@ static int __init vmware_panic_log_init(void) } early_initcall(vmware_panic_log_init); +static atomic_t vmware_crash_reported = ATOMIC_INIT(0); + +static void vmware_report_guest_crash(void) +{ + if (kexec_crash_loaded()) + return; + if (atomic_xchg(&vmware_crash_reported, 1)) + return; + + vmware_hypercall1(VMWARE_CMD_REPORTGUESTCRASH, 0); +} + +static void vmware_crash_report_dump(struct kmsg_dumper *dumper, + struct kmsg_dump_detail *detail) +{ + vmware_report_guest_crash(); +} + +static struct kmsg_dumper vmware_crash_report_dumper = { + .dump = vmware_crash_report_dump, + .max_reason = KMSG_DUMP_PANIC, +}; + +static int vmware_crash_report_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + vmware_report_guest_crash(); + return NOTIFY_DONE; +} + +static struct notifier_block vmware_crash_report_nb = { + .notifier_call = vmware_crash_report_notify, + .priority = INT_MIN, +}; + +static int __init vmware_crash_report_init(void) +{ + int ret; + + if (!hypervisor_is_type(X86_HYPER_VMWARE)) + return 0; + + ret = kmsg_dump_register(&vmware_crash_report_dumper); + if (!ret) + return 0; + if (IS_ENABLED(CONFIG_PRINTK)) { + pr_err("failed to register crash report dumper: %d\n", ret); + return 0; + } + + ret = atomic_notifier_chain_register(&panic_notifier_list, + &vmware_crash_report_nb); + if (ret) + pr_err("failed to register crash report notifier: %d\n", ret); + + return 0; +} +late_initcall_sync(vmware_crash_report_init); + #ifdef CONFIG_PARAVIRT static struct cyc2ns_data vmware_cyc2ns __ro_after_init; static bool vmw_sched_clock __initdata = true; -- 2.53.0

