Skip to content

Commit 8565617

Browse files
Lukas Gerlachavpatel
authored andcommitted
KVM: riscv: Fix Spectre-v1 in APLIC interrupt handling
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 41b8759 ("KVM: arm/arm64: vgic: fix possible spectre-v1 in vgic_get_irq()") and x86 commit 8c86405 ("KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks"). Fixes: 74967aa ("RISC-V: KVM: Add in-kernel emulation of AIA APLIC") Signed-off-by: Lukas Gerlach <lukas.gerlach@cispa.de> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260116095731.24555-1-lukas.gerlach@cispa.de Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent 11439c4 commit 8565617

1 file changed

Lines changed: 12 additions & 11 deletions

File tree

arch/riscv/kvm/aia_aplic.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/irqchip/riscv-aplic.h>
1111
#include <linux/kvm_host.h>
1212
#include <linux/math.h>
13+
#include <linux/nospec.h>
1314
#include <linux/spinlock.h>
1415
#include <linux/swab.h>
1516
#include <kvm/iodev.h>
@@ -45,7 +46,7 @@ static u32 aplic_read_sourcecfg(struct aplic *aplic, u32 irq)
4546

4647
if (!irq || aplic->nr_irqs <= irq)
4748
return 0;
48-
irqd = &aplic->irqs[irq];
49+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
4950

5051
raw_spin_lock_irqsave(&irqd->lock, flags);
5152
ret = irqd->sourcecfg;
@@ -61,7 +62,7 @@ static void aplic_write_sourcecfg(struct aplic *aplic, u32 irq, u32 val)
6162

6263
if (!irq || aplic->nr_irqs <= irq)
6364
return;
64-
irqd = &aplic->irqs[irq];
65+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
6566

6667
if (val & APLIC_SOURCECFG_D)
6768
val = 0;
@@ -81,7 +82,7 @@ static u32 aplic_read_target(struct aplic *aplic, u32 irq)
8182

8283
if (!irq || aplic->nr_irqs <= irq)
8384
return 0;
84-
irqd = &aplic->irqs[irq];
85+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
8586

8687
raw_spin_lock_irqsave(&irqd->lock, flags);
8788
ret = irqd->target;
@@ -97,7 +98,7 @@ static void aplic_write_target(struct aplic *aplic, u32 irq, u32 val)
9798

9899
if (!irq || aplic->nr_irqs <= irq)
99100
return;
100-
irqd = &aplic->irqs[irq];
101+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
101102

102103
val &= APLIC_TARGET_EIID_MASK |
103104
(APLIC_TARGET_HART_IDX_MASK << APLIC_TARGET_HART_IDX_SHIFT) |
@@ -116,7 +117,7 @@ static bool aplic_read_pending(struct aplic *aplic, u32 irq)
116117

117118
if (!irq || aplic->nr_irqs <= irq)
118119
return false;
119-
irqd = &aplic->irqs[irq];
120+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
120121

121122
raw_spin_lock_irqsave(&irqd->lock, flags);
122123
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)
132133

133134
if (!irq || aplic->nr_irqs <= irq)
134135
return;
135-
irqd = &aplic->irqs[irq];
136+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
136137

137138
raw_spin_lock_irqsave(&irqd->lock, flags);
138139

@@ -170,7 +171,7 @@ static bool aplic_read_enabled(struct aplic *aplic, u32 irq)
170171

171172
if (!irq || aplic->nr_irqs <= irq)
172173
return false;
173-
irqd = &aplic->irqs[irq];
174+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
174175

175176
raw_spin_lock_irqsave(&irqd->lock, flags);
176177
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)
186187

187188
if (!irq || aplic->nr_irqs <= irq)
188189
return;
189-
irqd = &aplic->irqs[irq];
190+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
190191

191192
raw_spin_lock_irqsave(&irqd->lock, flags);
192193
if (enabled)
@@ -205,7 +206,7 @@ static bool aplic_read_input(struct aplic *aplic, u32 irq)
205206

206207
if (!irq || aplic->nr_irqs <= irq)
207208
return false;
208-
irqd = &aplic->irqs[irq];
209+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
209210

210211
raw_spin_lock_irqsave(&irqd->lock, flags);
211212

@@ -254,7 +255,7 @@ static void aplic_update_irq_range(struct kvm *kvm, u32 first, u32 last)
254255
for (irq = first; irq <= last; irq++) {
255256
if (!irq || aplic->nr_irqs <= irq)
256257
continue;
257-
irqd = &aplic->irqs[irq];
258+
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
258259

259260
raw_spin_lock_irqsave(&irqd->lock, flags);
260261

@@ -283,7 +284,7 @@ int kvm_riscv_aia_aplic_inject(struct kvm *kvm, u32 source, bool level)
283284

284285
if (!aplic || !source || (aplic->nr_irqs <= source))
285286
return -ENODEV;
286-
irqd = &aplic->irqs[source];
287+
irqd = &aplic->irqs[array_index_nospec(source, aplic->nr_irqs)];
287288
ie = (aplic->domaincfg & APLIC_DOMAINCFG_IE) ? true : false;
288289

289290
raw_spin_lock_irqsave(&irqd->lock, flags);

0 commit comments

Comments
 (0)