mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
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 commit13c5183a4e("KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks"). Fixes:8f0153ecd3("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>
This commit is contained in:
committed by
Anup Patel
parent
8f0c15c4b1
commit
2dda6a9e09
@@ -10,6 +10,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/perf/riscv_pmu.h>
|
||||
#include <asm/csr.h>
|
||||
#include <asm/kvm_vcpu_sbi.h>
|
||||
@@ -87,7 +88,8 @@ static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc)
|
||||
|
||||
static u64 kvm_pmu_get_perf_event_hw_config(u32 sbi_event_code)
|
||||
{
|
||||
return hw_event_perf_map[sbi_event_code];
|
||||
return hw_event_perf_map[array_index_nospec(sbi_event_code,
|
||||
SBI_PMU_HW_GENERAL_MAX)];
|
||||
}
|
||||
|
||||
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,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[cidx];
|
||||
|
||||
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,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[cidx];
|
||||
|
||||
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,
|
||||
return 0;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
retdata->out_val = kvpmu->pmc[cidx].cinfo.value;
|
||||
|
||||
return 0;
|
||||
@@ -559,7 +564,8 @@ int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
||||
}
|
||||
/* Start the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
pmc_index = i + ctr_base;
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
continue;
|
||||
/* 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,
|
||||
|
||||
/* Stop the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
pmc_index = i + ctr_base;
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
continue;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
ctr_idx = array_index_nospec(ctr_idx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[ctr_idx];
|
||||
pmc->idx = ctr_idx;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user