KVM: x86/emulator: Move the unhandled outer privilege level logic of far return into...
authorHou Wenlong <houwenlong.hwl@antgroup.com>
Tue, 8 Feb 2022 09:34:05 +0000 (17:34 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 1 Mar 2022 13:50:49 +0000 (08:50 -0500)
Outer-privilege level return is not implemented in emulator,
move the unhandled logic into __load_segment_descriptor to
make it easier to understand why the checks for RET are
incomplete.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
Message-Id: <5b7188e6388ac9f4567d14eab32db9adf3e00119.1644292363.git.houwenlong.hwl@antgroup.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/emulate.c

index 35e69c2..a60b4d2 100644 (file)
@@ -1623,9 +1623,14 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                if (!(seg_desc.type & 8))
                        goto exception;
 
-               /* RET can never return to an inner privilege level. */
-               if (transfer == X86_TRANSFER_RET && rpl < cpl)
-                       goto exception;
+               if (transfer == X86_TRANSFER_RET) {
+                       /* RET can never return to an inner privilege level. */
+                       if (rpl < cpl)
+                               goto exception;
+                       /* Outer-privilege level return is not implemented */
+                       if (rpl > cpl)
+                               return X86EMUL_UNHANDLEABLE;
+               }
                if (transfer == X86_TRANSFER_RET || transfer == X86_TRANSFER_TASK_SWITCH) {
                        if (seg_desc.type & 4) {
                                /* conforming */
@@ -2220,9 +2225,6 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
        rc = emulate_pop(ctxt, &cs, ctxt->op_bytes);
        if (rc != X86EMUL_CONTINUE)
                return rc;
-       /* Outer-privilege level return is not implemented */
-       if (ctxt->mode >= X86EMUL_MODE_PROT16 && (cs & 3) > cpl)
-               return X86EMUL_UNHANDLEABLE;
        rc = __load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS, cpl,
                                       X86_TRANSFER_RET,
                                       &new_desc);