All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Anup Patel" <anup.patel@oss.qualcomm.com>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock
Date: Sat, 14 Nov 2026 14:08:52 +0000	[thread overview]
Message-ID: <sashiko-outbox-214611@kernel.org> (raw)
In-Reply-To: <20261114135056.202556-1-anup.patel@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] KVM: riscv: unordered MMIO write in
  kvm_riscv_vcpu_aia_imsic_inject()
- [High] KVM: riscv: race on IRQ_VS_EXT in
  kvm_riscv_vcpu_aia_imsic_inject()
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [Critical] RISC-V: KVM: double-free in
  kvm_riscv_vcpu_aia_imsic_update() [1]
--

commit 7416cdfbe4d0521c182f4faca63b3ac6e4ae60b3
Author: Anup Patel <anup.patel@oss.qualcomm.com>

RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock

This commit converts imsic->vsfile_lock from rwlock_t to raw_spinlock_t,
removes vsfile_hgei_lock, moves imsic_swfile_extirq_update() outside
vsfile_lock, and switches kvm_riscv_vcpu_aia_imsic_inject() to
writel_relaxed().

> diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
> index 302938972aa0e..0b9d15721d52f 100644
> --- a/arch/riscv/kvm/aia_imsic.c
> +++ b/arch/riscv/kvm/aia_imsic.c

[ ... ]

> @@ -726,10 +715,10 @@ int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu)
>  		return 1;
>  
>  	/* Read old IMSIC VS-file details */
> -	read_lock_irqsave(&imsic->vsfile_lock, flags);
> +	raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
>  	old_vsfile_hgei = imsic->vsfile_hgei;
>  	old_vsfile_cpu = imsic->vsfile_cpu;
> -	read_unlock_irqrestore(&imsic->vsfile_lock, flags);
> +	raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);

[Severity: Critical]
This problem wasn't introduced by this patch, but can [1] cause a
double free of old_vsfile_hgei when kvm_riscv_vcpu_aia_imsic_update()
races with kvm_riscv_vcpu_aia_imsic_release()?

kvm_riscv_vcpu_aia_imsic_update() caches old_vsfile_hgei and
old_vsfile_cpu under imsic->vsfile_lock and drops the lock before later
freeing the old HGEI slot:

CPU0                                  CPU1
kvm_riscv_vcpu_aia_imsic_update()     kvm_riscv_vcpu_aia_imsic_release()
  raw_spin_lock_irqsave(...)
  old_vsfile_hgei = imsic->vsfile_hgei;
  old_vsfile_cpu = imsic->vsfile_cpu;
  raw_spin_unlock_irqrestore(...)
                                        raw_spin_lock_irqsave(...)
                                        old_vsfile_hgei = imsic->vsfile_hgei;
                                        old_vsfile_cpu = imsic->vsfile_cpu;
                                        imsic->vsfile_cpu = -1;
                                        imsic->vsfile_hgei = -1;
                                        raw_spin_unlock_irqrestore(...)
                                        ...
                                        kvm_riscv_aia_free_hgei(...)
  ...
  if (old_vsfile_cpu >= 0) {
    ...
    kvm_riscv_aia_free_hgei(...)  <-- double free

If a concurrent CPU hotplug or vCPU reset runs
kvm_riscv_vcpu_aia_imsic_release() in that window, both paths free the
same HGEI slot.  If that slot was reallocated to another VM in between,
the second free corrupts cross-VM interrupt state.

[ ... ]

> @@ -970,17 +965,26 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
>  	if (imsic->nr_msis <= iid)
>  		return -EINVAL;
>  
> -	read_lock_irqsave(&imsic->vsfile_lock, flags);
> +	raw_spin_lock_irqsave(&imsic->vsfile_lock, flags);
>  
>  	if (imsic->vsfile_cpu >= 0) {
> -		writel(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);
> +		/*
> +		 * We can use writel_relaxed() over here because the
> +		 * raw_spin_unlock() below will do mmiowb_spin_unlock()
> +		 * which in-turn drains the write-buffer ensuring the
> +		 * write is visible to the CPU owning the IMSIC VS-file.
> +		 */
> +		writel_relaxed(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);

[Severity: High]
Does replacing writel() with writel_relaxed() leave the MMIO write to
imsic->vsfile_va unordered with raw_spin_unlock_irqrestore()?

mmiowb_spin_unlock() only emits mmiowb() when ms->mmiowb_pending is set:

include/asm-generic/mmiowb.h:mmiowb_spin_unlock() {
	struct mmiowb_state *ms = __mmiowb_state();

	if (unlikely(ms->mmiowb_pending)) {
		ms->mmiowb_pending = 0;
		mmiowb();
	}
}

On RISC-V, writel() calls __io_bw() and __io_aw() (which calls
mmiowb_set_pending()), whereas writel_relaxed() uses __io_rbw() and
__io_raw(), which are both no-ops.  Because writel_relaxed() never sets
ms->mmiowb_pending, raw_spin_unlock_irqrestore() does not emit mmiowb()
(RISCV_FENCE(o, w)).  If the vCPU concurrently migrates or releases its
VS-file in kvm_riscv_vcpu_aia_imsic_update() or
kvm_riscv_vcpu_aia_imsic_release(), the store to IMSIC_MMIO_SETIPNUM_LE
can arrive after imsic_vsfile_read() has cleared the old VS-file and
kvm_riscv_aia_free_hgei() has freed the slot, losing the guest interrupt
or delivering a spurious MSI to another vCPU.

>  	} else {
>  		eix = &imsic->swfile->eix[iid / BITS_PER_TYPE(u64)];
>  		set_bit(iid & (BITS_PER_TYPE(u64) - 1), eix->eip);
> -		imsic_swfile_extirq_update(vcpu);
> +		swfile_update = true;
>  	}
>  
> -	read_unlock_irqrestore(&imsic->vsfile_lock, flags);
> +	raw_spin_unlock_irqrestore(&imsic->vsfile_lock, flags);
> +
> +	if (swfile_update)
> +		imsic_swfile_extirq_update(vcpu);

[Severity: High]
Can moving imsic_swfile_extirq_update() outside imsic->vsfile_lock race
with kvm_riscv_vcpu_aia_imsic_update() and leave IRQ_VS_EXT stuck pending?

imsic_swfile_read() clears imsic->swfile and unsets IRQ_VS_EXT without
taking swfile_extirq_lock, relying on vsfile_lock to serialize against
SW-file producers:

CPU0                                  CPU1
kvm_riscv_vcpu_aia_imsic_inject()     kvm_riscv_vcpu_aia_imsic_update()
  raw_spin_lock_irqsave(&vsfile_lock)
  /* vsfile_cpu < 0 */
  set_bit(..., eix->eip)
  swfile_update = true
  raw_spin_unlock_irqrestore(...)
  imsic_swfile_extirq_update()
    raw_spin_lock_irqsave(&extirq_lock)
    /* reads eidelivery && topei != 0 */
                                        raw_spin_lock_irqsave(&vsfile_lock)
                                        imsic->vsfile_cpu = vcpu->cpu
                                        raw_spin_unlock_irqrestore(...)
                                        imsic_swfile_read(..., true, ...)
                                          memset(imsic->swfile, 0, ...)
                                          kvm_riscv_vcpu_unset_interrupt(
                                              vcpu, IRQ_VS_EXT)
    kvm_riscv_vcpu_set_interrupt(
        vcpu, IRQ_VS_EXT)  <-- re-asserts IRQ_VS_EXT

Once the vCPU is using a hardware VS-file (HSTATUS.VGEIN > 0), guest
accesses to CSR_VSTOPEI are handled by hardware without trapping, so
nothing clears IRQ_VS_EXT in CSR_HVIP and the guest vCPU is wedged in a
spurious external interrupt storm.

[1] https://sashiko.dev/#/bug/linux-0a58883c-0da3-49e7-847e-a71b508f0638

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114135056.202556-1-anup.patel@oss.qualcomm.com?part=1

      reply	other threads:[~2026-11-14 14:08 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-14 13:50 [PATCH] RISC-V: KVM: Convert IMSIC vsfile_lock to a raw spinlock Anup Patel
2026-11-14 13:50 ` Anup Patel
2026-11-14 13:50 ` Anup Patel
2026-11-14 14:08 ` sashiko-bot [this message]

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=sashiko-outbox-214611@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=anup.patel@oss.qualcomm.com \
    --cc=kvm@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.