Re: [Question] int3 instruction generates a #UD in SEV VM

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 8/2/23 10:04, Sean Christopherson wrote:
On Wed, Aug 02, 2023, Tom Lendacky wrote:
On 8/2/23 09:25, Tom Lendacky wrote:
On 8/2/23 09:01, Sean Christopherson wrote:
You're right. The #UD is injected by KVM.

The path I found is:
      svm_vcpu_run
          svm_complete_interrupts
         kvm_requeue_exception // vector = 3
             kvm_make_request

      vcpu_enter_guest
          kvm_check_and_inject_events
         svm_inject_exception
             svm_update_soft_interrupt_rip
             __svm_skip_emulated_instruction
                 x86_emulate_instruction
                 svm_can_emulate_instruction
                     kvm_queue_exception(vcpu, UD_VECTOR)

Does this mean a #PF intercept occur when the guest try to deliver a
#BP through the IDT? But why?

I doubt it's a #PF.  A #NPF is much more likely, though it could be
something
else entirely, but I'm pretty sure that would require bugs in both
the host and
guest.

What is the last exit recorded by trace_kvm_exit() before the #UD is
injected?

I'm guessing it was a #NPF, too. Could it be related to the changes that
went in around svm_update_soft_interrupt_rip()?

6ef88d6e36c2 ("KVM: SVM: Re-inject INT3/INTO instead of retrying the
instruction")

Sorry, that should have been:

7e5b5ef8dca3 ("KVM: SVM: Re-inject INTn instead of retrying the insn on "failure"")


Before this the !nrips check would prevent the call into
svm_skip_emulated_instruction(). But now, there is a call to:

    svm_update_soft_interrupt_rip()
      __svm_skip_emulated_instruction()
        kvm_emulate_instruction()
          x86_emulate_instruction() (passed a NULL insn pointer)
            kvm_can_emulate_insn() (passed a NULL insn pointer)
              svm_can_emulate_instruction() (passed NULL insn pointer)

Because it is an SEV guest, it ends up in the "if (unlikely(!insn))" path
and injects the #UD.

Yeah, my money is on that too.  I believe this is the least awful solution:

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d381ad424554..2eace114a934 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -385,6 +385,9 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu,
         }
if (!svm->next_rip) {
+               if (sev_guest(vcpu->kvm))
+                       return 0;
+
                 if (unlikely(!commit_side_effects))
                         old_rflags = svm->vmcb->save.rflags;
I'll send a formal patch (with a comment) if that solves the problem.


Side topic, KVM should require nrips for SEV and beyond, I don't see how SEV can
possibly work if KVM doesn't utilize nrips.  E.g. this

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 2eace114a934..43e500503d48 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -5111,9 +5111,11 @@ static __init int svm_hardware_setup(void)
svm_adjust_mmio_mask(); + nrips = nrips && boot_cpu_has(X86_FEATURE_NRIPS);
+
         /*
          * Note, SEV setup consumes npt_enabled and enable_mmio_caching (which
-        * may be modified by svm_adjust_mmio_mask()).
+        * may be modified by svm_adjust_mmio_mask()), as well as nrips.
          */
         sev_hardware_setup();

You moved the setting of nrips up, I'm assuming you then want to add a check in sev_hardware_setup() for nrips?

Thanks,
Tom

@@ -5125,11 +5127,6 @@ static __init int svm_hardware_setup(void)
                         goto err;
         }
- if (nrips) {
-               if (!boot_cpu_has(X86_FEATURE_NRIPS))
-                       nrips = false;
-       }
-
         enable_apicv = avic = avic && avic_hardware_setup();
if (!enable_apicv) {




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux