On Tue Aug 5, 2025 at 1:14 PM CEST, Claudio Imbrenda wrote: > If mmu_notifier_register() fails, for example because a signal was > pending, the mmu_notifier will not be registered. But when the VM gets > destroyed, it will get unregistered anyway and that will cause one > extra mmdrop(), which will eventually cause the mm of the process to > be freed too early, and cause a use-after free. > > This bug happens rarely, and only when secure guests are involved. > > The solution is to check the return value of mmu_notifier_register() > and return it to the caller (ultimately it will be propagated all the > way to userspace). In case of -EINTR, userspace will try again. > > Fixes: ca2fd0609b5d ("KVM: s390: pv: add mmu_notifier") > Signed-off-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> Reviewed-by: Christoph Schlameuss <schlameuss@xxxxxxxxxxxxx> > --- > arch/s390/kvm/pv.c | 14 +++++++++----- > 1 file changed, 9 insertions(+), 5 deletions(-) > > diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c > index 14c330ec8ceb..e85fb3247b0e 100644 > --- a/arch/s390/kvm/pv.c > +++ b/arch/s390/kvm/pv.c > @@ -622,6 +622,15 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) > int cc, ret; > u16 dummy; > > + /* Add the notifier only once. No races because we hold kvm->lock */ > + if (kvm->arch.pv.mmu_notifier.ops != &kvm_s390_pv_mmu_notifier_ops) { > + ret = mmu_notifier_register(&kvm->arch.pv.mmu_notifier, kvm->mm); > + if (ret) > + return ret; > + /* The notifier will be unregistered when the VM is destroyed */ > + kvm->arch.pv.mmu_notifier.ops = &kvm_s390_pv_mmu_notifier_ops; > + } > + > ret = kvm_s390_pv_alloc_vm(kvm); > if (ret) > return ret; > @@ -657,11 +666,6 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) > return -EIO; > } > kvm->arch.gmap->guest_handle = uvcb.guest_handle; > - /* Add the notifier only once. No races because we hold kvm->lock */ > - if (kvm->arch.pv.mmu_notifier.ops != &kvm_s390_pv_mmu_notifier_ops) { > - kvm->arch.pv.mmu_notifier.ops = &kvm_s390_pv_mmu_notifier_ops; > - mmu_notifier_register(&kvm->arch.pv.mmu_notifier, kvm->mm); > - } > return 0; > } >