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

Jiakai Xu xujiakai2025 at iscas.ac.cn
Wed Apr 1 03:49:02 PDT 2026


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




More information about the linux-riscv mailing list