Skip to content

Commit

Permalink
x86/kvm: Disable all PV features on crash
Browse files Browse the repository at this point in the history
commit 3d6b841 upstream.

Crash shutdown handler only disables kvmclock and steal time, other PV
features remain active so we risk corrupting memory or getting some
side-effects in kdump kernel. Move crash handler to kvm.c and unify
with CPU offline.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20210414123544.1060604-5-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
vittyvk authored and gregkh committed Jun 10, 2021
1 parent 3b0becf commit 334c59d
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 39 deletions.
6 changes: 0 additions & 6 deletions arch/x86/include/asm/kvm_para.h
Expand Up @@ -92,7 +92,6 @@ unsigned int kvm_arch_para_hints(void);
void kvm_async_pf_task_wait_schedule(u32 token);
void kvm_async_pf_task_wake(u32 token);
u32 kvm_read_and_reset_apf_flags(void);
void kvm_disable_steal_time(void);
bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token);

DECLARE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
Expand Down Expand Up @@ -137,11 +136,6 @@ static inline u32 kvm_read_and_reset_apf_flags(void)
return 0;
}

static inline void kvm_disable_steal_time(void)
{
return;
}

static __always_inline bool kvm_handle_async_pf(struct pt_regs *regs, u32 token)
{
return false;
Expand Down
44 changes: 32 additions & 12 deletions arch/x86/kernel/kvm.c
Expand Up @@ -38,6 +38,7 @@
#include <asm/tlb.h>
#include <asm/cpuidle_haltpoll.h>
#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/svm.h>

DEFINE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
Expand Down Expand Up @@ -375,6 +376,14 @@ static void kvm_pv_disable_apf(void)
pr_info("Unregister pv shared memory for cpu %d\n", smp_processor_id());
}

static void kvm_disable_steal_time(void)
{
if (!has_steal_clock)
return;

wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
}

static void kvm_pv_guest_cpu_reboot(void *unused)
{
/*
Expand Down Expand Up @@ -417,14 +426,6 @@ static u64 kvm_steal_clock(int cpu)
return steal;
}

void kvm_disable_steal_time(void)
{
if (!has_steal_clock)
return;

wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
}

static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
{
early_set_memory_decrypted((unsigned long) ptr, size);
Expand Down Expand Up @@ -461,13 +462,14 @@ static bool pv_tlb_flush_supported(void)

static DEFINE_PER_CPU(cpumask_var_t, __pv_cpu_mask);

static void kvm_guest_cpu_offline(void)
static void kvm_guest_cpu_offline(bool shutdown)
{
kvm_disable_steal_time();
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
kvm_pv_disable_apf();
apf_task_wake_all();
if (!shutdown)
apf_task_wake_all();
kvmclock_disable();
}

Expand Down Expand Up @@ -613,7 +615,7 @@ static int kvm_cpu_down_prepare(unsigned int cpu)
unsigned long flags;

local_irq_save(flags);
kvm_guest_cpu_offline();
kvm_guest_cpu_offline(false);
local_irq_restore(flags);
return 0;
}
Expand All @@ -622,7 +624,7 @@ static int kvm_cpu_down_prepare(unsigned int cpu)

static int kvm_suspend(void)
{
kvm_guest_cpu_offline();
kvm_guest_cpu_offline(false);

return 0;
}
Expand All @@ -637,6 +639,20 @@ static struct syscore_ops kvm_syscore_ops = {
.resume = kvm_resume,
};

/*
* After a PV feature is registered, the host will keep writing to the
* registered memory location. If the guest happens to shutdown, this memory
* won't be valid. In cases like kexec, in which you install a new kernel, this
* means a random memory location will be kept being written.
*/
#ifdef CONFIG_KEXEC_CORE
static void kvm_crash_shutdown(struct pt_regs *regs)
{
kvm_guest_cpu_offline(true);
native_machine_crash_shutdown(regs);
}
#endif

static void kvm_flush_tlb_others(const struct cpumask *cpumask,
const struct flush_tlb_info *info)
{
Expand Down Expand Up @@ -705,6 +721,10 @@ static void __init kvm_guest_init(void)
kvm_guest_cpu_init();
#endif

#ifdef CONFIG_KEXEC_CORE
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif

register_syscore_ops(&kvm_syscore_ops);

/*
Expand Down
21 changes: 0 additions & 21 deletions arch/x86/kernel/kvmclock.c
Expand Up @@ -20,7 +20,6 @@
#include <asm/hypervisor.h>
#include <asm/mem_encrypt.h>
#include <asm/x86_init.h>
#include <asm/reboot.h>
#include <asm/kvmclock.h>

static int kvmclock __initdata = 1;
Expand Down Expand Up @@ -204,23 +203,6 @@ static void kvm_setup_secondary_clock(void)
}
#endif

/*
* After the clock is registered, the host will keep writing to the
* registered memory location. If the guest happens to shutdown, this memory
* won't be valid. In cases like kexec, in which you install a new kernel, this
* means a random memory location will be kept being written. So before any
* kind of shutdown from our side, we unregister the clock by writing anything
* that does not have the 'enable' bit set in the msr
*/
#ifdef CONFIG_KEXEC_CORE
static void kvm_crash_shutdown(struct pt_regs *regs)
{
native_write_msr(msr_kvm_system_time, 0, 0);
kvm_disable_steal_time();
native_machine_crash_shutdown(regs);
}
#endif

void kvmclock_disable(void)
{
native_write_msr(msr_kvm_system_time, 0, 0);
Expand Down Expand Up @@ -350,9 +332,6 @@ void __init kvmclock_init(void)
#endif
x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
#ifdef CONFIG_KEXEC_CORE
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif
kvm_get_preset_lpj();

/*
Expand Down

0 comments on commit 334c59d

Please sign in to comment.