From nobody Thu Sep 24 17:53:44 2026 Received: from mta0.migadu.com (out-245.mta0.migadu.com [91.218.175.245]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C607E50B8D0 for ; Mon, 21 Sep 2026 19:08:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.245 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790017734; cv=none; b=Xq3sccwYLikPvhKY5XIg9zIC3124twoY1NZND3SgNe/wwjMfyGFzqydRk77nJxRZOUvqm8y/+kAoxEd4DQQescRjBixic8oHQFcZeC/7bJ8JnkuC0tek2sb4rOPfTC4wxJtQn34K4veHafQPEhVeWVRGNeWVIS3IsqBw3TxGEzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790017734; c=relaxed/simple; bh=byn7IcfYtNzqQNzC68nkMM9pNinh2rMmEj6DsERw1DA=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=h22R+HQJMcEtfzgzDqsRlzC7AkItM0O3ERVh26Ane6EimeUKROrgjwADbyuaOd46mf042QjLEfiknhfXcImbiRWgRNEq3He0IP8d4XDE/Ek59PxTKpgXgIR8ZnJXC+CMmZscHY43ZphI5LkzYOOHbdETjVaqGGcpupyka4F5o8w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=tX/m/a/a; arc=none smtp.client-ip=91.218.175.245 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="tX/m/a/a" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=byn7IcfYtNzqQNzC68nkMM9pNinh2rMmEj6DsERw1DA=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1790017728; v=1; x=1790622528; b=tX/m/a/avHXHHIsDdy9/0zS/5tSDLrVyTkM5/YNfvDD8fLoMSIDP1/YYtiMb0HLyCqMpmLZt XcfWVKfdhAHeh9aur7TlFO1CBVjjTY9+7e7Wcf0ycyc9Bh4yikl1UQYpk5vrgBna7Mr+n6e5hPa E0C40KnZnYkrAZBUuTBlYjQE= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 2fcc12c4d7f11f74; Mon, 21 Sep 2026 19:08:48 +0000 X-Mizu-Trace-ID: 2fcc12c4d7f11f74 X-Migadu-Flow: FLOW_OUT From: Fuad Tabba To: Marc Zyngier , Oliver Upton Cc: Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Will Deacon , Lorenzo Stoakes , Jack Thomson , kvmarm@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Fuad Tabba Subject: [PATCH v3] KVM: arm64: Clear the VM's feature bitmap when kvm_setup_vcpu() fails Date: Mon, 21 Sep 2026 20:08:43 +0100 Message-Id: <20260921190843.107881-1-fuad.tabba@linux.dev> X-Mailer: git-send-email 2.39.5 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" __kvm_vcpu_set_target() copies the requested features into the VM-wide bitmap before kvm_setup_vcpu() runs and doesn't undo it when setup fails, so a rejected KVM_ARM_VCPU_INIT leaves the VM recording features that were never set up. With HAS_EL2 | HAS_EL2_E2H0 on a host without FEAT_NV1, kvm_vcpu_init_nested() returns -EINVAL before it allocates any nested stage-2 MMU, and vcpu_has_nv() is then true with nested_mmus_size =3D=3D 0; its -ENOMEM paths do the same on a VM's first INIT. Until one INIT has succeeded, every INIT that passes the feature check rewrites the bitmap and a failure leaves it there; once KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED is set, kvm_vcpu_init_changed() has already required the requested features to equal the bitmap, so the copy is a no-op. Clear the bitmap on failure while the flag is clear. This showed up with the series that enables KVM_PRE_FAULT_MEMORY for arm64, since the generic kvm_vcpu_pre_fault_memory() calls vcpu_load() without checking that the vCPU has been initialised. After the rejected INIT, the first call's vcpu_load() reads hw_mmu still set to the canonical MMU and leaves it alone, but its vcpu_put() takes the vcpu_has_nv() branch into kvm_vcpu_put_hw_mmu(), which clears hw_mmu. The second call's vcpu_load() reads hw_mmu as NULL and takes the nested branch into get_s2_mmu_nested(), whose search over nested_mmus_size =3D=3D 0 leaves s2_mmu NULL for the BUG_ON(atomic_read(&s2_mmu->refcnt)), under mmu_lock. On kvmarm/next with the series applied: Unable to handle kernel NULL pointer dereference at virtual address 00000= 00000000074 Call trace: kvm_vcpu_load_hw_mmu (arch/arm64/kvm/nested.c:891) (P) kvm_arch_vcpu_load (arch/arm64/kvm/arm.c:662) kvm_vcpu_pre_fault_memory (virt/kvm/kvm_main.c:170 virt/kvm/kvm_main.c:4= 349) kvm_vcpu_ioctl (virt/kvm/kvm_main.c:4639) Fixes: 427733579744e ("KVM: arm64: Select default PMU in KVM_ARM_VCPU_INIT = handler") Suggested-by: Oliver Upton Link: https://lore.kernel.org/r/20260825-kvm-arm-prefault-v1-0-befe8947702e= @kernel.org/ Signed-off-by: Fuad Tabba Reviewed-by: Lorenzo Stoakes (ARM) --- v3: - Clear the bitmap on failure instead of saving and restoring it, only while KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED is clear, since with the flag set the copy was a no-op (Oliver). - Commit message: drop the "latent, exposed by the series" framing and state the flag invariant behind the clear; the pre-fault crash is how the bug showed up. - Dropped Lorenzo's Reviewed-by since the code changed. v2: - Commit message: say what the prefault series enables, bring the two-ioctl walk and the trace up from below the fold, the trace decoded, and drop the Fixes: on 1de10b7d13a97, which had nothing fallible after the copy (Lorenzo). - Fold Lorenzo's Reviewed-by. Reproduced on kvmarm/next plus the series under QEMU (-cpu max with an Apple M2 MIDR, which has_nv1() denies; kvm-arm.mode=3Dnested): KVM_ARM_VCPU_INIT with HAS_EL2 | HAS_EL2_E2H0 returns -EINVAL, then KVM_PRE_FAULT_MEMORY twice. With the fix both calls return -ENOENT and the host is unaffected. Based on kvmarm/fixes; applies cleanly to v7.3-rc4 and to kvmarm/next. v2: https://lore.kernel.org/r/20260921063718.1604533-1-fuad.tabba@linux.dev/ v1: https://lore.kernel.org/r/20260918120553.163139-1-fuad.tabba@linux.dev/ arch/arm64/kvm/arm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index eaf583b771931..bd19f64ae82ef 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1698,8 +1698,16 @@ static int __kvm_vcpu_set_target(struct kvm_vcpu *vc= pu, bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES); =20 ret =3D kvm_setup_vcpu(vcpu); - if (ret) + if (ret) { + /* + * Clear the bitmap if setup fails on the first vCPU to be + * initialized. + */ + if (!test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags)) + bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES); + goto out_unlock; + } =20 /* Now we know what it is, we can reset it. */ kvm_reset_vcpu(vcpu); base-commit: 6b1bca1b1ab77f60a62087337bfe6e2f0efb9e6d --=20 2.39.5