| From 66061740f1a487f4ed54fde75e724709f805da53 Mon Sep 17 00:00:00 2001 |
| From: Marios Pomonis <pomonis@google.com> |
| Date: Wed, 11 Dec 2019 12:47:53 -0800 |
| Subject: KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks |
| |
| From: Marios Pomonis <pomonis@google.com> |
| |
| commit 66061740f1a487f4ed54fde75e724709f805da53 upstream. |
| |
| This fixes Spectre-v1/L1TF vulnerabilities in intel_find_fixed_event() |
| and intel_rdpmc_ecx_to_pmc(). |
| kvm_rdpmc() (ancestor of intel_find_fixed_event()) and |
| reprogram_fixed_counter() (ancestor of intel_rdpmc_ecx_to_pmc()) are |
| exported symbols so KVM should treat them conservatively from a security |
| perspective. |
| |
| Fixes: 25462f7f5295 ("KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch") |
| |
| Signed-off-by: Nick Finco <nifi@google.com> |
| Signed-off-by: Marios Pomonis <pomonis@google.com> |
| Reviewed-by: Andrew Honig <ahonig@google.com> |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Jim Mattson <jmattson@google.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/pmu_intel.c | 24 ++++++++++++++++-------- |
| 1 file changed, 16 insertions(+), 8 deletions(-) |
| |
| --- a/arch/x86/kvm/pmu_intel.c |
| +++ b/arch/x86/kvm/pmu_intel.c |
| @@ -87,10 +87,14 @@ static unsigned intel_find_arch_event(st |
| |
| static unsigned intel_find_fixed_event(int idx) |
| { |
| - if (idx >= ARRAY_SIZE(fixed_pmc_events)) |
| + u32 event; |
| + size_t size = ARRAY_SIZE(fixed_pmc_events); |
| + |
| + if (idx >= size) |
| return PERF_COUNT_HW_MAX; |
| |
| - return intel_arch_events[fixed_pmc_events[idx]].event_type; |
| + event = fixed_pmc_events[array_index_nospec(idx, size)]; |
| + return intel_arch_events[event].event_type; |
| } |
| |
| /* check if a PMC is enabled by comparing it with globl_ctrl bits. */ |
| @@ -131,16 +135,20 @@ static struct kvm_pmc *intel_msr_idx_to_ |
| struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); |
| bool fixed = idx & (1u << 30); |
| struct kvm_pmc *counters; |
| + unsigned int num_counters; |
| |
| idx &= ~(3u << 30); |
| - if (!fixed && idx >= pmu->nr_arch_gp_counters) |
| - return NULL; |
| - if (fixed && idx >= pmu->nr_arch_fixed_counters) |
| + if (fixed) { |
| + counters = pmu->fixed_counters; |
| + num_counters = pmu->nr_arch_fixed_counters; |
| + } else { |
| + counters = pmu->gp_counters; |
| + num_counters = pmu->nr_arch_gp_counters; |
| + } |
| + if (idx >= num_counters) |
| return NULL; |
| - counters = fixed ? pmu->fixed_counters : pmu->gp_counters; |
| *mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP]; |
| - |
| - return &counters[idx]; |
| + return &counters[array_index_nospec(idx, num_counters)]; |
| } |
| |
| static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) |