[PATCH] KVM: riscv: Fix Spectre-v1 in APLIC interrupt handling
Nutty.Liu
nutty.liu at hotmail.com
Mon Jan 19 01:59:19 PST 2026
On 1/16/2026 5:57 PM, Lukas Gerlach wrote:
> Guests can control IRQ indices via MMIO. Sanitize them with
> array_index_nospec() to prevent speculative out-of-bounds access
> to the aplic->irqs[] array.
>
> Similar to arm64 commit 41b87599c743 ("KVM: arm/arm64: vgic: fix possible
> spectre-v1 in vgic_get_irq()") and x86 commit 8c86405f606c ("KVM: x86:
> Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks").
>
> Fixes: 74967aa208e2 ("RISC-V: KVM: Add in-kernel emulation of AIA APLIC")
> Signed-off-by: Lukas Gerlach <lukas.gerlach at cispa.de>
> ---
> arch/riscv/kvm/aia_aplic.c | 23 ++++++++++++-----------
> 1 file changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/arch/riscv/kvm/aia_aplic.c b/arch/riscv/kvm/aia_aplic.c
> index f59d1c0c8c43..a2b831e57ecd 100644
> --- a/arch/riscv/kvm/aia_aplic.c
> +++ b/arch/riscv/kvm/aia_aplic.c
> @@ -10,6 +10,7 @@
> #include <linux/irqchip/riscv-aplic.h>
> #include <linux/kvm_host.h>
> #include <linux/math.h>
> +#include <linux/nospec.h>
> #include <linux/spinlock.h>
> #include <linux/swab.h>
> #include <kvm/iodev.h>
> @@ -45,7 +46,7 @@ static u32 aplic_read_sourcecfg(struct aplic *aplic, u32 irq)
>
> if (!irq || aplic->nr_irqs <= irq)
> return 0;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> ret = irqd->sourcecfg;
> @@ -61,7 +62,7 @@ static void aplic_write_sourcecfg(struct aplic *aplic, u32 irq, u32 val)
>
> if (!irq || aplic->nr_irqs <= irq)
> return;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> if (val & APLIC_SOURCECFG_D)
> val = 0;
> @@ -81,7 +82,7 @@ static u32 aplic_read_target(struct aplic *aplic, u32 irq)
>
> if (!irq || aplic->nr_irqs <= irq)
> return 0;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> ret = irqd->target;
> @@ -97,7 +98,7 @@ static void aplic_write_target(struct aplic *aplic, u32 irq, u32 val)
>
> if (!irq || aplic->nr_irqs <= irq)
> return;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> val &= APLIC_TARGET_EIID_MASK |
> (APLIC_TARGET_HART_IDX_MASK << APLIC_TARGET_HART_IDX_SHIFT) |
> @@ -116,7 +117,7 @@ static bool aplic_read_pending(struct aplic *aplic, u32 irq)
>
> if (!irq || aplic->nr_irqs <= irq)
> return false;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> ret = (irqd->state & APLIC_IRQ_STATE_PENDING) ? true : false;
> @@ -132,7 +133,7 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending)
>
> if (!irq || aplic->nr_irqs <= irq)
> return;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
>
> @@ -170,7 +171,7 @@ static bool aplic_read_enabled(struct aplic *aplic, u32 irq)
>
> if (!irq || aplic->nr_irqs <= irq)
> return false;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> ret = (irqd->state & APLIC_IRQ_STATE_ENABLED) ? true : false;
> @@ -186,7 +187,7 @@ static void aplic_write_enabled(struct aplic *aplic, u32 irq, bool enabled)
>
> if (!irq || aplic->nr_irqs <= irq)
> return;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> if (enabled)
> @@ -205,7 +206,7 @@ static bool aplic_read_input(struct aplic *aplic, u32 irq)
>
> if (!irq || aplic->nr_irqs <= irq)
> return false;
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
>
> @@ -254,7 +255,7 @@ static void aplic_update_irq_range(struct kvm *kvm, u32 first, u32 last)
> for (irq = first; irq <= last; irq++) {
> if (!irq || aplic->nr_irqs <= irq)
> continue;
Seems the above code would be better as follows ?
if (!irq)
continue;
if(aplic->nr_irqs <= irq)
return;
Otherwise,
Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>
Thanks,
Nutty
> - irqd = &aplic->irqs[irq];
> + irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
>
> @@ -283,7 +284,7 @@ int kvm_riscv_aia_aplic_inject(struct kvm *kvm, u32 source, bool level)
>
> if (!aplic || !source || (aplic->nr_irqs <= source))
> return -ENODEV;
> - irqd = &aplic->irqs[source];
> + irqd = &aplic->irqs[array_index_nospec(source, aplic->nr_irqs)];
> ie = (aplic->domaincfg & APLIC_DOMAINCFG_IE) ? true : false;
>
> raw_spin_lock_irqsave(&irqd->lock, flags);
> --
> 2.51.0
>
>
More information about the linux-riscv
mailing list