[RFC PATCH 13/73] KVM: x86/emulator: Reinject #GP if instruction emulation failed for PVM

Lai Jiangshan
2024-02-26T14:35:20Z

From: Hou Wenlong <houwenlong.hwl@antgroup.com>

The privilege instruction in PVM guest supervisor mode will trigger a
instruction triggers a #GP in PVM guest supervisor mode and is not
implemented in the emulator, the emulator will currently exit to
userspace, and VMM may not be able to handle it. This can be triggered
by guest userspace, e.g., a guest userspace process can corrupt the
XSTATE header in a signal frame and the XRSTOR in the guest kernel will
trigger a #GP, but XRSTOR is not implemented in the emulator now.
Therefore, a new emulate type for PVM is added to instruct the emulator
to reinject the #GP into the guest.

Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
Signed-off-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
---
arch/x86/include/asm/kvm_host.h | 8 ++++++++
arch/x86/kvm/x86.c | 5 +++--
2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index a90807f676b9..3e6f27865528 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1954,6 +1954,13 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
* the gfn, i.e. retrying the instruction will hit a
* !PRESENT fault, which results in a new shadow page
* and sends KVM back to square one.
+ *
+ * EMULTYPE_PVM_GP - Set when emulating an intercepted #GP for PVM. Privilege
+ * instruction in PVM guest supervisor mode will trigger a
+ * #GP and be emulated by PVM. But if a non-privilege
+ * instruction triggers a #GP in PVM guest supervisor mode
+ * and is not implemented in the emulator, the emulator
+ * should reinject the #GP into guest.
*/
#define EMULTYPE_NO_DECODE (1 << 0)
#define EMULTYPE_TRAP_UD (1 << 1)
@@ -1964,6 +1971,7 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
#define EMULTYPE_PF (1 << 6)
#define EMULTYPE_COMPLETE_USER_EXIT (1 << 7)
#define EMULTYPE_WRITE_PF_TO_SP (1 << 8)
+#define EMULTYPE_PVM_GP (1 << 9)

int kvm_emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type);
int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 89bf368085a9..29413cb2f090 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8664,7 +8664,7 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type)
++vcpu->stat.insn_emulation_fail;
trace_kvm_emulate_insn_failed(vcpu);

- if (emulation_type & EMULTYPE_VMWARE_GP) {
+ if (emulation_type & (EMULTYPE_VMWARE_GP | EMULTYPE_PVM_GP)) {
kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
return 1;
}
@@ -8902,7 +8902,8 @@ static bool kvm_vcpu_check_code_breakpoint(struct kvm_vcpu *vcpu,
* and without a prefix.
*/
if (emulation_type & (EMULTYPE_NO_DECODE | EMULTYPE_SKIP |
- EMULTYPE_TRAP_UD | EMULTYPE_VMWARE_GP | EMULTYPE_PF))
+ EMULTYPE_TRAP_UD | EMULTYPE_VMWARE_GP |
+ EMULTYPE_PVM_GP | EMULTYPE_PF))
return false;

if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) &&
--
2.19.1.6.gb485710b