| From eb7511bf9182292ef1df1082d23039e856d1ddfb Mon Sep 17 00:00:00 2001 |
| From: Haimin Zhang <tcs_kernel@tencent.com> |
| Date: Fri, 3 Sep 2021 10:37:06 +0800 |
| Subject: KVM: x86: Handle SRCU initialization failure during page track init |
| |
| From: Haimin Zhang <tcs_kernel@tencent.com> |
| |
| commit eb7511bf9182292ef1df1082d23039e856d1ddfb upstream. |
| |
| Check the return of init_srcu_struct(), which can fail due to OOM, when |
| initializing the page track mechanism. Lack of checking leads to a NULL |
| pointer deref found by a modified syzkaller. |
| |
| Reported-by: TCS Robot <tcs_robot@tencent.com> |
| Signed-off-by: Haimin Zhang <tcs_kernel@tencent.com> |
| Message-Id: <1630636626-12262-1-git-send-email-tcs_kernel@tencent.com> |
| [Move the call towards the beginning of kvm_arch_init_vm. - Paolo] |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/include/asm/kvm_page_track.h | 2 +- |
| arch/x86/kvm/mmu/page_track.c | 4 ++-- |
| arch/x86/kvm/x86.c | 7 ++++++- |
| 3 files changed, 9 insertions(+), 4 deletions(-) |
| |
| --- a/arch/x86/include/asm/kvm_page_track.h |
| +++ b/arch/x86/include/asm/kvm_page_track.h |
| @@ -46,7 +46,7 @@ struct kvm_page_track_notifier_node { |
| struct kvm_page_track_notifier_node *node); |
| }; |
| |
| -void kvm_page_track_init(struct kvm *kvm); |
| +int kvm_page_track_init(struct kvm *kvm); |
| void kvm_page_track_cleanup(struct kvm *kvm); |
| |
| void kvm_page_track_free_memslot(struct kvm_memory_slot *slot); |
| --- a/arch/x86/kvm/mmu/page_track.c |
| +++ b/arch/x86/kvm/mmu/page_track.c |
| @@ -163,13 +163,13 @@ void kvm_page_track_cleanup(struct kvm * |
| cleanup_srcu_struct(&head->track_srcu); |
| } |
| |
| -void kvm_page_track_init(struct kvm *kvm) |
| +int kvm_page_track_init(struct kvm *kvm) |
| { |
| struct kvm_page_track_notifier_head *head; |
| |
| head = &kvm->arch.track_notifier_head; |
| - init_srcu_struct(&head->track_srcu); |
| INIT_HLIST_HEAD(&head->track_notifier_list); |
| + return init_srcu_struct(&head->track_srcu); |
| } |
| |
| /* |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -10392,9 +10392,15 @@ void kvm_arch_free_vm(struct kvm *kvm) |
| |
| int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) |
| { |
| + int ret; |
| + |
| if (type) |
| return -EINVAL; |
| |
| + ret = kvm_page_track_init(kvm); |
| + if (ret) |
| + return ret; |
| + |
| INIT_HLIST_HEAD(&kvm->arch.mask_notifier_list); |
| INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); |
| INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages); |
| @@ -10421,7 +10427,6 @@ int kvm_arch_init_vm(struct kvm *kvm, un |
| INIT_DELAYED_WORK(&kvm->arch.kvmclock_sync_work, kvmclock_sync_fn); |
| |
| kvm_hv_init_vm(kvm); |
| - kvm_page_track_init(kvm); |
| kvm_mmu_init_vm(kvm); |
| |
| return kvm_x86_ops.vm_init(kvm); |