KVM: vmx: VMXOFF emulation in vm86 should cause #UD
[sfrench/cifs-2.6.git] / arch / x86 / kvm / emulate.c
index 56657b0bb3bb14f14b76fdcd99a746598ce5e8b4..a240fac29e769cdd02dafededd87d1219d48d976 100644 (file)
@@ -527,6 +527,7 @@ static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
 static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
                             u32 error, bool valid)
 {
+       WARN_ON(vec > 0x1f);
        ctxt->exception.vector = vec;
        ctxt->exception.error_code = error;
        ctxt->exception.error_code_valid = valid;
@@ -1468,7 +1469,7 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                return ret;
 
        err_code = selector & 0xfffc;
-       err_vec = GP_VECTOR;
+       err_vec = in_task_switch ? TS_VECTOR : GP_VECTOR;
 
        /* can't load system descriptor into segment selector */
        if (seg <= VCPU_SREG_GS && !seg_desc.s)
@@ -1491,9 +1492,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                        goto exception;
                break;
        case VCPU_SREG_CS:
-               if (in_task_switch && rpl != dpl)
-                       goto exception;
-
                if (!(seg_desc.type & 8))
                        goto exception;
 
@@ -1552,8 +1550,7 @@ load:
        ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg);
        return X86EMUL_CONTINUE;
 exception:
-       emulate_exception(ctxt, err_vec, err_code, true);
-       return X86EMUL_PROPAGATE_FAULT;
+       return emulate_exception(ctxt, err_vec, err_code, true);
 }
 
 static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
@@ -2726,8 +2723,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
        if (!next_tss_desc.p ||
            ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
             desc_limit < 0x2b)) {
-               emulate_ts(ctxt, tss_selector & 0xfffc);
-               return X86EMUL_PROPAGATE_FAULT;
+               return emulate_ts(ctxt, tss_selector & 0xfffc);
        }
 
        if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
@@ -3019,7 +3015,7 @@ static int em_movbe(struct x86_emulate_ctxt *ctxt)
                ctxt->dst.val = swab64(ctxt->src.val);
                break;
        default:
-               return X86EMUL_PROPAGATE_FAULT;
+               BUG();
        }
        return X86EMUL_CONTINUE;
 }
@@ -3143,12 +3139,8 @@ static int em_clts(struct x86_emulate_ctxt *ctxt)
 
 static int em_vmcall(struct x86_emulate_ctxt *ctxt)
 {
-       int rc;
+       int rc = ctxt->ops->fix_hypercall(ctxt);
 
-       if (ctxt->modrm_mod != 3 || ctxt->modrm_rm != 1)
-               return X86EMUL_UNHANDLEABLE;
-
-       rc = ctxt->ops->fix_hypercall(ctxt);
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
@@ -3566,6 +3558,12 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt)
                F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e),     \
                F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e)
 
+static const struct opcode group7_rm0[] = {
+       N,
+       I(SrcNone | Priv | EmulateOnUD, em_vmcall),
+       N, N, N, N, N, N,
+};
+
 static const struct opcode group7_rm1[] = {
        DI(SrcNone | Priv, monitor),
        DI(SrcNone | Priv, mwait),
@@ -3659,7 +3657,7 @@ static const struct group_dual group7 = { {
        II(SrcMem16 | Mov | Priv,               em_lmsw, lmsw),
        II(SrcMem | ByteOp | Priv | NoAccess,   em_invlpg, invlpg),
 }, {
-       I(SrcNone | Priv | EmulateOnUD, em_vmcall),
+       EXT(0, group7_rm0),
        EXT(0, group7_rm1),
        N, EXT(0, group7_rm3),
        II(SrcNone | DstMem | Mov,              em_smsw, smsw), N,
@@ -4394,8 +4392,11 @@ done_prefixes:
 
        ctxt->execute = opcode.u.execute;
 
+       if (unlikely(ctxt->ud) && likely(!(ctxt->d & EmulateOnUD)))
+               return EMULATION_FAILED;
+
        if (unlikely(ctxt->d &
-                    (NotImpl|EmulateOnUD|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
+                    (NotImpl|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
                /*
                 * These are copied unconditionally here, and checked unconditionally
                 * in x86_emulate_insn.
@@ -4406,9 +4407,6 @@ done_prefixes:
                if (ctxt->d & NotImpl)
                        return EMULATION_FAILED;
 
-               if (!(ctxt->d & EmulateOnUD) && ctxt->ud)
-                       return EMULATION_FAILED;
-
                if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
                        ctxt->op_bytes = 8;
 
@@ -4832,8 +4830,10 @@ writeback:
        ctxt->eip = ctxt->_eip;
 
 done:
-       if (rc == X86EMUL_PROPAGATE_FAULT)
+       if (rc == X86EMUL_PROPAGATE_FAULT) {
+               WARN_ON(ctxt->exception.vector > 0x1f);
                ctxt->have_exception = true;
+       }
        if (rc == X86EMUL_INTERCEPTED)
                return EMULATION_INTERCEPTED;