summaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorAaron Lewis <aaronlewis@google.com>2022-12-20 16:12:31 +0000
committerSean Christopherson <seanjc@google.com>2023-01-24 10:06:11 -0800
commit8589827fd5342b0ae3703e3093a946d708c44f3a (patch)
tree7b9009a0f8921438ff2d4595acf282a218547cd3 /arch/x86/kvm
parent6a5cba7bed35580effda9fb1872b274da47e6b23 (diff)
downloadlinux-stable-8589827fd5342b0ae3703e3093a946d708c44f3a.tar.gz
linux-stable-8589827fd5342b0ae3703e3093a946d708c44f3a.tar.bz2
linux-stable-8589827fd5342b0ae3703e3093a946d708c44f3a.zip
KVM: x86/pmu: Remove impossible events from the pmu event filter
If it's not possible for an event in the pmu event filter to match a pmu event being programmed by the guest, it's pointless to have it in the list. Opt for a shorter list by removing those events. Because this is established uAPI the pmu event filter can't outright rejected these events as garbage and return an error. Instead, play nice and remove them from the list. Also, opportunistically rewrite the comment when the filter is set to clarify that it guards against *all* TOCTOU attacks on the verified data. Signed-off-by: Aaron Lewis <aaronlewis@google.com> Link: https://lore.kernel.org/r/20221220161236.555143-3-aaronlewis@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/pmu.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index f5b933eeb549..d29f6393c07e 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -594,6 +594,21 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id)
}
EXPORT_SYMBOL_GPL(kvm_pmu_trigger_event);
+static void remove_impossible_events(struct kvm_pmu_event_filter *filter)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < filter->nevents; i++) {
+ if (filter->events[i] & ~(kvm_pmu_ops.EVENTSEL_EVENT |
+ ARCH_PERFMON_EVENTSEL_UMASK))
+ continue;
+
+ filter->events[j++] = filter->events[i];
+ }
+
+ filter->nevents = j;
+}
+
int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
{
struct kvm_pmu_event_filter tmp, *filter;
@@ -624,9 +639,11 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
if (copy_from_user(filter, argp, size))
goto cleanup;
- /* Ensure nevents can't be changed between the user copies. */
+ /* Restore the verified state to guard against TOCTOU attacks. */
*filter = tmp;
+ remove_impossible_events(filter);
+
/*
* Sort the in-kernel list so that we can search it with bsearch.
*/