> #define CPUSTAT_STOPPED 0x80000000 > #define CPUSTAT_WAIT 0x10000000 > #define CPUSTAT_ECALL_PEND 0x08000000 > @@ -315,7 +321,10 @@ struct kvm_s390_sie_block { > #define CRYCB_FORMAT2 0x00000003 > __u32 crycbd; /* 0x00fc */ > __u64 gcr[16]; /* 0x0100 */ > - __u64 gbea; /* 0x0180 */ > + union { > + __u64 gbea; /* 0x0180 */ > + __u64 sidad; > + }; > __u8 reserved188[8]; /* 0x0188 */ > __u64 sdnxo; /* 0x0190 */ > __u8 reserved198[8]; /* 0x0198 */ > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c > index 6f90d16cad92..56488f9ed190 100644 > --- a/arch/s390/kvm/kvm-s390.c > +++ b/arch/s390/kvm/kvm-s390.c > @@ -4435,6 +4435,41 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, > return r; > } > > +static long kvm_s390_guest_sida_op(struct kvm_vcpu *vcpu, > + struct kvm_s390_mem_op *mop) > +{ > + void __user *uaddr = (void __user *)mop->buf; > + int r = 0; > + > + if (mop->flags || !mop->size) > + return -EINVAL; > + > + if (mop->size > sida_size(vcpu->arch.sie_block)) > + return -E2BIG; > + > + if (mop->sida_offset > sida_size(vcpu->arch.sie_block)) > + return -E2BIG; > + > + if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block)) > + return -E2BIG; > + if (mop->size + mop->sida_offset > mop->size) return -EINVAL; if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block)) return -E2BIG; Should be sufficient (instead of 3 checks). > + switch (mop->op) { > + case KVM_S390_MEMOP_SIDA_READ: > + r = 0; > + if (copy_to_user(uaddr, (void *)(sida_origin(vcpu->arch.sie_block) + > + mop->sida_offset), mop->size)) > + r = -EFAULT; > + > + break; > + case KVM_S390_MEMOP_SIDA_WRITE: > + r = 0; > + if (copy_from_user((void *)(sida_origin(vcpu->arch.sie_block) + > + mop->sida_offset), uaddr, mop->size)) > + r = -EFAULT; > + break; > + } > + return r; > +} > static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, > struct kvm_s390_mem_op *mop) > { > @@ -4444,6 +4479,8 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, > const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION > | KVM_S390_MEMOP_F_CHECK_ONLY; > > + > + BUILD_BUG_ON(sizeof(*mop) != 64); > if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size) > return -EINVAL; > > @@ -4460,6 +4497,10 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, > > switch (mop->op) { > case KVM_S390_MEMOP_LOGICAL_READ: > + if (kvm_s390_pv_is_protected(vcpu->kvm)) { > + r = -EINVAL; > + break; > + } Race with PV_VM_DESTROY (freeing sidad) > if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) { > r = check_gva_range(vcpu, mop->gaddr, mop->ar, > mop->size, GACC_FETCH); > @@ -4472,6 +4513,10 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, > } > break; > case KVM_S390_MEMOP_LOGICAL_WRITE: > + if (kvm_s390_pv_is_protected(vcpu->kvm)) { > + r = -EINVAL; > + break; > + } Race with PV_VM_DESTROY (freeing sidad) -- Thanks, David / dhildenb