Re: [PATCH v2] RISC-V: KVM: Fix use-after-free in kvm_riscv_gstage_get_leaf()

From: Jiakai Xu

Date: Wed Apr 01 2026 - 07:03:38 EST


Hi Anup,

I've been fuzzing the latest kvm-riscv with the spin_trylock() fix
applied, and I can still reproduce the use-after-free bug in
kvm_riscv_gstage_get_leaf(). This indicates the current fix is
insufficient.

The current code does:
mmu_locked = spin_trylock(&kvm->mmu_lock);
kvm_riscv_gstage_unmap_range(...);
if (mmu_locked)
spin_unlock(&kvm->mmu_lock);
When spin_trylock() fails (lock held by another CPU), the code still
proceeds to access the gstage page table without any protection,
leading to UAF when concurrent with kvm_riscv_mmu_free_pgd().

The fundamental issue is that spin_trylock() returns false in two
different cases:
1. Lock held by current thread (we should continue)
2. Lock held by another thread (we should NOT continue)
But the current code doesn't distinguish between them.

My proposed fix:
Use lock_is_held_type() to check if current thread already holds the
lock:
bool need_unlock = false;
if (!lock_is_held_type(&kvm->mmu_lock, LOCK_STATE_HELD)) {
spin_lock(&kvm->mmu_lock);
need_unlock = true;
}
kvm_riscv_gstage_unmap_range(...);
if (need_unlock)
spin_unlock(&kvm->mmu_lock);

However, I'm not sure if this is the best approach. What do you think?

Thanks,
Jiakai