Skip to content

Commit 2dda6a9

Browse files
Lukas Gerlachavpatel
authored andcommitted
KVM: riscv: Fix Spectre-v1 in PMU counter access
Guest-controlled counter indices received via SBI ecalls are used to index into the PMC array. Sanitize them with array_index_nospec() to prevent speculative out-of-bounds access. Similar to x86 commit 13c5183 ("KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks"). Fixes: 8f0153e ("RISC-V: KVM: Add skeleton support for perf") 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-4-192caab8e0dc@cispa.de Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent 8f0c15c commit 2dda6a9

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

arch/riscv/kvm/vcpu_pmu.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/errno.h>
1111
#include <linux/err.h>
1212
#include <linux/kvm_host.h>
13+
#include <linux/nospec.h>
1314
#include <linux/perf/riscv_pmu.h>
1415
#include <asm/csr.h>
1516
#include <asm/kvm_vcpu_sbi.h>
@@ -87,7 +88,8 @@ static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc)
8788

8889
static u64 kvm_pmu_get_perf_event_hw_config(u32 sbi_event_code)
8990
{
90-
return hw_event_perf_map[sbi_event_code];
91+
return hw_event_perf_map[array_index_nospec(sbi_event_code,
92+
SBI_PMU_HW_GENERAL_MAX)];
9193
}
9294

9395
static u64 kvm_pmu_get_perf_event_cache_config(u32 sbi_event_code)
@@ -218,6 +220,7 @@ static int pmu_fw_ctr_read_hi(struct kvm_vcpu *vcpu, unsigned long cidx,
218220
return -EINVAL;
219221
}
220222

223+
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
221224
pmc = &kvpmu->pmc[cidx];
222225

223226
if (pmc->cinfo.type != SBI_PMU_CTR_TYPE_FW)
@@ -244,6 +247,7 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
244247
return -EINVAL;
245248
}
246249

250+
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
247251
pmc = &kvpmu->pmc[cidx];
248252

249253
if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW) {
@@ -525,6 +529,7 @@ int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx,
525529
return 0;
526530
}
527531

532+
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
528533
retdata->out_val = kvpmu->pmc[cidx].cinfo.value;
529534

530535
return 0;
@@ -559,7 +564,8 @@ int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
559564
}
560565
/* Start the counters that have been configured and requested by the guest */
561566
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
562-
pmc_index = i + ctr_base;
567+
pmc_index = array_index_nospec(i + ctr_base,
568+
RISCV_KVM_MAX_COUNTERS);
563569
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
564570
continue;
565571
/* The guest started the counter again. Reset the overflow status */
@@ -630,7 +636,8 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
630636

631637
/* Stop the counters that have been configured and requested by the guest */
632638
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
633-
pmc_index = i + ctr_base;
639+
pmc_index = array_index_nospec(i + ctr_base,
640+
RISCV_KVM_MAX_COUNTERS);
634641
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
635642
continue;
636643
pmc = &kvpmu->pmc[pmc_index];
@@ -761,6 +768,7 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba
761768
}
762769
}
763770

771+
ctr_idx = array_index_nospec(ctr_idx, RISCV_KVM_MAX_COUNTERS);
764772
pmc = &kvpmu->pmc[ctr_idx];
765773
pmc->idx = ctr_idx;
766774

0 commit comments

Comments
 (0)