Skip to content

Commit d43548f

Browse files
author
Marc Zyngier
committed
KVM: arm64: nv: Hold mmu_lock when invalidating VNCR SW-TLB before translating
When translating a VNCR translation fault, we start by marking the current SW-managed TLB as invalid, so that we can populate it in place. This is, however, done without the mmu_lock held. A consequence of this is that another CPU dealing with TLBI emulation can observe a translation still flagged as valid, but with invalid walk results (such as pgshift being 0). Bad things can result from this, such as a BUG() in pgshift_level_to_ttl(). Fix it by taking the mmu_lock for write to perform this local invalidation, and use invalidate_vncr() instead of open-coding the write to the 'valid' flag. Fixes: 069a05e ("KVM: arm64: nv: Handle VNCR_EL2-triggered faults") Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Link: https://lore.kernel.org/r/20250520144116.3667978-1-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 29d1697 commit d43548f

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

arch/arm64/kvm/nested.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,13 +1179,24 @@ static int kvm_translate_vncr(struct kvm_vcpu *vcpu)
11791179

11801180
vt = vcpu->arch.vncr_tlb;
11811181

1182-
vt->wi = (struct s1_walk_info) {
1183-
.regime = TR_EL20,
1184-
.as_el0 = false,
1185-
.pan = false,
1186-
};
1187-
vt->wr = (struct s1_walk_result){};
1188-
vt->valid = false;
1182+
/*
1183+
* If we're about to walk the EL2 S1 PTs, we must invalidate the
1184+
* current TLB, as it could be sampled from another vcpu doing a
1185+
* TLBI *IS. A real CPU wouldn't do that, but we only keep a single
1186+
* translation, so not much of a choice.
1187+
*
1188+
* We also prepare the next walk wilst we're at it.
1189+
*/
1190+
scoped_guard(write_lock, &vcpu->kvm->mmu_lock) {
1191+
invalidate_vncr(vt);
1192+
1193+
vt->wi = (struct s1_walk_info) {
1194+
.regime = TR_EL20,
1195+
.as_el0 = false,
1196+
.pan = false,
1197+
};
1198+
vt->wr = (struct s1_walk_result){};
1199+
}
11891200

11901201
guard(srcu)(&vcpu->kvm->srcu);
11911202

0 commit comments

Comments
 (0)