From: mike.malyshev@gmail.com
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, tglx@kernel.org, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
"H. Peter Anvin" <hpa@zytor.com>,
Mikhail Malyshev <mike.malyshev@gmail.com>
Subject: [PATCH 0/1] KVM: x86/mmu: don't kill the VM on access to a disabled passthrough BAR
Date: Sun, 21 Jun 2026 13:37:07 +0000 [thread overview]
Message-ID: <20260621133708.3454718-1-mike.malyshev@gmail.com> (raw)
From: Mikhail Malyshev <mike.malyshev@gmail.com>
A guest with an assigned PCI device can crash its own VM by toggling
PCI_COMMAND.MEM on that device while another vCPU accesses the device's
BAR. KVM_RUN returns -EFAULT, which userspace (QEMU) treats as fatal.
This is a guest-triggerable, host-side VM kill, so I think it is worth
addressing in KVM rather than papering over it in userspace.
The window
==========
A passed-through BAR is mapped into the guest via a VM_IO/VM_PFNMAP VMA
whose fault handler (vfio_pci_mmap_fault()) refuses to install a PTE while
the device's memory space is disabled. When the guest clears
PCI_COMMAND.MEM:
- the kernel vfio config-write path zaps the BAR's userspace mapping;
- userspace's memory listener later removes the corresponding KVM
memslot.
A vCPU that faults on the BAR in the window after the mapping is zapped but
before the memslot is removed lands in the page fault path with a *valid*
memslot but a backing whose fault handler declines. hva_to_pfn_remapped()
returns an error, the gfn resolves to KVM_PFN_ERR_FAULT, and
kvm_handle_error_pfn() returns -EFAULT.
On bare metal the same access is an Unsupported Request (reads all ones,
writes dropped), not a fatal error. This series makes KVM emulate the
access as MMIO in that case, matching hardware, while leaving genuine
faults (e.g. a vanished anonymous backing, vma == NULL) returning -EFAULT
as before -- consistent with what tools/testing/selftests/kvm/
mmu_stress_test.c already asserts.
How it was found / confirmed
============================
The crash was originally hit in production on edge devices that pass an
Intel iGPU (Raptor Lake-P) through to a guest; the guest's display driver
clears PCI_COMMAND.MEM on one vCPU while another vCPU is mid-MMIO to BAR0.
To study it deterministically I built a reduced, hardware-light reproducer
(no specific guest OS required, the race is host-side):
- a Linux guest with any assigned PCI device whose BAR0 is mmap'd from
userspace (/sys/.../resource0) and hammered with a tight MMIO write
loop on one vCPU;
- a second thread that toggles PCI_COMMAND.MEM 1->0->1 on that device
via the VFIO config region.
Without this patch the VM dies within ~1 s. eBPF on the fault path showed
the -EFAULT originating in the faultin path (kvm_mmu_faultin_pfn ->
kvm_handle_error_pfn) with the memslot valid (flags=0, not
KVM_MEMSLOT_INVALID), no mmu_notifier invalidation in progress, and the
pfn equal to the GUP-error value -- i.e. the VM_PFNMAP fault handler
declining, exactly the case this patch targets. (An earlier attempt to
treat it as a stale-mapping race and retry on mmu_invalidate_retry_gfn()
did not help, because by the time of the fault the invalidation has
already completed and the seq is stable; that confirmed the failure is a
steady-state "device decoding disabled" condition, not a transient
invalidation, and led to the MMIO approach here.)
With the patch the same reproducer survived 200k toggle cycles, and a
fleet of 17 devices ran 48h with no recurrence.
Open questions for reviewers
============================
- hva_to_pfn_remapped() can in principle return an error for reasons
other than "fault handler declined" (e.g. an OOM from
fixup_user_fault()). Treating all of them as MMIO is what this patch
does for simplicity; I can instead plumb the specific condition through
if you'd prefer to narrow it.
- I could not find a clean way to add a selftest: a faithful regression
test needs a VM_PFNMAP backing whose fault handler can be toggled,
which from pure userspace means /dev/mem or a real assigned device
(neither CI-portable), or a dedicated test module (outside selftests).
Guidance on the preferred shape would be welcome.
Mikhail Malyshev (1):
KVM: x86/mmu: Emulate, don't kill the VM, on access to a disabled
passthrough BAR
arch/x86/kvm/mmu/mmu.c | 16 +++++++++++++++-
include/linux/kvm_host.h | 8 ++++++++
virt/kvm/kvm_main.c | 9 ++++++++-
3 files changed, 31 insertions(+), 2 deletions(-)
--
2.43.0
next reply other threads:[~2026-06-21 13:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-21 13:37 mike.malyshev [this message]
2026-06-21 13:37 ` [PATCH 1/1] KVM: x86/mmu: Emulate, don't kill the VM, " mike.malyshev
2026-06-22 23:23 ` Sean Christopherson
2026-06-23 11:46 ` Mikhail Malyshev
2026-06-25 16:21 ` Sean Christopherson
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=20260621133708.3454718-1-mike.malyshev@gmail.com \
--to=mike.malyshev@gmail.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=tglx@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox