[SRU][F][PATCH v2 2/2] KVM: s390: pv: don't allow userspace to set the clock under PV
Roxana Nicolescu
roxana.nicolescu at canonical.com
Fri Feb 17 10:51:52 UTC 2023
On 17-02-2023 11:50, Stefan Bader wrote:
> On 17.02.23 11:29, Roxana Nicolescu wrote:
>> From: Nico Boehr <nrb at linux.ibm.com>
>>
>> BugLink: https://bugs.launchpad.net/bugs/1999882
>>
>> [ Upstream commit 6973091d1b50ab4042f6a2d495f59e9db3662ab8 ]
>>
>> When running under PV, the guest's TOD clock is under control of the
>> ultravisor and the hypervisor isn't allowed to change it. Hence, don't
>> allow userspace to change the guest's TOD clock by returning
>> -EOPNOTSUPP.
>>
>> When userspace changes the guest's TOD clock, KVM updates its
>> kvm.arch.epoch field and, in addition, the epoch field in all state
>> descriptions of all VCPUs.
>>
>> But, under PV, the ultravisor will ignore the epoch field in the state
>> description and simply overwrite it on next SIE exit with the actual
>> guest epoch. This leads to KVM having an incorrect view of the guest's
>> TOD clock: it has updated its internal kvm.arch.epoch field, but the
>> ultravisor ignores the field in the state description.
>>
>> Whenever a guest is now waiting for a clock comparator, KVM will
>> incorrectly calculate the time when the guest should wake up, possibly
>> causing the guest to sleep for much longer than expected.
>>
>> With this change, kvm_s390_set_tod() will now take the kvm->lock to be
>> able to call kvm_s390_pv_is_protected(). Since kvm_s390_set_tod_clock()
>> also takes kvm->lock, use __kvm_s390_set_tod_clock() instead.
>>
>> The function kvm_s390_set_tod_clock is now unused, hence remove it.
>> Update the documentation to indicate the TOD clock attr calls can now
>> return -EOPNOTSUPP.
>>
>> Fixes: 0f3035047140 ("KVM: s390: protvirt: Do only reset registers
>> that are accessible")
>> Reported-by: Marc Hartmayer <mhartmay at linux.ibm.com>
>> Signed-off-by: Nico Boehr <nrb at linux.ibm.com>
>> Reviewed-by: Claudio Imbrenda <imbrenda at linux.ibm.com>
>> Reviewed-by: Janosch Frank <frankja at linux.ibm.com>
>> Link:
>> https://lore.kernel.org/r/20221011160712.928239-2-nrb@linux.ibm.com
>> Message-Id: <20221011160712.928239-2-nrb at linux.ibm.com>
>> Signed-off-by: Janosch Frank <frankja at linux.ibm.com>
>> Signed-off-by: Sasha Levin <sashal at kernel.org>
>> (backported from commmit 6973091d1b50ab4042f6a2d495f59e9db3662ab8)
>> [roxanan: commit 6c972ba685d5849009e0747cf8799adc3b8d5f11 replaces
>> Documentation/virt/kvm/devices.vm.txt with vm.rst, therefore changes
>> applied to vm.rst in the original commit were applied to vm.txt here]
>
> I would shorten this to
> [roxanan: Path to documentation file adjusted]
>
> when applying...
>
>> Signed-off-by: Roxana Nicolescu <roxana.nicolescu at canonical.com>
>> ---
>> Documentation/virt/kvm/devices/vm.txt | 4 ++++
>> arch/s390/kvm/kvm-s390.c | 26 +++++++++++++++++---------
>> arch/s390/kvm/kvm-s390.h | 1 -
>> 3 files changed, 21 insertions(+), 10 deletions(-)
>>
>> diff --git a/Documentation/virt/kvm/devices/vm.txt
>> b/Documentation/virt/kvm/devices/vm.txt
>> index 4ffb82b02468..e8c28c299144 100644
>> --- a/Documentation/virt/kvm/devices/vm.txt
>> +++ b/Documentation/virt/kvm/devices/vm.txt
>> @@ -183,6 +183,7 @@ KVM_S390_VM_TOD_EXT).
>> Parameters: address of a buffer in user space to store the data
>> (u8) to
>> Returns: -EFAULT if the given address is not accessible from
>> kernel space
>> -EINVAL if setting the TOD clock extension to != 0 is not
>> supported
>> + -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
>> 3.2. ATTRIBUTE: KVM_S390_VM_TOD_LOW
>> @@ -191,6 +192,8 @@ the POP (u64).
>> Parameters: address of a buffer in user space to store the data
>> (u64) to
>> Returns: -EFAULT if the given address is not accessible from
>> kernel space
>> + -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
>> +
>> 3.3. ATTRIBUTE: KVM_S390_VM_TOD_EXT
>> Allows user space to set/get bits 0-63 of the TOD clock register as
>> defined in
>> @@ -202,6 +205,7 @@ Parameters: address of a buffer in user space to
>> store the data
>> (kvm_s390_vm_tod_clock) to
>> Returns: -EFAULT if the given address is not accessible from
>> kernel space
>> -EINVAL if setting the TOD clock extension to != 0 is not
>> supported
>> + -EOPNOTSUPP for a PV guest (TOD managed by the ultravisor)
>> 4. GROUP: KVM_S390_VM_CRYPTO
>> Architectures: s390
>> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
>> index 0f1b0dde0de3..f505999708bd 100644
>> --- a/arch/s390/kvm/kvm-s390.c
>> +++ b/arch/s390/kvm/kvm-s390.c
>> @@ -1096,6 +1096,8 @@ static int kvm_s390_vm_get_migration(struct kvm
>> *kvm,
>> return 0;
>> }
>> +static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct
>> kvm_s390_vm_tod_clock *gtod);
>> +
>> static int kvm_s390_set_tod_ext(struct kvm *kvm, struct
>> kvm_device_attr *attr)
>> {
>> struct kvm_s390_vm_tod_clock gtod;
>> @@ -1105,7 +1107,7 @@ static int kvm_s390_set_tod_ext(struct kvm
>> *kvm, struct kvm_device_attr *attr)
>> if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
>> return -EINVAL;
>> - kvm_s390_set_tod_clock(kvm, >od);
>> + __kvm_s390_set_tod_clock(kvm, >od);
>> VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
>> gtod.epoch_idx, gtod.tod);
>> @@ -1136,7 +1138,7 @@ static int kvm_s390_set_tod_low(struct kvm
>> *kvm, struct kvm_device_attr *attr)
>> sizeof(gtod.tod)))
>> return -EFAULT;
>> - kvm_s390_set_tod_clock(kvm, >od);
>> + __kvm_s390_set_tod_clock(kvm, >od);
>> VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
>> return 0;
>> }
>> @@ -1148,6 +1150,16 @@ static int kvm_s390_set_tod(struct kvm *kvm,
>> struct kvm_device_attr *attr)
>> if (attr->flags)
>> return -EINVAL;
>> + mutex_lock(&kvm->lock);
>> + /*
>> + * For protected guests, the TOD is managed by the ultravisor,
>> so trying
>> + * to change it will never bring the expected results.
>> + */
>> + if (kvm_s390_pv_is_protected(kvm)) {
>> + ret = -EOPNOTSUPP;
>> + goto out_unlock;
>> + }
>> +
>> switch (attr->attr) {
>> case KVM_S390_VM_TOD_EXT:
>> ret = kvm_s390_set_tod_ext(kvm, attr);
>> @@ -1162,6 +1174,9 @@ static int kvm_s390_set_tod(struct kvm *kvm,
>> struct kvm_device_attr *attr)
>> ret = -ENXIO;
>> break;
>> }
>> +
>> +out_unlock:
>> + mutex_unlock(&kvm->lock);
>> return ret;
>> }
>> @@ -3968,13 +3983,6 @@ static void __kvm_s390_set_tod_clock(struct
>> kvm *kvm, const struct kvm_s390_vm_t
>> preempt_enable();
>> }
>> -void kvm_s390_set_tod_clock(struct kvm *kvm, const struct
>> kvm_s390_vm_tod_clock *gtod)
>> -{
>> - mutex_lock(&kvm->lock);
>> - __kvm_s390_set_tod_clock(kvm, gtod);
>> - mutex_unlock(&kvm->lock);
>> -}
>> -
>> int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct
>> kvm_s390_vm_tod_clock *gtod)
>> {
>> if (!mutex_trylock(&kvm->lock))
>> diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
>> index c94c1e29eeca..487b2bd53599 100644
>> --- a/arch/s390/kvm/kvm-s390.h
>> +++ b/arch/s390/kvm/kvm-s390.h
>> @@ -335,7 +335,6 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
>> int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
>> /* implemented in kvm-s390.c */
>> -void kvm_s390_set_tod_clock(struct kvm *kvm, const struct
>> kvm_s390_vm_tod_clock *gtod);
>> int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct
>> kvm_s390_vm_tod_clock *gtod);
>> long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int
>> writable);
>> int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned
>> long addr);
>
>
Thanks Stefan. I will apply your feedback for next submissions :)
Roxana
More information about the kernel-team
mailing list