aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
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 /arch/x86
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>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kvm/svm.c2
-rw-r--r--arch/x86/kvm/vmx.c2
-rw-r--r--arch/x86/kvm/x86.c18
3 files changed, 17 insertions, 5 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.