128 lines
4.7 KiB
Diff
128 lines
4.7 KiB
Diff
From 50399796da938c4ea7c69058fde84695bce9d794 Mon Sep 17 00:00:00 2001
|
|
From: Paolo Bonzini <pbonzini@redhat.com>
|
|
Date: Mon, 18 Mar 2024 14:41:10 -0400
|
|
Subject: [PATCH 019/100] KVM: track whether guest state is encrypted
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
|
|
RH-MergeRequest: 245: SEV-SNP support
|
|
RH-Jira: RHEL-39544
|
|
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
|
RH-Acked-by: Bandan Das <bdas@redhat.com>
|
|
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
RH-Commit: [19/91] 685b9c54d43d0043d15c33d13afc3a420cbe139b (bonzini/rhel-qemu-kvm)
|
|
|
|
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>
|
|
(cherry picked from commit 5c3131c392f84c660033d511ec39872d8beb4b1e)
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
---
|
|
accel/kvm/kvm-all.c | 17 ++++++++++++++---
|
|
include/sysemu/kvm.h | 2 ++
|
|
include/sysemu/kvm_int.h | 1 +
|
|
target/i386/sev.c | 1 +
|
|
4 files changed, 18 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
|
|
index 931f74256e..ec0f6df7c5 100644
|
|
--- a/accel/kvm/kvm-all.c
|
|
+++ b/accel/kvm/kvm-all.c
|
|
@@ -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)
|
|
{
|
|
- if (!cpu->vcpu_dirty) {
|
|
+ if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
|
|
int ret = kvm_arch_get_registers(cpu);
|
|
if (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)
|
|
{
|
|
- 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);
|
|
}
|
|
}
|
|
@@ -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)
|
|
{
|
|
- 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)
|
|
@@ -4099,3 +4105,8 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
|
|
query_stats_schema_vcpu(first_cpu, &stats_args);
|
|
}
|
|
}
|
|
+
|
|
+void kvm_mark_guest_state_protected(void)
|
|
+{
|
|
+ kvm_state->guest_state_protected = true;
|
|
+}
|
|
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
|
|
index fad9a7e8ff..302e8f6f1e 100644
|
|
--- a/include/sysemu/kvm.h
|
|
+++ b/include/sysemu/kvm.h
|
|
@@ -539,6 +539,8 @@ bool kvm_dirty_ring_enabled(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
|
|
* reported for the VM.
|
|
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
|
|
index 882e37e12c..3496be7997 100644
|
|
--- a/include/sysemu/kvm_int.h
|
|
+++ b/include/sysemu/kvm_int.h
|
|
@@ -87,6 +87,7 @@ struct KVMState
|
|
bool kernel_irqchip_required;
|
|
OnOffAuto kernel_irqchip_split;
|
|
bool sync_mmu;
|
|
+ bool guest_state_protected;
|
|
uint64_t manual_dirty_log_protect;
|
|
/* The man page (and posix) say ioctl numbers are signed int, but
|
|
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
|
|
diff --git a/target/i386/sev.c b/target/i386/sev.c
|
|
index b8f79d34d1..c49a8fd55e 100644
|
|
--- a/target/i386/sev.c
|
|
+++ b/target/i386/sev.c
|
|
@@ -755,6 +755,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
|
|
if (ret) {
|
|
exit(1);
|
|
}
|
|
+ kvm_mark_guest_state_protected();
|
|
}
|
|
|
|
/* query the measurement blob length */
|
|
--
|
|
2.39.3
|
|
|