KVM: track whether guest state is encrypted
So far, KVM has allowed KVM_GET/SET_* ioctls to execute even if the guest state is encrypted, in which case they do nothing. For the new API using VM types, instead, the ioctls will fail which is a safer and more robust approach. The new API will be the only one available for SEV-SNP and TDX, but it is also usable for SEV and SEV-ES. In preparation for that, require architecture-specific KVM code to communicate the point at which guest state is protected (which must be after kvm_cpu_synchronize_post_init(), though that might change in the future in order to suppor migration). From that point, skip reading registers so that cpu->vcpu_dirty is never true: if it ever becomes true, kvm_arch_put_registers() will fail miserably. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
08b2d15cdd
commit
5c3131c392
@ -2703,7 +2703,7 @@ bool kvm_cpu_check_are_resettable(void)
|
|||||||
|
|
||||||
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
if (!cpu->vcpu_dirty) {
|
if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
|
||||||
int ret = kvm_arch_get_registers(cpu);
|
int ret = kvm_arch_get_registers(cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_report("Failed to get registers: %s", strerror(-ret));
|
error_report("Failed to get registers: %s", strerror(-ret));
|
||||||
@ -2717,7 +2717,7 @@ static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
|||||||
|
|
||||||
void kvm_cpu_synchronize_state(CPUState *cpu)
|
void kvm_cpu_synchronize_state(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (!cpu->vcpu_dirty) {
|
if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
|
||||||
run_on_cpu(cpu, do_kvm_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_kvm_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2752,7 +2752,13 @@ static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
|
|||||||
|
|
||||||
void kvm_cpu_synchronize_post_init(CPUState *cpu)
|
void kvm_cpu_synchronize_post_init(CPUState *cpu)
|
||||||
{
|
{
|
||||||
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
if (!kvm_state->guest_state_protected) {
|
||||||
|
/*
|
||||||
|
* This runs before the machine_init_done notifiers, and is the last
|
||||||
|
* opportunity to synchronize the state of confidential guests.
|
||||||
|
*/
|
||||||
|
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_kvm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
|
static void do_kvm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
|
||||||
@ -4099,3 +4105,8 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
|
|||||||
query_stats_schema_vcpu(first_cpu, &stats_args);
|
query_stats_schema_vcpu(first_cpu, &stats_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_mark_guest_state_protected(void)
|
||||||
|
{
|
||||||
|
kvm_state->guest_state_protected = true;
|
||||||
|
}
|
||||||
|
@ -539,6 +539,8 @@ bool kvm_dirty_ring_enabled(void);
|
|||||||
|
|
||||||
uint32_t kvm_dirty_ring_size(void);
|
uint32_t kvm_dirty_ring_size(void);
|
||||||
|
|
||||||
|
void kvm_mark_guest_state_protected(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_hwpoisoned_mem - indicate if there is any hwpoisoned page
|
* kvm_hwpoisoned_mem - indicate if there is any hwpoisoned page
|
||||||
* reported for the VM.
|
* reported for the VM.
|
||||||
|
@ -87,6 +87,7 @@ struct KVMState
|
|||||||
bool kernel_irqchip_required;
|
bool kernel_irqchip_required;
|
||||||
OnOffAuto kernel_irqchip_split;
|
OnOffAuto kernel_irqchip_split;
|
||||||
bool sync_mmu;
|
bool sync_mmu;
|
||||||
|
bool guest_state_protected;
|
||||||
uint64_t manual_dirty_log_protect;
|
uint64_t manual_dirty_log_protect;
|
||||||
/* The man page (and posix) say ioctl numbers are signed int, but
|
/* The man page (and posix) say ioctl numbers are signed int, but
|
||||||
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
|
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
|
||||||
|
@ -755,6 +755,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
kvm_mark_guest_state_protected();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query the measurement blob length */
|
/* query the measurement blob length */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user