aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWanpeng Li <wanpengli@tencent.com>2018-04-03 19:28:49 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2018-04-04 13:09:40 -0400
commit6c86eedc206dd1f9d37a2796faa8e6f2278215d2 (patch)
treed7f41b8dab91d94a460a9e9128086d11cfba8518
parent082d06edab49f302eb96b7a9d029f52713156354 (diff)
KVM: X86: Add Force Emulation Prefix for "emulate the next instruction"
There is no easy way to force KVM to run an instruction through the emulator (by design as that will expose the x86 emulator as a significant attack-surface). However, we do wish to expose the x86 emulator in case we are testing it (e.g. via kvm-unit-tests). Therefore, this patch adds a "force emulation prefix" that is designed to raise #UD which KVM will trap and it's #UD exit-handler will match "force emulation prefix" to run instruction after prefix by the x86 emulator. To not expose the x86 emulator by default, we add a module parameter that should be off by default. A simple testcase here: #include <stdio.h> #include <string.h> #define HYPERVISOR_INFO 0x40000000 #define CPUID(idx, eax, ebx, ecx, edx) \ asm volatile (\ "ud2a; .ascii \"kvm\"; cpuid" \ :"=b" (*ebx), "=a" (*eax), "=c" (*ecx), "=d" (*edx) \ :"0"(idx) ); void main() { unsigned int eax, ebx, ecx, edx; char string[13]; CPUID(HYPERVISOR_INFO, &eax, &ebx, &ecx, &edx); *(unsigned int *)(string + 0) = ebx; *(unsigned int *)(string + 4) = ecx; *(unsigned int *)(string + 8) = edx; string[12] = 0; if (strncmp(string, "KVMKVMKVM\0\0\0", 12) == 0) printf("kvm guest\n"); else printf("bare hardware\n"); } Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Radim Krčmář <rkrcmar@redhat.com> Reviewed-by: Liran Alon <liran.alon@oracle.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Andrew Cooper <andrew.cooper3@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Liran Alon <liran.alon@oracle.com> Signed-off-by: Wanpeng Li <wanpengli@tencent.com> [Correctly handle usermode exits. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/x86.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1eb495e04fd3..8f108131d85d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -146,6 +146,9 @@ bool __read_mostly enable_vmware_backdoor = false;
146module_param(enable_vmware_backdoor, bool, S_IRUGO); 146module_param(enable_vmware_backdoor, bool, S_IRUGO);
147EXPORT_SYMBOL_GPL(enable_vmware_backdoor); 147EXPORT_SYMBOL_GPL(enable_vmware_backdoor);
148 148
149static bool __read_mostly force_emulation_prefix = false;
150module_param(force_emulation_prefix, bool, S_IRUGO);
151
149#define KVM_NR_SHARED_MSRS 16 152#define KVM_NR_SHARED_MSRS 16
150 153
151struct kvm_shared_msrs_global { 154struct kvm_shared_msrs_global {
@@ -4842,9 +4845,20 @@ EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
4842 4845
4843int handle_ud(struct kvm_vcpu *vcpu) 4846int handle_ud(struct kvm_vcpu *vcpu)
4844{ 4847{
4848 int emul_type = EMULTYPE_TRAP_UD;
4845 enum emulation_result er; 4849 enum emulation_result er;
4850 char sig[5]; /* ud2; .ascii "kvm" */
4851 struct x86_exception e;
4852
4853 if (force_emulation_prefix &&
4854 kvm_read_guest_virt(&vcpu->arch.emulate_ctxt,
4855 kvm_get_linear_rip(vcpu), sig, sizeof(sig), &e) == 0 &&
4856 memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
4857 kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
4858 emul_type = 0;
4859 }
4846 4860
4847 er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD); 4861 er = emulate_instruction(vcpu, emul_type);
4848 if (er == EMULATE_USER_EXIT) 4862 if (er == EMULATE_USER_EXIT)
4849 return 0; 4863 return 0;
4850 if (er != EMULATE_DONE) 4864 if (er != EMULATE_DONE)