• Lorenzo Stoakes's avatar
    mm: rework vm_ops->close() handling on VMA merge · 01c373e9
    Lorenzo Stoakes authored
    In commit 714965ca ("mm/mmap: start distinguishing if vma can be
    removed in mergeability test") we relaxed the VMA merge rules for VMAs
    possessing a vm_ops->close() hook, permitting this operation in instances
    where we wouldn't delete the VMA as part of the merge operation.
    
    This was later corrected in commit fc0c8f90 ("mm, mmap: fix
    vma_merge() case 7 with vma_ops->close") to account for a subtle case that
    the previous commit had not taken into account.
    
    In both instances, we first rely on is_mergeable_vma() to determine
    whether we might be dealing with a VMA that might be removed, taking
    advantage of the fact that a 'previous' VMA will never be deleted, only
    VMAs that follow it.
    
    The second patch corrects the instance where a merge of the previous VMA
    into a subsequent one did not correctly check whether the subsequent VMA
    had a vm_ops->close() handler.
    
    Both changes prevent merge cases that are actually permissible (for
    instance a merge of a VMA into a following VMA with a vm_ops->close(), but
    with no previous VMA, which would result in the next VMA being extended,
    not deleted).
    
    In addition, both changes fail to consider the case where a VMA that would
    otherwise be merged with the previous and next VMA might have
    vm_ops->close(), on the assumption that for this to be the case, all three
    would have to have the same vma->vm_file to be mergeable and thus the same
    vm_ops.
    
    And in addition both changes operate at 50,000 feet, trying to guess
    whether a VMA will be deleted.
    
    As we have majorly refactored the VMA merge operation and de-duplicated
    code to the point where we know precisely where deletions will occur, this
    patch removes the aforementioned checks altogether and instead explicitly
    checks whether a VMA will be deleted.
    
    In cases where a reduced merge is still possible (where we merge both
    previous and next VMA but the next VMA has a vm_ops->close hook, meaning
    we could just merge the previous and current VMA), we do so, otherwise the
    merge is not permitted.
    
    We take advantage of our userland testing to assert that this functions
    correctly - replacing the previous limited vm_ops->close() tests with
    tests for every single case where we delete a VMA.
    
    We also update all testing for both new and modified VMAs to set
    vma->vm_ops->close() in every single instance where this would not prevent
    the merge, to assert that we never do so.
    
    Link: https://lkml.kernel.org/r/9f96b8cfeef3d14afabddac3d6144afdfbef2e22.1725040657.git.lorenzo.stoakes@oracle.comSigned-off-by: default avatarLorenzo Stoakes <lorenzo.stoakes@oracle.com>
    Acked-by: default avatarVlastimil Babka <vbabka@suse.cz>
    Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
    Cc: Mark Brown <broonie@kernel.org>
    Cc: Bert Karwatzki <spasswolf@web.de>
    Cc: Jeff Xu <jeffxu@chromium.org>
    Cc: Jiri Olsa <olsajiri@gmail.com>
    Cc: Kees Cook <kees@kernel.org>
    Cc: Lorenzo Stoakes <lstoakes@gmail.com>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: "Paul E. McKenney" <paulmck@kernel.org>
    Cc: Paul Moore <paul@paul-moore.com>
    Cc: Sidhartha Kumar <sidhartha.kumar@oracle.com>
    Cc: Suren Baghdasaryan <surenb@google.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    01c373e9
vma.c 39.9 KB