]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: riscv: Fix Spectre-v1 in AIA CSR access
authorLukas Gerlach <lukas.gerlach@cispa.de>
Tue, 3 Mar 2026 14:19:42 +0000 (15:19 +0100)
committerAnup Patel <anup@brainfault.org>
Fri, 6 Mar 2026 05:50:30 +0000 (11:20 +0530)
User-controlled indices are used to access AIA CSR registers.
Sanitize them with array_index_nospec() to prevent speculative
out-of-bounds access.

Similar to x86 commit 8c86405f606c ("KVM: x86: Protect
ioapic_read_indirect() from Spectre-v1/L1TF attacks") and arm64
commit 41b87599c743 ("KVM: arm/arm64: vgic: fix possible spectre-v1
in vgic_get_irq()").

Reviewed-by: Radim Krčmář <radim.krcmar@oss.qualcomm.com>
Signed-off-by: Lukas Gerlach <lukas.gerlach@cispa.de>
Link: https://lore.kernel.org/r/20260303-kvm-riscv-spectre-v1-v2-2-192caab8e0dc@cispa.de
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/kvm/aia.c

index cac3c2b51d7247cf4be69f4c3b692c72a27b99c9..38de97d2f5b85fdb14ac94733f0f26fff507394c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/irqchip/riscv-imsic.h>
 #include <linux/irqdomain.h>
 #include <linux/kvm_host.h>
+#include <linux/nospec.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <asm/cpufeature.h>
@@ -182,10 +183,13 @@ int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu,
                               unsigned long *out_val)
 {
        struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+       unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
 
-       if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long))
+       if (reg_num >= regs_max)
                return -ENOENT;
 
+       reg_num = array_index_nospec(reg_num, regs_max);
+
        *out_val = 0;
        if (kvm_riscv_aia_available())
                *out_val = ((unsigned long *)csr)[reg_num];
@@ -198,10 +202,13 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
                               unsigned long val)
 {
        struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+       unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
 
-       if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long))
+       if (reg_num >= regs_max)
                return -ENOENT;
 
+       reg_num = array_index_nospec(reg_num, regs_max);
+
        if (kvm_riscv_aia_available()) {
                ((unsigned long *)csr)[reg_num] = val;