All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: syzbot <syzbot+760a73552f47a8cd0fd9@syzkaller.appspotmail.com>,
	Gleb Natapov <gleb@redhat.com>, Avi Kivity <avi@redhat.com>,
	syzkaller-bugs@googlegroups.com, "H. Peter Anvin" <hpa@zytor.com>,
	kvm <kvm@vger.kernel.org>, Ingo Molnar <mingo@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Radim Krcmar <rkrcmar@redhat.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	the arch/x86 maintainers <x86@kernel.org>,
	Wanpeng Li <kernellwp@gmail.com>
Subject: Re: WARNING in kvm_arch_vcpu_ioctl_run (3)
Date: Mon, 27 Jun 2022 20:08:39 +0000	[thread overview]
Message-ID: <YroOR4Qky66yqO7P@google.com> (raw)
In-Reply-To: <e3a1a213-ea9f-dbd8-93be-74e927794090@I-love.SAKURA.ne.jp>

On Wed, Jun 22, 2022, Tetsuo Handa wrote:
> On 2018/03/28 16:29, Wanpeng Li wrote:
> >> syzbot dashboard link:
> >> https://syzkaller.appspot.com/bug?extid=760a73552f47a8cd0fd9
> >>
> > Maybe the same as this one. https://lkml.org/lkml/2018/3/21/174 Paolo,
> > any idea against my analysis?
> 
> No progress for 4 years. Did somebody check Wanpeng's analysis ?

The most recent failure is a different bug, the splat Wanpeng debugged requires
unrestricted guest to be disabled, whereas this does not.  Somewhat of a side
topic, if the old bug still exists (the syzkaller reproducer fails with invalid
guest state, so it's not clear whether or not the bug is still a problem),
I suspect this hack-a-fix would handle the Real Mode injection case:

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 735543df829a..58801d3888c8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8209,7 +8209,7 @@ void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip)
        ctxt->_eip = ctxt->eip + inc_eip;
        ret = emulate_int_real(ctxt, irq);

-       if (ret != X86EMUL_CONTINUE) {
+       if (ret != X86EMUL_CONTINUE || vcpu->mmio_needed) {
                kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
        } else {
                ctxt->eip = ctxt->_eip;

If I ever have time and/or get bored, I'll try to repro the realmode bug unless
someone beats me to it.

> Since I'm not familiar with KVM, my questions from different direction...
> 
> 
> 
> syzbot is hitting WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed) added by
> commit 716d51abff06f484 ("KVM: Provide userspace IO exit completion callback")
> due to vcpu->mmio_needed == true.
> 
> Question 1: what is the intent of checking for vcpu->mmio_needed == false?

It's a sanity check to detect KVM bugs.  If vcpu->mmio_needed is true, KVM needs
to exit to userspace to complete the MMIO operation.  On that exit to userspace,
KVM is supposed to also set a callback to essentially acknowledge that the MMIO
completed.

The issue in this bug is that after setting vcpu->mmio_needed, KVM detects and
injects an exception.  Because of how KVM handles MMIO, unlike MMIO reads, MMIO
writes don't immediately stop emulation.  While odd, it should work because MMIO
writes shouldn't be processed until after all fault checks have passed.  The
underlying bug is that LTR emulation has incorrect ordering and checks for a
non-canonical base _after_ marking the TSS as busy (which triggers MMIO).

So as much as I want to suppress this type of warn by clearing vcpu->mmio_needed
when injecting an exception, I suspect playing whack-a-mole is the right approach
because all those moles are likely bugs :-(  Though one thing we can do is change
the WARN_ON() to a WARN_ON_ONCE() so that kernels outside of panic_on_warn=1 won't
blow up on a buggy/malicious userspace.

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 39ea9138224c..09e4b67b881f 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1699,16 +1699,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
        case VCPU_SREG_TR:
                if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
                        goto exception;
-               if (!seg_desc.p) {
-                       err_vec = NP_VECTOR;
-                       goto exception;
-               }
-               old_desc = seg_desc;
-               seg_desc.type |= 2; /* busy */
-               ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc,
-                                                 sizeof(seg_desc), &ctxt->exception);
-               if (ret != X86EMUL_CONTINUE)
-                       return ret;
                break;
        case VCPU_SREG_LDTR:
                if (seg_desc.s || seg_desc.type != 2)
@@ -1749,6 +1739,15 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                                ((u64)base3 << 32), ctxt))
                        return emulate_gp(ctxt, 0);
        }
+
+       if (seg == VCPU_SREG_TR) {
+               old_desc = seg_desc;
+               seg_desc.type |= 2; /* busy */
+               ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc,
+                                                 sizeof(seg_desc), &ctxt->exception);
+               if (ret != X86EMUL_CONTINUE)
+                       return ret;
+       }
 load:
        ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg);
        if (desc)


> If we run a reproducer provided by syzbot, we can observe that mutex_unlock(&vcpu->mutex)
> in kvm_vcpu_ioctl() is called with vcpu->mmio_needed == true.
> 
> Question 2: Is kvm_vcpu_ioctl() supposed to leave with vcpu->mmio_needed == false?
> In other words, is doing
> 
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -4104,6 +4104,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
>  		r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
>  	}
>  out:
> +	WARN_ON_ONCE(vcpu->mmio_needed);
>  	mutex_unlock(&vcpu->mutex);
>  	kfree(fpu);
>  	kfree(kvm_sregs);
> 
> appropriate?

It's not appropriate, mmio_needed is actually supposed to be accompanied by a
exit from kvm_vcpu_ioctl() to userspace.

  reply	other threads:[~2022-06-27 20:08 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-28  7:13 WARNING in kvm_arch_vcpu_ioctl_run (3) syzbot
2018-03-28  7:29 ` Wanpeng Li
2022-06-22  2:46   ` Tetsuo Handa
2022-06-27 20:08     ` Sean Christopherson [this message]
2018-10-02 21:07 ` syzbot
2019-04-14 11:06 ` syzbot
2019-06-17  2:55 ` syzbot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YroOR4Qky66yqO7P@google.com \
    --to=seanjc@google.com \
    --cc=avi@redhat.com \
    --cc=gleb@redhat.com \
    --cc=hpa@zytor.com \
    --cc=kernellwp@gmail.com \
    --cc=kvm@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=penguin-kernel@i-love.sakura.ne.jp \
    --cc=rkrcmar@redhat.com \
    --cc=syzbot+760a73552f47a8cd0fd9@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.