lkml.org 
[lkml]   [2018]   [Nov]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.18 247/350] mm/hmm: fix race between hmm_mirror_unregister() and mmu_notifier callback
    Date
    4.18-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Ralph Campbell <rcampbell@nvidia.com>

    commit 86a2d59841ab0b147ffc1b7b3041af87927cf312 upstream.

    In hmm_mirror_unregister(), mm->hmm is set to NULL and then
    mmu_notifier_unregister_no_release() is called. That creates a small
    window where mmu_notifier can call mmu_notifier_ops with mm->hmm equal to
    NULL. Fix this by first unregistering mmu notifier callbacks and then
    setting mm->hmm to NULL.

    Similarly in hmm_register(), set mm->hmm before registering mmu_notifier
    callbacks so callback functions always see mm->hmm set.

    Link: http://lkml.kernel.org/r/20181019160442.18723-4-jglisse@redhat.com
    Signed-off-by: Ralph Campbell <rcampbell@nvidia.com>
    Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
    Reviewed-by: John Hubbard <jhubbard@nvidia.com>
    Reviewed-by: Jérôme Glisse <jglisse@redhat.com>
    Reviewed-by: Balbir Singh <bsingharora@gmail.com>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    mm/hmm.c | 36 +++++++++++++++++++++---------------
    1 file changed, 21 insertions(+), 15 deletions(-)

    --- a/mm/hmm.c
    +++ b/mm/hmm.c
    @@ -91,16 +91,6 @@ static struct hmm *hmm_register(struct m
    spin_lock_init(&hmm->lock);
    hmm->mm = mm;

    - /*
    - * We should only get here if hold the mmap_sem in write mode ie on
    - * registration of first mirror through hmm_mirror_register()
    - */
    - hmm->mmu_notifier.ops = &hmm_mmu_notifier_ops;
    - if (__mmu_notifier_register(&hmm->mmu_notifier, mm)) {
    - kfree(hmm);
    - return NULL;
    - }
    -
    spin_lock(&mm->page_table_lock);
    if (!mm->hmm)
    mm->hmm = hmm;
    @@ -108,12 +98,27 @@ static struct hmm *hmm_register(struct m
    cleanup = true;
    spin_unlock(&mm->page_table_lock);

    - if (cleanup) {
    - mmu_notifier_unregister(&hmm->mmu_notifier, mm);
    - kfree(hmm);
    - }
    + if (cleanup)
    + goto error;
    +
    + /*
    + * We should only get here if hold the mmap_sem in write mode ie on
    + * registration of first mirror through hmm_mirror_register()
    + */
    + hmm->mmu_notifier.ops = &hmm_mmu_notifier_ops;
    + if (__mmu_notifier_register(&hmm->mmu_notifier, mm))
    + goto error_mm;

    return mm->hmm;
    +
    +error_mm:
    + spin_lock(&mm->page_table_lock);
    + if (mm->hmm == hmm)
    + mm->hmm = NULL;
    + spin_unlock(&mm->page_table_lock);
    +error:
    + kfree(hmm);
    + return NULL;
    }

    void hmm_mm_destroy(struct mm_struct *mm)
    @@ -275,12 +280,13 @@ void hmm_mirror_unregister(struct hmm_mi
    if (!should_unregister || mm == NULL)
    return;

    + mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
    +
    spin_lock(&mm->page_table_lock);
    if (mm->hmm == hmm)
    mm->hmm = NULL;
    spin_unlock(&mm->page_table_lock);

    - mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
    kfree(hmm);
    }
    EXPORT_SYMBOL(hmm_mirror_unregister);

    \
     
     \ /
      Last update: 2018-11-12 00:23    [W:4.119 / U:0.272 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site