Skip to content

Commit ca23cbb

Browse files
mjkravetzksacilotto
authored andcommitted
hugetlb: fix copy_huge_page_from_user contig page struct assumption
BugLink: https://bugs.launchpad.net/bugs/1918974 commit 3272cfc 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: 8fb5deb ("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> Signed-off-by: Kamal Mostafa <kamal@canonical.com> Signed-off-by: Kelsey Skunberg <kelsey.skunberg@canonical.com>
1 parent fd6126b commit ca23cbb

File tree

1 file changed

+6
-4
lines changed

1 file changed

+6
-4
lines changed

mm/memory.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4719,17 +4719,19 @@ long copy_huge_page_from_user(struct page *dst_page,
47194719
void *page_kaddr;
47204720
unsigned long i, rc = 0;
47214721
unsigned long ret_val = pages_per_huge_page * PAGE_SIZE;
4722+
struct page *subpage = dst_page;
47224723

4723-
for (i = 0; i < pages_per_huge_page; i++) {
4724+
for (i = 0; i < pages_per_huge_page;
4725+
i++, subpage = mem_map_next(subpage, dst_page, i)) {
47244726
if (allow_pagefault)
4725-
page_kaddr = kmap(dst_page + i);
4727+
page_kaddr = kmap(subpage);
47264728
else
4727-
page_kaddr = kmap_atomic(dst_page + i);
4729+
page_kaddr = kmap_atomic(subpage);
47284730
rc = copy_from_user(page_kaddr,
47294731
(const void __user *)(src + i * PAGE_SIZE),
47304732
PAGE_SIZE);
47314733
if (allow_pagefault)
4732-
kunmap(dst_page + i);
4734+
kunmap(subpage);
47334735
else
47344736
kunmap_atomic(page_kaddr);
47354737

0 commit comments

Comments
 (0)