aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSheng Yang <sheng.yang@intel.com>2008-01-02 01:49:22 -0500
committerAvi Kivity <avi@qumranet.com>2008-01-30 11:01:21 -0500
commit571008daccc17c03ccec810922c2bcaed86b15c1 (patch)
treefa748f57d24dae69456e12c989d0f71c1a0caaa5
parent5882842f9b86179e1fe2e17e35e0e46a268d04e4 (diff)
KVM: x86 emulator: Only allow VMCALL/VMMCALL trapped by #UD
When executing a test program called "crashme", we found the KVM guest cannot survive more than ten seconds, then encounterd kernel panic. The basic concept of "crashme" is generating random assembly code and trying to execute it. After some fixes on emulator insn validity judgment, we found it's hard to get the current emulator handle the invalid instructions correctly, for the #UD trap for hypercall patching caused troubles. The problem is, if the opcode itself was OK, but combination of opcode and modrm_reg was invalid, and one operand of the opcode was memory (SrcMem or DstMem), the emulator will fetch the memory operand first rather than checking the validity, and may encounter an error there. For example, ".byte 0xfe, 0x34, 0xcd" has this problem. In the patch, we simply check that if the invalid opcode wasn't vmcall/vmmcall, then return from emulate_instruction() and inject a #UD to guest. With the patch, the guest had been running for more than 12 hours. Signed-off-by: Feng (Eric) Liu <eric.e.liu@intel.com> Signed-off-by: Sheng Yang <sheng.yang@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--arch/x86/kvm/svm.c2
-rw-r--r--arch/x86/kvm/vmx.c2
-rw-r--r--arch/x86/kvm/x86.c18
-rw-r--r--include/asm-x86/kvm_host.h4
4 files changed, 20 insertions, 6 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 33f77b044c52..de755cb1431d 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -942,7 +942,7 @@ static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
942{ 942{
943 int er; 943 int er;
944 944
945 er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0); 945 er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
946 if (er != EMULATE_DONE) 946 if (er != EMULATE_DONE)
947 kvm_queue_exception(&svm->vcpu, UD_VECTOR); 947 kvm_queue_exception(&svm->vcpu, UD_VECTOR);
948 return 1; 948 return 1;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3d251f894a8d..ad36447e696e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1863,7 +1863,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1863 } 1863 }
1864 1864
1865 if (is_invalid_opcode(intr_info)) { 1865 if (is_invalid_opcode(intr_info)) {
1866 er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); 1866 er = emulate_instruction(vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
1867 if (er != EMULATE_DONE) 1867 if (er != EMULATE_DONE)
1868 kvm_queue_exception(vcpu, UD_VECTOR); 1868 kvm_queue_exception(vcpu, UD_VECTOR);
1869 return 1; 1869 return 1;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e3b3141db13c..8a90403272e2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1840,9 +1840,10 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
1840 struct kvm_run *run, 1840 struct kvm_run *run,
1841 unsigned long cr2, 1841 unsigned long cr2,
1842 u16 error_code, 1842 u16 error_code,
1843 int no_decode) 1843 int emulation_type)
1844{ 1844{
1845 int r; 1845 int r;
1846 struct decode_cache *c;
1846 1847
1847 vcpu->arch.mmio_fault_cr2 = cr2; 1848 vcpu->arch.mmio_fault_cr2 = cr2;
1848 kvm_x86_ops->cache_regs(vcpu); 1849 kvm_x86_ops->cache_regs(vcpu);
@@ -1850,7 +1851,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
1850 vcpu->mmio_is_write = 0; 1851 vcpu->mmio_is_write = 0;
1851 vcpu->arch.pio.string = 0; 1852 vcpu->arch.pio.string = 0;
1852 1853
1853 if (!no_decode) { 1854 if (!(emulation_type & EMULTYPE_NO_DECODE)) {
1854 int cs_db, cs_l; 1855 int cs_db, cs_l;
1855 kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); 1856 kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
1856 1857
@@ -1884,6 +1885,16 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
1884 get_segment_base(vcpu, VCPU_SREG_FS); 1885 get_segment_base(vcpu, VCPU_SREG_FS);
1885 1886
1886 r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); 1887 r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
1888
1889 /* Reject the instructions other than VMCALL/VMMCALL when
1890 * try to emulate invalid opcode */
1891 c = &vcpu->arch.emulate_ctxt.decode;
1892 if ((emulation_type & EMULTYPE_TRAP_UD) &&
1893 (!(c->twobyte && c->b == 0x01 &&
1894 (c->modrm_reg == 0 || c->modrm_reg == 3) &&
1895 c->modrm_mod == 3 && c->modrm_rm == 1)))
1896 return EMULATE_FAIL;
1897
1887 ++vcpu->stat.insn_emulation; 1898 ++vcpu->stat.insn_emulation;
1888 if (r) { 1899 if (r) {
1889 ++vcpu->stat.insn_emulation_fail; 1900 ++vcpu->stat.insn_emulation_fail;
@@ -2640,7 +2651,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
2640 vcpu->mmio_read_completed = 1; 2651 vcpu->mmio_read_completed = 1;
2641 vcpu->mmio_needed = 0; 2652 vcpu->mmio_needed = 0;
2642 r = emulate_instruction(vcpu, kvm_run, 2653 r = emulate_instruction(vcpu, kvm_run,
2643 vcpu->arch.mmio_fault_cr2, 0, 1); 2654 vcpu->arch.mmio_fault_cr2, 0,
2655 EMULTYPE_NO_DECODE);
2644 if (r == EMULATE_DO_MMIO) { 2656 if (r == EMULATE_DO_MMIO) {
2645 /* 2657 /*
2646 * Read-modify-write. Back to userspace. 2658 * Read-modify-write. Back to userspace.
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 20597bc16744..4702b04b979a 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -415,8 +415,10 @@ enum emulation_result {
415 EMULATE_FAIL, /* can't emulate this instruction */ 415 EMULATE_FAIL, /* can't emulate this instruction */
416}; 416};
417 417
418#define EMULTYPE_NO_DECODE (1 << 0)
419#define EMULTYPE_TRAP_UD (1 << 1)
418int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, 420int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
419 unsigned long cr2, u16 error_code, int no_decode); 421 unsigned long cr2, u16 error_code, int emulation_type);
420void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); 422void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
421void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); 423void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
422void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); 424void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);