Skip to content

Commit 64d6820

Browse files
author
Marc Zyngier
committed
KVM: arm64: PMU: Sanitise PMCR_EL0.LP on first vcpu run
Userspace can play some dirty tricks on us by selecting a given PMU version (such as PMUv3p5), restore a PMCR_EL0 value that has PMCR_EL0.LP set, and then switch the PMU version to PMUv3p1, for example. In this situation, we end-up with PMCR_EL0.LP being set and spreading havoc in the PMU emulation. This is specially hard as the first two step can be done on one vcpu and the third step on another, meaning that we need to sanitise *all* vcpus when the PMU version is changed. In orer to avoid a pretty complicated locking situation, defer the sanitisation of PMCR_EL0 to the point where the vcpu is actually run for the first tine, using the existing KVM_REQ_RELOAD_PMU request that calls into kvm_pmu_handle_pmcr(). There is still an obscure corner case where userspace could do the above trick, and then save the VM without running it. They would then observe an inconsistent state (PMUv3.1 + LP set), but that state will be fixed on the first run anyway whenever the guest gets restored on a host. Reported-by: Reiji Watanabe <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 292e8f1 commit 64d6820

File tree

2 files changed

+10
-4
lines changed

2 files changed

+10
-4
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,12 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
538538
if (!kvm_vcpu_has_pmu(vcpu))
539539
return;
540540

541+
/* Fixup PMCR_EL0 to reconcile the PMU version and the LP bit */
542+
if (!kvm_pmu_is_3p5(vcpu))
543+
val &= ~ARMV8_PMU_PMCR_LP;
544+
545+
__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
546+
541547
if (val & ARMV8_PMU_PMCR_E) {
542548
kvm_pmu_enable_counter_mask(vcpu,
543549
__vcpu_sys_reg(vcpu, PMCNTENSET_EL0));

arch/arm64/kvm/sys_regs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -693,15 +693,15 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
693693
return false;
694694

695695
if (p->is_write) {
696-
/* Only update writeable bits of PMCR */
696+
/*
697+
* Only update writeable bits of PMCR (continuing into
698+
* kvm_pmu_handle_pmcr() as well)
699+
*/
697700
val = __vcpu_sys_reg(vcpu, PMCR_EL0);
698701
val &= ~ARMV8_PMU_PMCR_MASK;
699702
val |= p->regval & ARMV8_PMU_PMCR_MASK;
700703
if (!kvm_supports_32bit_el0())
701704
val |= ARMV8_PMU_PMCR_LC;
702-
if (!kvm_pmu_is_3p5(vcpu))
703-
val &= ~ARMV8_PMU_PMCR_LP;
704-
__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
705705
kvm_pmu_handle_pmcr(vcpu, val);
706706
kvm_vcpu_pmu_restore_guest(vcpu);
707707
} else {

0 commit comments

Comments
 (0)