From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:49:26
The host CTRL (runlatch) value is not restored after guest exit. The
host CTRL should always be 1 except in CPU idle code, so this can result
in the host running with runlatch clear, and potentially switching to
a different vCPU which then runs with runlatch clear as well.
This has little effect on P9 machines, CTRL is only responsible for some
PMU counter logic in the host and so other than corner cases of software
relying on that, or explicitly reading the runlatch value (Linux does
not appear to be affected but it's possible non-Linux guests could be),
there should be no execution correctness problem, though it could be
used as a covert channel between guests.
There may be microcontrollers, firmware or monitoring tools that sample
the runlatch value out-of-band, however since the register is writable
by guests, these values would (should) not be relied upon for correct
operation of the host, so suboptimal performance or incorrect reporting
should be the worst problem.
Fixes: 95a6432ce9038 ("KVM: PPC: Book3S HV: Streamlined guest entry/exit path on P9 for radix guests")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 3 +++
1 file changed, 3 insertions(+)
@@ -3728,7 +3728,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu->arch.dec_expires=dec+tb;vcpu->cpu=-1;vcpu->arch.thread_cpu=-1;+/* Save guest CTRL register, set runlatch to 1 */vcpu->arch.ctrl=mfspr(SPRN_CTRLF);+if(!(vcpu->arch.ctrl&1))+mtspr(SPRN_CTRLT,vcpu->arch.ctrl|1);vcpu->arch.iamr=mfspr(SPRN_IAMR);vcpu->arch.pspb=mfspr(SPRN_PSPB);
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:50:23
This will get a bit more complicated in future patches. Move it
into the helper function.
This change allows the L1 hypervisor to determine some of the LPCR
bits that the L0 is using to run it, which could be a privilege
violation (LPCR is HV-privileged), although the same problem exists
now for HFSCR for example. Discussion of the HV privilege issue is
ongoing and can be resolved with a later change.
Reviewed-by: Fabiano Rosas <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv_nested.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
@@ -271,8 +290,6 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)u64hv_ptr,regs_ptr;u64hdec_exp;s64delta_purr,delta_spurr,delta_ic,delta_vtb;-u64mask;-unsignedlonglpcr;if(vcpu->kvm->arch.l1_ptcr==0)returnH_NOT_AVAILABLE;
@@ -321,9 +338,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)vcpu->arch.nested_vcpu_id=l2_hv.vcpu_token;vcpu->arch.regs=l2_regs;vcpu->arch.shregs.msr=vcpu->arch.regs.msr;-mask=LPCR_DPFD|LPCR_ILE|LPCR_TC|LPCR_AIL|LPCR_LD|-LPCR_LPES|LPCR_MER;-lpcr=(vc->lpcr&~mask)|(l2_hv.lpcr&mask);+sanitise_hv_regs(vcpu,&l2_hv);restore_hv_regs(vcpu,&l2_hv);
@@ -335,7 +350,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)r=RESUME_HOST;break;}-r=kvmhv_run_single_vcpu(vcpu,hdec_exp,lpcr);+r=kvmhv_run_single_vcpu(vcpu,hdec_exp,l2_hv.lpcr);}while(is_kvmppc_resume_guest(r));/* save L2 state for return */
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:50:48
Guest LPCR depends on hardware type, and future changes will add
restrictions based on errata and guest MMU mode. Move this logic
to a common function and use it for the cases where the guest
wants to update its LPCR (or the LPCR of a nested guest).
This also adds a warning in other places that set or update LPCR
if we try to set something that would have been disallowed by
the filter, as a sanity check.
Reviewed-by: Fabiano Rosas <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_book3s.h | 2 +
arch/powerpc/kvm/book3s_hv.c | 68 ++++++++++++++++++++-------
arch/powerpc/kvm/book3s_hv_nested.c | 8 +++-
3 files changed, 59 insertions(+), 19 deletions(-)
@@ -1635,6 +1635,35 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,return0;}+/*+*EnforcelimitsonguestLPCRvaluesbasedonhardwareavailability,+*guestconfiguration,andpossiblyhypervisorsupportandsecurity+*concerns.+*/+unsignedlongkvmppc_filter_lpcr_hv(structkvm*kvm,unsignedlonglpcr)+{+/* On POWER8 and above, userspace can modify AIL */+if(!cpu_has_feature(CPU_FTR_ARCH_207S))+lpcr&=~LPCR_AIL;++/*+*OnPOWER9,allowuserspacetoenablelargedecrementerforthe+*guest,whetherornotthehosthasitenabled.+*/+if(!cpu_has_feature(CPU_FTR_ARCH_300))+lpcr&=~LPCR_LD;++returnlpcr;+}++staticvoidverify_lpcr(structkvm*kvm,unsignedlonglpcr)+{+if(lpcr!=kvmppc_filter_lpcr_hv(kvm,lpcr)){+WARN_ONCE(1,"lpcr 0x%lx differs from filtered 0x%lx\n",+lpcr,kvmppc_filter_lpcr_hv(kvm,lpcr));+}+}+staticvoidkvmppc_set_lpcr(structkvm_vcpu*vcpu,u64new_lpcr,boolpreserve_top32){
@@ -1643,6 +1672,23 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,u64mask;spin_lock(&vc->lock);++/*+*Userspacecanonlymodify+*DPFD(defaultprefetchdepth),ILE(interruptlittle-endian),+*TC(translationcontrol),AIL(alternateinterruptlocation),+*LD(largedecrementer).+*Thesearesubjecttorestrictionsfromkvmppc_filter_lcpr_hv().+*/+mask=LPCR_DPFD|LPCR_ILE|LPCR_TC|LPCR_AIL|LPCR_LD;++/* Broken 32-bit version of LPCR must not clear top bits */+if(preserve_top32)+mask&=0xFFFFFFFF;++new_lpcr=kvmppc_filter_lpcr_hv(kvm,+(vc->lpcr&~mask)|(new_lpcr&mask));+/**IfILE(interruptlittle-endian)haschanged,updatethe*MSR_LEbitintheintr_msrforeachvcpuinthisvcore.
@@ -1661,25 +1707,8 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,}}-/*-*UserspacecanonlymodifyDPFD(defaultprefetchdepth),-*ILE(interruptlittle-endian)andTC(translationcontrol).-*OnPOWER8andPOWER9userspacecanalsomodifyAIL(alt.interruptloc.).-*/-mask=LPCR_DPFD|LPCR_ILE|LPCR_TC;-if(cpu_has_feature(CPU_FTR_ARCH_207S))-mask|=LPCR_AIL;-/*-*OnPOWER9,allowuserspacetoenablelargedecrementerforthe-*guest,whetherornotthehosthasitenabled.-*/-if(cpu_has_feature(CPU_FTR_ARCH_300))-mask|=LPCR_LD;+vc->lpcr=new_lpcr;-/* Broken 32-bit version of LPCR must not clear top bits */-if(preserve_top32)-mask&=0xFFFFFFFF;-vc->lpcr=(vc->lpcr&~mask)|(new_lpcr&mask);spin_unlock(&vc->lock);}
@@ -4644,8 +4673,10 @@ void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr, unsigned long mask)structkvmppc_vcore*vc=kvm->arch.vcores[i];if(!vc)continue;+spin_lock(&vc->lock);vc->lpcr=(vc->lpcr&~mask)|lpcr;+verify_lpcr(kvm,vc->lpcr);spin_unlock(&vc->lock);if(++cores_done>=kvm->arch.online_vcores)break;
@@ -4973,6 +5004,7 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)kvmppc_setup_partition_table(kvm);}+verify_lpcr(kvm,lpcr);kvm->arch.lpcr=lpcr;/* Initialization for future HPT resizes */
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:51:15
These are already disallowed by H_SET_MODE from the guest, also disallow
these by updating LPCR directly.
AIL modes can affect the host interrupt behaviour while the guest LPCR
value is set, so filter it here too.
Acked-by: Paul Mackerras <redacted>
Suggested-by: Fabiano Rosas <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
@@ -803,7 +803,10 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,vcpu->arch.dawrx1=value2;returnH_SUCCESS;caseH_SET_MODE_RESOURCE_ADDR_TRANS_MODE:-/* KVM does not support mflags=2 (AIL=2) */+/*+*KVMdoesnotsupportmflags=2(AIL=2)andAIL=1isreserved.+*Keepthisinsynchwithkvmppc_filter_guest_lpcr_hv.+*/if(mflags!=0&&mflags!=3)returnH_UNSUPPORTED_FLAG_START;returnH_TOO_HARD;
@@ -1645,6 +1648,8 @@ unsigned long kvmppc_filter_lpcr_hv(struct kvm *kvm, unsigned long lpcr)/* On POWER8 and above, userspace can modify AIL */if(!cpu_has_feature(CPU_FTR_ARCH_207S))lpcr&=~LPCR_AIL;+if((lpcr&LPCR_AIL)!=LPCR_AIL_3)+lpcr&=~LPCR_AIL;/* LPCR[AIL]=1/2 is disallowed *//**OnPOWER9,allowuserspacetoenablelargedecrementerforthe
@@ -1645,6 +1645,10 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,*/unsignedlongkvmppc_filter_lpcr_hv(structkvm*kvm,unsignedlonglpcr){+/* LPCR_TC only applies to HPT guests */+if(kvm_is_radix(kvm))+lpcr&=~LPCR_TC;+/* On POWER8 and above, userspace can modify AIL */if(!cpu_has_feature(CPU_FTR_ARCH_207S))lpcr&=~LPCR_AIL;
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:52:15
This SPR is set to 0 twice when exiting the guest.
Acked-by: Paul Mackerras <redacted>
Suggested-by: Fabiano Rosas <redacted>
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 1 -
1 file changed, 1 deletion(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:52:41
The va argument is not used in the function or set by its asm caller,
so remove it to be safe.
Acked-by: Paul Mackerras <redacted>
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_ppc.h | 3 +--
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:53:06
This config option causes the warning in init_default_hcalls to fire
because the TCE handlers are in the default hcall list but not
implemented.
Acked-by: Paul Mackerras <redacted>
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 2 ++
1 file changed, 2 insertions(+)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:53:53
The code being executed in KVM_GUEST_MODE_SKIP is hypervisor code with
MSR[IR]=0, so the faults of concern are the d-side ones caused by access
to guest context by the hypervisor.
Instruction breakpoint interrupts are not a concern here. It's unlikely
any good would come of causing breaks in this code, but skipping the
instruction that caused it won't help matters (e.g., skip the mtmsr that
sets MSR[DR]=0 or clears KVM_GUEST_MODE_SKIP).
[Paul notes: "the 0x1300 interrupt was dropped from the architecture a
long time ago and is not generated by P7, P8, P9 or P10." So add a
comment about this in the handler code while we're here. ]
Acked-by: Paul Mackerras <redacted>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Fabiano Rosas <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:54:17
Rather than add the ME bit to the MSR at guest entry, make it clear
that the hypervisor does not allow the guest to clear the bit.
The ME set is kept in guest entry for now, but a future patch will
warn if it's not present.
Acked-by: Paul Mackerras <redacted>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Fabiano Rosas <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv_builtin.c | 3 +++
arch/powerpc/kvm/book3s_hv_nested.c | 4 +++-
2 files changed, 6 insertions(+), 1 deletion(-)
@@ -662,6 +662,9 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu)voidkvmppc_set_msr_hv(structkvm_vcpu*vcpu,u64msr){+/* Guest must always run with ME enabled. */+msr=msr|MSR_ME;+/**Checkforillegaltransactionalstatebitcombination*andifwefindit,forcetheTSfieldtoasafestate.
@@ -343,7 +343,9 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)vcpu->arch.nested=l2;vcpu->arch.nested_vcpu_id=l2_hv.vcpu_token;vcpu->arch.regs=l2_regs;-vcpu->arch.shregs.msr=vcpu->arch.regs.msr;++/* Guest must always run with ME enabled. */+vcpu->arch.shregs.msr=vcpu->arch.regs.msr|MSR_ME;sanitise_hv_regs(vcpu,&l2_hv);restore_hv_regs(vcpu,&l2_hv);
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-12 01:54:47
Rather than clear the HV bit from the MSR at guest entry, make it clear
that the hypervisor does not allow the guest to set the bit.
The HV clear is kept in guest entry for now, but a future patch will
warn if it is set.
Acked-by: Paul Mackerras <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv_builtin.c | 4 ++--
arch/powerpc/kvm/book3s_hv_nested.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
@@ -662,8 +662,8 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu)voidkvmppc_set_msr_hv(structkvm_vcpu*vcpu,u64msr){-/* Guest must always run with ME enabled. */-msr=msr|MSR_ME;+/* Guest must always run with ME enabled, HV disabled. */+msr=(msr|MSR_ME)&~MSR_HV;/**Checkforillegaltransactionalstatebitcombination
@@ -344,8 +344,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)vcpu->arch.nested_vcpu_id=l2_hv.vcpu_token;vcpu->arch.regs=l2_regs;-/* Guest must always run with ME enabled. */-vcpu->arch.shregs.msr=vcpu->arch.regs.msr|MSR_ME;+/* Guest must always run with ME enabled, HV disabled. */+vcpu->arch.shregs.msr=(vcpu->arch.regs.msr|MSR_ME)&~MSR_HV;sanitise_hv_regs(vcpu,&l2_hv);restore_hv_regs(vcpu,&l2_hv);
The host CTRL (runlatch) value is not restored after guest exit. The
host CTRL should always be 1 except in CPU idle code, so this can result
in the host running with runlatch clear, and potentially switching to
a different vCPU which then runs with runlatch clear as well.
This has little effect on P9 machines, CTRL is only responsible for some
PMU counter logic in the host and so other than corner cases of software
relying on that, or explicitly reading the runlatch value (Linux does
not appear to be affected but it's possible non-Linux guests could be),
there should be no execution correctness problem, though it could be
used as a covert channel between guests.
There may be microcontrollers, firmware or monitoring tools that sample
the runlatch value out-of-band, however since the register is writable
by guests, these values would (should) not be relied upon for correct
operation of the host, so suboptimal performance or incorrect reporting
should be the worst problem.
Fixes: 95a6432ce9038 ("KVM: PPC: Book3S HV: Streamlined guest entry/exit path on P9 for radix guests")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 3 +++
1 file changed, 3 insertions(+)
@@ -3728,7 +3728,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu->arch.dec_expires=dec+tb;vcpu->cpu=-1;vcpu->arch.thread_cpu=-1;+/* Save guest CTRL register, set runlatch to 1 */vcpu->arch.ctrl=mfspr(SPRN_CTRLF);+if(!(vcpu->arch.ctrl&1))+mtspr(SPRN_CTRLT,vcpu->arch.ctrl|1);
Maybe ditch the comment and use the already defined CTRL_RUNLATCH?
From: Nicholas Piggin <npiggin@gmail.com> Date: 2021-04-13 01:26:29
Excerpts from Fabiano Rosas's message of April 13, 2021 12:06 am:
Nicholas Piggin [off-list ref] writes:
quoted
The host CTRL (runlatch) value is not restored after guest exit. The
host CTRL should always be 1 except in CPU idle code, so this can result
in the host running with runlatch clear, and potentially switching to
a different vCPU which then runs with runlatch clear as well.
This has little effect on P9 machines, CTRL is only responsible for some
PMU counter logic in the host and so other than corner cases of software
relying on that, or explicitly reading the runlatch value (Linux does
not appear to be affected but it's possible non-Linux guests could be),
there should be no execution correctness problem, though it could be
used as a covert channel between guests.
There may be microcontrollers, firmware or monitoring tools that sample
the runlatch value out-of-band, however since the register is writable
by guests, these values would (should) not be relied upon for correct
operation of the host, so suboptimal performance or incorrect reporting
should be the worst problem.
Fixes: 95a6432ce9038 ("KVM: PPC: Book3S HV: Streamlined guest entry/exit path on P9 for radix guests")
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kvm/book3s_hv.c | 3 +++
1 file changed, 3 insertions(+)
@@ -3728,7 +3728,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,vcpu->arch.dec_expires=dec+tb;vcpu->cpu=-1;vcpu->arch.thread_cpu=-1;+/* Save guest CTRL register, set runlatch to 1 */vcpu->arch.ctrl=mfspr(SPRN_CTRLF);+if(!(vcpu->arch.ctrl&1))+mtspr(SPRN_CTRLT,vcpu->arch.ctrl|1);
Maybe ditch the comment and use the already defined CTRL_RUNLATCH?
I did it this way so you can more easily match up the C with the
existing asm version.
I have a later patch to clean up CTRL handling a bit (in both C and
asm).
Thanks,
Nick
Rather than clear the HV bit from the MSR at guest entry, make it clear
that the hypervisor does not allow the guest to set the bit.
The HV clear is kept in guest entry for now, but a future patch will
warn if it is set.
Acked-by: Paul Mackerras <redacted>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
@@ -662,8 +662,8 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu)voidkvmppc_set_msr_hv(structkvm_vcpu*vcpu,u64msr){-/* Guest must always run with ME enabled. */-msr=msr|MSR_ME;+/* Guest must always run with ME enabled, HV disabled. */+msr=(msr|MSR_ME)&~MSR_HV;/**Checkforillegaltransactionalstatebitcombination
@@ -344,8 +344,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)vcpu->arch.nested_vcpu_id=l2_hv.vcpu_token;vcpu->arch.regs=l2_regs;-/* Guest must always run with ME enabled. */-vcpu->arch.shregs.msr=vcpu->arch.regs.msr|MSR_ME;+/* Guest must always run with ME enabled, HV disabled. */+vcpu->arch.shregs.msr=(vcpu->arch.regs.msr|MSR_ME)&~MSR_HV;sanitise_hv_regs(vcpu,&l2_hv);restore_hv_regs(vcpu,&l2_hv);
From: Michael Ellerman <hidden> Date: 2021-04-19 04:10:11
On Mon, 12 Apr 2021 11:48:33 +1000, Nicholas Piggin wrote:
Here is the first batch of patches are extracted from the patches of the
KVM C conversion series, plus one new fix (host CTRL not restored) since
v6 was posted.
Please consider for merging.
Thanks,
Nick
[...]