mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: David Woodhouse <dwmw2@infradead.org>
To: "Jörg Rödel" <joro@8bytes.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	ashish.kalra@amd.com, michael.roth@amd.com, nsaenz@amazon.com,
	anelkz@amazon.de, James.Bottomley@HansenPartnership.com,
	Melody Wang <huibo.wang@amd.com>,
	kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	kvmarm@lists.linux.dev, loongarch@lists.linux.dev,
	linux-mips@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	kvm-riscv@lists.infradead.org, x86@kernel.org,
	coconut-svsm@lists.linux.dev, joerg.roedel@amd.com,
	Mushahid Hussain <hmushi@amazon.co.uk>,
	Sriram Nambakam <snambakam@linux.microsoft.com>,
	David Woodhouse <dwmw@amazon.co.uk>
Subject: [PATCH 10/16] KVM: planes: Keep current_vcpu in sync in vcpu_load()
Date: Wed, 11 Nov 2026 14:29:05 -0800	[thread overview]
Message-ID: <20261111222911.477-11-dwmw2@infradead.org> (raw)
In-Reply-To: <20261111222911.477-1-dwmw2@infradead.org>

From: David Woodhouse <dwmw@amazon.co.uk>

The preempt notifiers save and restore common->current_vcpu
(kvm_sched_out()/kvm_sched_in()), but vcpu_load() does not update it.

An ioctl on a plane-N fd loads that plane's vCPU while current_vcpu
may still name the plane that ran last. A reschedule inside the ioctl
then arch-puts the stale twin, whose state is not resident, and
arch-loads it back over the state the ioctl made resident: on VMX the
ioctl's VMCS writes land in the other plane's VMCS, and the trailing
vcpu_put() unloads a non-resident vCPU, corrupting the per-pCPU
loaded_vmcs tracking. The kick paths read current_vcpu->cpu too, and
the next patch, which swaps each twin in around its update after
KVM_SET_CPUID2, relies on the loaded vCPU being the one the preempt
notifiers see.

Set common->current_vcpu in vcpu_load(), so every load path (the run
loop and vCPU ioctls on any plane's fd) agrees with what the preempt
notifiers will operate on. kvm_vcpu_select_plane() keeps its own
assignment; both stores use WRITE_ONCE() to pair with the lock-free
readers in the kick paths.

That makes twin creation a writer as well: kvm_arch_vcpu_create()
calls vcpu_load() on the new twin while its plane-0 twin may be in
KVM_RUN on another pCPU, and the shared preempt notifier would be
registered twice. Hold the shared vCPU mutex across creation of a
non-zero plane's vCPU, from before kvm_arch_vcpu_create() to the end,
including the error-path kvm_arch_vcpu_destroy(), which can
vcpu_load() too (nested_vmx_free_vcpu()). Since vcpu_put() leaves
current_vcpu naming the new twin, put back the twin that owned it once
the arch code returns, on success and on every failure path; otherwise
a failed creation (create_vcpu_fd() can be made to fail with
RLIMIT_NOFILE) frees a vCPU that the lock-free kick paths still
dereference.

Found by a local Sashiko review.

Fixes the current_vcpu tracking in "kvm: Move VCPU scheduling state to
struct kvm_vcpu_common".

Fixes: https://lore.kernel.org/all/20260608144252.351443-16-joro@8bytes.org/
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 virt/kvm/kvm_main.c | 54 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 24d2291b60a2..b6bdbe5c5133 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -174,6 +174,16 @@ void vcpu_load(struct kvm_vcpu *vcpu)
 {
 	int cpu = get_cpu();
 
+	/*
+	 * The preempt notifiers operate on common->current_vcpu, so it
+	 * must name the plane vCPU being loaded here: an ioctl taken on
+	 * another plane's fd than the one that ran last would otherwise
+	 * have a preemption arch-put the stale twin (whose state is not
+	 * resident) and arch-load it back over the state this load makes
+	 * resident.  The kick paths also read it to find the running
+	 * twin's pCPU.
+	 */
+	WRITE_ONCE(vcpu->common->current_vcpu, vcpu);
 	__this_cpu_write(kvm_running_vcpu, vcpu->common);
 	preempt_notifier_register(&vcpu->common->preempt_notifier);
 	kvm_arch_vcpu_load(vcpu, cpu);
@@ -4470,7 +4480,7 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu)
 static int kvm_plane_ioctl_create_vcpu(struct kvm_plane *plane, unsigned long id)
 {
 	struct kvm *kvm = plane->kvm;
-	struct kvm_vcpu *vcpu;
+	struct kvm_vcpu *vcpu, *prev = NULL;
 	int r;
 
 	guard(mutex)(&kvm->lock);
@@ -4513,9 +4523,34 @@ static int kvm_plane_ioctl_create_vcpu(struct kvm_plane *plane, unsigned long id
 
 	kvm_vcpu_init(vcpu, kvm, id);
 
+	/*
+	 * A non-zero plane shares 'common' with a plane-0 twin which may
+	 * already be running.  kvm_arch_vcpu_create() calls vcpu_load(),
+	 * which publishes the half-created vCPU through
+	 * common->current_vcpu and registers the shared preempt notifier,
+	 * so it must not run concurrently with a twin's KVM_RUN: hold the
+	 * shared vCPU mutex from here to the end of creation, including
+	 * the error-path kvm_arch_vcpu_destroy(), which can vcpu_load()
+	 * too (nested VMX teardown).  It nests inside the kvm->lock held
+	 * for all of vCPU creation, the usual kvm->lock -> vcpu mutex order.
+	 *
+	 * vcpu_put() leaves current_vcpu naming the new twin; put back
+	 * the twin that owned it, so that the lock-free kick paths never
+	 * see a vCPU that is not reachable yet, or that a failed creation
+	 * frees.
+	 */
+	if (plane->level > 0) {
+		r = mutex_lock_killable(kvm_vcpu_mutex(vcpu));
+		if (r)
+			goto vcpu_free_common;
+		prev = vcpu->common->current_vcpu;
+	}
+
 	r = kvm_arch_vcpu_create(vcpu);
+	if (plane->level > 0)
+		WRITE_ONCE(vcpu->common->current_vcpu, prev);
 	if (r)
-		goto vcpu_free_common;
+		goto unlock_vcpu_free_common;
 
 	/*
 	 * Set the vCPU's index *before* the vCPU is reachable by other tasks.
@@ -4534,9 +4569,10 @@ static int kvm_plane_ioctl_create_vcpu(struct kvm_plane *plane, unsigned long id
 	 * visible (per online_vcpus), e.g. so that KVM doesn't get tricked
 	 * into a NULL-pointer dereference because KVM thinks the _current_
 	 * vCPU doesn't exist.  As a bonus, taking vcpu->mutex ensures lockdep
-	 * knows it's taken *inside* kvm->lock.
+	 * knows it's taken *inside* kvm->lock.  A twin holds it already.
 	 */
-	kvm_vcpu_lock(vcpu);
+	if (!plane->level)
+		kvm_vcpu_lock(vcpu);
 	kvm_get_kvm(kvm);
 	r = create_vcpu_fd(vcpu);
 	if (r < 0)
@@ -4550,12 +4586,18 @@ static int kvm_plane_ioctl_create_vcpu(struct kvm_plane *plane, unsigned long id
 	return r;
 
 kvm_put_xa_erase:
-	kvm_vcpu_unlock(vcpu);
+	if (!plane->level)
+		kvm_vcpu_unlock(vcpu);
 	kvm_put_kvm_no_destroy(kvm);
 	xa_erase(&plane->vcpu_array, vcpu->vcpu_idx);
 unlock_vcpu_destroy:
 	vcpu->vcpu_idx = -1;
 	kvm_arch_vcpu_destroy(vcpu);
+	if (plane->level > 0)
+		WRITE_ONCE(vcpu->common->current_vcpu, prev);
+unlock_vcpu_free_common:
+	if (plane->level > 0)
+		kvm_vcpu_unlock(vcpu);
 vcpu_free_common:
 	kvm_vcpu_common_destroy(vcpu);
 vcpu_free:
@@ -5136,7 +5178,7 @@ struct kvm_vcpu *kvm_vcpu_select_plane(struct kvm_vcpu *vcpu)
 		ret->plane_state = RUNNABLE;
 	}
 
-	common->current_vcpu = ret;
+	WRITE_ONCE(common->current_vcpu, ret);
 
 	common->plane_switch = false;
 
-- 
2.50.1


  parent reply	other threads:[~2026-11-11 22:29 UTC|newest]

Thread overview: 97+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08 14:41 [PATCH 00/60] KVM Planes + SEV-SNP Support Jörg Rödel
2026-06-08 14:41 ` [PATCH 01/60] x86/sev: Define the #HV doorbell page structure Jörg Rödel
2026-06-08 14:41 ` [PATCH 02/60] KVM: SVM: Add support for the SEV-SNP #HV doorbell page NAE event Jörg Rödel
2026-06-10 13:28   ` Tom Lendacky
2026-06-10 15:05     ` Tom Lendacky
2026-06-08 14:41 ` [PATCH 03/60] KVM: SVM: Inject #HV when Restricted Injection is active Jörg Rödel
2026-06-08 14:41 ` [PATCH 04/60] KVM: SVM: Inject NMIs " Jörg Rödel
2026-06-08 14:41 ` [PATCH 05/60] KVM: SVM: Inject MCEs " Jörg Rödel
2026-06-08 14:41 ` [PATCH 06/60] KVM: SVM: Enable Restricted Injection for an SEV-SNP guest Jörg Rödel
2026-06-08 14:41 ` [PATCH 07/60] KVM: SVM: Add support for the SEV-SNP #HV IPI NAE event Jörg Rödel
2026-06-10 13:45   ` Tom Lendacky
2026-06-08 14:42 ` [PATCH 08/60] Documentation: kvm: introduce "VM plane" concept Jörg Rödel
2026-06-08 14:42 ` [PATCH 09/60] kvm: Introduce struct kvm_plane Jörg Rödel
2026-06-08 14:42 ` [PATCH 10/60] kvm: Move vcpu_array to " Jörg Rödel
2026-06-08 14:42 ` [PATCH 11/60] kvm: Introduce struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 12/60] kvm: Move vcpu accounting to " Jörg Rödel
2026-06-08 14:42 ` [PATCH 13/60] kvm: Add read accessors for kvm_vcpu scheduling state Jörg Rödel
2026-06-08 14:42 ` [PATCH 14/60] kvm: Make kvm_running_vcpus point to struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 15/60] kvm: Move VCPU scheduling state " Jörg Rödel
2026-06-08 14:42 ` [PATCH 16/60] kvm: Add accessors for kvm_vcpu->mutex Jörg Rödel
2026-06-08 14:42 ` [PATCH 17/60] kvm: Move VCPU locking to struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 18/60] kvm: Move kvm_vcpu->rcuwait " Jörg Rödel
2026-06-08 14:42 ` [PATCH 19/60] kvm: Introduce accessors for kvm_vcpu->mode Jörg Rödel
2026-06-08 14:42 ` [PATCH 20/60] kvm: Move kvm_vcpu mode and requests field to struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 21/60] kvm: Introduce per-plane VCPU requests Jörg Rödel
2026-06-08 14:42 ` [PATCH 22/60] kvm: Move kvm_vcpu pid members to struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 23/60] kvm: Move kvm_vcpu sigset " Jörg Rödel
2026-06-08 14:42 ` [PATCH 24/60] kvm: Move kvm_vcpu spinloop " Jörg Rödel
2026-06-08 14:42 ` [PATCH 25/60] kvm: Move kvm_vcpu->dirty_ring " Jörg Rödel
2026-06-08 14:42 ` [PATCH 26/60] kvm: Introduce arch-specific plane state Jörg Rödel
2026-06-08 14:42 ` [PATCH 27/60] kvm: Introduce arch-specific part of struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 28/60] kvm: Implement KVM_CAP_PLANES Jörg Rödel
2026-06-08 14:42 ` [PATCH 29/60] kvm: Implement KVM_CREATE_PLANE ioctl Jörg Rödel
2026-09-11 17:54   ` Serge Hallyn
2026-06-08 14:42 ` [PATCH 30/60] kvm: Add KVM_EXIT_PLANE_EVENT Jörg Rödel
2026-06-08 14:42 ` [PATCH 31/60] kvm: Allocate struct kvm_plane in architecture code Jörg Rödel
2026-06-08 14:42 ` [PATCH 32/60] kvm: Allocate struct kvm_run only for struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 33/60] KVM: Implement KVM_CREATE_VCPU ioctl for planes Jörg Rödel
2026-06-08 14:42 ` [PATCH 34/60] kvm: Keep track of plane VCPUs in struct kvm_vcpu_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 35/60] kvm: Add VCPU plane-scheduling state and helpers Jörg Rödel
2026-06-08 16:47   ` Paolo Bonzini
2026-06-08 17:52     ` Jörg Rödel
2026-06-08 17:58       ` Paolo Bonzini
2026-06-09 12:37         ` Jörg Rödel
2026-06-09 12:59           ` James Bottomley
2026-06-09 14:27             ` Jörg Rödel
2026-06-09 15:06               ` James Bottomley
2026-07-17 13:48           ` Saenz Julienne, Nicolas
2026-07-17 15:56             ` James Bottomley
2026-07-17 17:33               ` Saenz Julienne, Nicolas
2026-07-17 18:26                 ` James Bottomley
2026-07-17 14:35           ` James Bottomley
2026-09-24 14:10             ` Jörg Rödel
2026-06-08 14:42 ` [PATCH 36/60] kvm: Add plane_level to kvm_kernel_irq_routing_entry Jörg Rödel
2026-06-08 14:42 ` [PATCH 37/60] kvm: Pass plane_level to kvm_set_routing_entry() Jörg Rödel
2026-06-08 14:42 ` [PATCH 38/60] kvm: Make KVM_SIGNAL_MSI per plane Jörg Rödel
2026-06-08 14:42 ` [PATCH 39/60] kvm: Make KVM_SET_GSI_ROUTING " Jörg Rödel
2026-06-08 14:42 ` [PATCH 40/60] kvm: x86: Handle IOAPIC EOIs " Jörg Rödel
2026-06-08 14:42 ` [PATCH 41/60] kvm: x86: Make apic_map " Jörg Rödel
2026-06-08 14:42 ` [PATCH 42/60] kvm: x86: Make local APIC code aware of planes Jörg Rödel
2026-06-08 14:42 ` [PATCH 43/60] kvm: x86: Move CPUID state to struct kvm_vcpu_arch_common Jörg Rödel
2026-06-08 14:42 ` [PATCH 44/60] kvm: x86: Move cpu_caps " Jörg Rödel
2026-06-08 14:42 ` [PATCH 45/60] kvm: x86: Update state for all plane VCPUs after CPUID update Jörg Rödel
2026-06-08 14:42 ` [PATCH 46/60] kvm: x86: Share MTRR state across planes Jörg Rödel
2026-06-08 14:42 ` [PATCH 47/60] kvm: x86: Select a plane to run Jörg Rödel
2026-06-08 14:42 ` [PATCH 48/60] kvm: x86: Make event injection VCPU requests per-plane Jörg Rödel
2026-06-08 14:42 ` [PATCH 49/60] kvm: x86: Allow hardware backend to overwrite struct kvm_plane allocation Jörg Rödel
2026-06-08 14:42 ` [PATCH 50/60] kvm: x86: Make KVM_REQ_UPDATE_PROTECTED_GUEST_STATE per plane Jörg Rödel
2026-06-08 14:42 ` [PATCH 51/60] kvm: x86: Share pio_data across planes Jörg Rödel
2026-06-08 14:42 ` [PATCH 52/60] kvm: x86: Switch to plane0 if it has events Jörg Rödel
2026-06-08 14:42 ` [PATCH 53/60] kvm: x86: Introduce max_planes x86-op Jörg Rödel
2026-06-08 14:42 ` [PATCH 54/60] kvm: x86: Restrict KVM planes support to KVM_IRQCHIP_SPLIT Jörg Rödel
2026-06-08 14:42 ` [PATCH 55/60] kvm: svm: Track vmsa_features per plane Jörg Rödel
2026-06-08 14:42 ` [PATCH 56/60] kvm: svm: Implement GET_AP_APIC_IDS NAE event Jörg Rödel
2026-06-08 14:42 ` [PATCH 57/60] kvm: sev: Allow for VMPL level specification in AP create Jörg Rödel
2026-06-08 14:42 ` [PATCH 58/60] kvm: svm: Invoke a specified VMPL level VMSA for the vCPU Jörg Rödel
2026-06-08 14:42 ` [PATCH 59/60] kvm: svm: Implement max_planes x86 operation Jörg Rödel
2026-06-08 14:42 ` [PATCH 60/60] kvm: svm: Advertise full multi-VMPL support to the SNP guest Jörg Rödel
2026-06-09  9:29 ` [syzbot ci] Re: KVM Planes + SEV-SNP Support syzbot ci
2026-06-10 18:13 ` [PATCH 00/60] " Melody Wang
2026-11-11 22:28 ` [PATCH 00/16] KVM: Fixes for the Planes + SEV-SNP series David Woodhouse
2026-11-11 22:28   ` [PATCH 01/16] KVM: s390: arm64: Pass plane_level to the kvm_set_routing_entry() stub David Woodhouse
2026-11-11 22:28   ` [PATCH 02/16] KVM: SVM: Derive the plane limit from the immutable VM type David Woodhouse
2026-11-11 22:28   ` [PATCH 03/16] KVM: planes: Report KVM_MAX_PLANES from the system fd David Woodhouse
2026-11-11 22:28   ` [PATCH 04/16] KVM: Guard the per-plane KVM_SIGNAL_MSI cases with __KVM_HAVE_MSI David Woodhouse
2026-11-11 22:29   ` [PATCH 05/16] KVM: x86: Initialise Hyper-V state on every plane vCPU David Woodhouse
2026-11-11 22:29   ` [PATCH 06/16] KVM: x86: Widen the plane vCPU fd ioctl allowlist David Woodhouse
2026-11-11 22:29   ` [PATCH 07/16] KVM: x86/mmu: Free obsolete roots of all planes David Woodhouse
2026-11-11 22:29   ` [PATCH 08/16] KVM: planes: Publish a new plane only once KVM_CREATE_PLANE cannot fail David Woodhouse
2026-11-11 22:29   ` [PATCH 09/16] KVM: planes: Kick the running twin's pCPU, not the request target's David Woodhouse
2026-11-11 22:29   ` David Woodhouse [this message]
2026-11-11 22:29   ` [PATCH 11/16] KVM: x86: Load each plane twin while updating it after KVM_SET_CPUID David Woodhouse
2026-11-11 22:29   ` [PATCH 12/16] KVM: VMX: Leave the IPIv PID-table entry to the plane 0 vCPU David Woodhouse
2026-11-11 22:29   ` [PATCH 13/16] KVM: x86: Leave TSC matching to the plane 0 vCPUs David Woodhouse
2026-11-11 22:29   ` [PATCH 14/16] KVM: x86: Derive runtime CPUID bits from the executing plane David Woodhouse
2026-11-11 22:29   ` [PATCH 15/16] KVM: planes: Annotate the lockless twin-publication protocol David Woodhouse
2026-11-11 22:29   ` [PATCH 16/16] KVM: SVM: Make KVM_REQ_VMSA_PAGE_RELOAD per plane David Woodhouse

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=20261111222911.477-11-dwmw2@infradead.org \
    --to=dwmw2@infradead.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=anelkz@amazon.de \
    --cc=ashish.kalra@amd.com \
    --cc=coconut-svsm@lists.linux.dev \
    --cc=dwmw@amazon.co.uk \
    --cc=hmushi@amazon.co.uk \
    --cc=huibo.wang@amd.com \
    --cc=joerg.roedel@amd.com \
    --cc=joro@8bytes.org \
    --cc=kvm-riscv@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=loongarch@lists.linux.dev \
    --cc=michael.roth@amd.com \
    --cc=nsaenz@amazon.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=snambakam@linux.microsoft.com \
    --cc=thomas.lendacky@amd.com \
    --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

all inboxes | Powered by JetHome®