Skip to content

Commit

Permalink
x86/reboot: VMCLEAR active VMCSes before emergency reboot
Browse files Browse the repository at this point in the history
VMCLEAR active VMCSes before any emergency reboot, not just if the kernel
may kexec into a new kernel after a crash.  Per Intel's SDM, the VMX
architecture doesn't require the CPU to flush the VMCS cache on INIT.  If
an emergency reboot doesn't RESET CPUs, cached VMCSes could theoretically
be kept and only be written back to memory after the new kernel is booted,
i.e. could effectively corrupt memory after reboot.

Opportunistically remove the setting of the global pointer to NULL to make
checkpatch happy.

Cc: Andrew Cooper <Andrew.Cooper3@citrix.com>
Link: https://lore.kernel.org/r/20230721201859.2307736-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
  • Loading branch information
sean-jc committed Aug 3, 2023
1 parent 41e90a6 commit b23c83a
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 40 deletions.
2 changes: 0 additions & 2 deletions arch/x86/include/asm/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image);
#endif
#endif

typedef void crash_vmclear_fn(void);
extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
extern void kdump_nmi_shootdown_cpus(void);

#endif /* __ASSEMBLY__ */
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/reboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ void __noreturn machine_real_restart(unsigned int type);
#define MRR_BIOS 0
#define MRR_APM 1

typedef void crash_vmclear_fn(void);
extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
void cpu_emergency_disable_virtualization(void);

typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
Expand Down
31 changes: 0 additions & 31 deletions arch/x86/kernel/crash.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,38 +48,12 @@ struct crash_memmap_data {
unsigned int type;
};

/*
* This is used to VMCLEAR all VMCSs loaded on the
* processor. And when loading kvm_intel module, the
* callback function pointer will be assigned.
*
* protected by rcu.
*/
crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL;
EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);

static inline void cpu_crash_vmclear_loaded_vmcss(void)
{
crash_vmclear_fn *do_vmclear_operation = NULL;

rcu_read_lock();
do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss);
if (do_vmclear_operation)
do_vmclear_operation();
rcu_read_unlock();
}

#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)

static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
{
crash_save_cpu(regs, cpu);

/*
* VMCLEAR VMCSs loaded on all cpus if needed.
*/
cpu_crash_vmclear_loaded_vmcss();

/*
* Disable Intel PT to stop its logging
*/
Expand Down Expand Up @@ -133,11 +107,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs)

crash_smp_send_stop();

/*
* VMCLEAR VMCSs loaded on this cpu if needed.
*/
cpu_crash_vmclear_loaded_vmcss();

cpu_emergency_disable_virtualization();

/*
Expand Down
22 changes: 22 additions & 0 deletions arch/x86/kernel/reboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,26 @@ void machine_crash_shutdown(struct pt_regs *regs)
}
#endif

/*
* This is used to VMCLEAR all VMCSs loaded on the
* processor. And when loading kvm_intel module, the
* callback function pointer will be assigned.
*
* protected by rcu.
*/
crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);

static inline void cpu_crash_vmclear_loaded_vmcss(void)
{
crash_vmclear_fn *do_vmclear_operation = NULL;

rcu_read_lock();
do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss);
if (do_vmclear_operation)
do_vmclear_operation();
rcu_read_unlock();
}

/* This is the CPU performing the emergency shutdown work. */
int crashing_cpu = -1;
Expand All @@ -798,6 +818,8 @@ int crashing_cpu = -1;
*/
void cpu_emergency_disable_virtualization(void)
{
cpu_crash_vmclear_loaded_vmcss();

cpu_emergency_vmxoff();
cpu_emergency_svm_disable();
}
Expand Down
10 changes: 3 additions & 7 deletions arch/x86/kvm/vmx/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
#include <asm/idtentry.h>
#include <asm/io.h>
#include <asm/irq_remapping.h>
#include <asm/kexec.h>
#include <asm/reboot.h>
#include <asm/perf_event.h>
#include <asm/mmu_context.h>
#include <asm/mshyperv.h>
Expand Down Expand Up @@ -725,7 +725,6 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
return ret;
}

#ifdef CONFIG_KEXEC_CORE
static void crash_vmclear_local_loaded_vmcss(void)
{
int cpu = raw_smp_processor_id();
Expand All @@ -735,7 +734,6 @@ static void crash_vmclear_local_loaded_vmcss(void)
loaded_vmcss_on_cpu_link)
vmcs_clear(v->vmcs);
}
#endif /* CONFIG_KEXEC_CORE */

static void __loaded_vmcs_clear(void *arg)
{
Expand Down Expand Up @@ -8573,10 +8571,9 @@ static void __vmx_exit(void)
{
allow_smaller_maxphyaddr = false;

#ifdef CONFIG_KEXEC_CORE
RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL);
synchronize_rcu();
#endif

vmx_cleanup_l1d_flush();
}

Expand Down Expand Up @@ -8623,10 +8620,9 @@ static int __init vmx_init(void)
pi_init_cpu(cpu);
}

#ifdef CONFIG_KEXEC_CORE
rcu_assign_pointer(crash_vmclear_loaded_vmcss,
crash_vmclear_local_loaded_vmcss);
#endif

vmx_check_vmcs12_offsets();

/*
Expand Down

0 comments on commit b23c83a

Please sign in to comment.