lkml.org 
[lkml]   [2021]   [Mar]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.11 704/775] hugetlb: fix copy_huge_page_from_user contig page struct assumption
    Date
    From: Mike Kravetz <mike.kravetz@oracle.com>

    commit 3272cfc2525b3a2810a59312d7a1e6f04a0ca3ef upstream.

    page structs are not guaranteed to be contiguous for gigantic pages. The
    routine copy_huge_page_from_user can encounter gigantic pages, yet it
    assumes page structs are contiguous when copying pages from user space.

    Since page structs for the target gigantic page are not contiguous, the
    data copied from user space could overwrite other pages not associated
    with the gigantic page and cause data corruption.

    Non-contiguous page structs are generally not an issue. However, they can
    exist with a specific kernel configuration and hotplug operations. For
    example: Configure the kernel with CONFIG_SPARSEMEM and
    !CONFIG_SPARSEMEM_VMEMMAP. Then, hotplug add memory for the area where
    the gigantic page will be allocated.

    Link: https://lkml.kernel.org/r/20210217184926.33567-2-mike.kravetz@oracle.com
    Fixes: 8fb5debc5fcd ("userfaultfd: hugetlbfs: add hugetlb_mcopy_atomic_pte for userfaultfd support")
    Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
    Cc: Zi Yan <ziy@nvidia.com>
    Cc: Davidlohr Bueso <dbueso@suse.de>
    Cc: "Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>
    Cc: Andrea Arcangeli <aarcange@redhat.com>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: Oscar Salvador <osalvador@suse.de>
    Cc: Joao Martins <joao.m.martins@oracle.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/memory.c | 10 ++++++----
    1 file changed, 6 insertions(+), 4 deletions(-)

    --- a/mm/memory.c
    +++ b/mm/memory.c
    @@ -5204,17 +5204,19 @@ long copy_huge_page_from_user(struct pag
    void *page_kaddr;
    unsigned long i, rc = 0;
    unsigned long ret_val = pages_per_huge_page * PAGE_SIZE;
    + struct page *subpage = dst_page;

    - for (i = 0; i < pages_per_huge_page; i++) {
    + for (i = 0; i < pages_per_huge_page;
    + i++, subpage = mem_map_next(subpage, dst_page, i)) {
    if (allow_pagefault)
    - page_kaddr = kmap(dst_page + i);
    + page_kaddr = kmap(subpage);
    else
    - page_kaddr = kmap_atomic(dst_page + i);
    + page_kaddr = kmap_atomic(subpage);
    rc = copy_from_user(page_kaddr,
    (const void __user *)(src + i * PAGE_SIZE),
    PAGE_SIZE);
    if (allow_pagefault)
    - kunmap(dst_page + i);
    + kunmap(subpage);
    else
    kunmap_atomic(page_kaddr);


    \
     
     \ /
      Last update: 2021-03-02 14:40    [W:2.786 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site