Skip to content

Commit 23be746

Browse files
gormanmtorvalds
authored andcommitted
hugetlb: fix infinite loop in get_futex_key() when backed by huge pages
If a futex key happens to be located within a huge page mapped MAP_PRIVATE, get_futex_key() can go into an infinite loop waiting for a page->mapping that will never exist. See https://bugzilla.redhat.com/show_bug.cgi?id=552257 for more details about the problem. This patch makes page->mapping a poisoned value that includes PAGE_MAPPING_ANON mapped MAP_PRIVATE. This is enough for futex to continue but because of PAGE_MAPPING_ANON, the poisoned value is not dereferenced or used by futex. No other part of the VM should be dereferencing the page->mapping of a hugetlbfs page as its page cache is not on the LRU. This patch fixes the problem with the test case described in the bugzilla. [[email protected]: mel cant spel] Signed-off-by: Mel Gorman <[email protected]> Acked-by: Peter Zijlstra <[email protected]> Acked-by: Darren Hart <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 9a6a1ec commit 23be746

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

include/linux/poison.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@
4848
#define POISON_FREE 0x6b /* for use-after-free poisoning */
4949
#define POISON_END 0xa5 /* end-byte of poisoning */
5050

51+
/********** mm/hugetlb.c **********/
52+
/*
53+
* Private mappings of hugetlb pages use this poisoned value for
54+
* page->mapping. The core VM should not be doing anything with this mapping
55+
* but futex requires the existence of some page->mapping value even though it
56+
* is unused if PAGE_MAPPING_ANON is set.
57+
*/
58+
#define HUGETLB_POISON ((void *)(0x00300300 + POISON_POINTER_DELTA + PAGE_MAPPING_ANON))
59+
5160
/********** arch/$ARCH/mm/init.c **********/
5261
#define POISON_FREE_INITMEM 0xcc
5362

mm/hugetlb.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ static void free_huge_page(struct page *page)
546546

547547
mapping = (struct address_space *) page_private(page);
548548
set_page_private(page, 0);
549+
page->mapping = NULL;
549550
BUG_ON(page_count(page));
550551
INIT_LIST_HEAD(&page->lru);
551552

@@ -2447,8 +2448,10 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
24472448
spin_lock(&inode->i_lock);
24482449
inode->i_blocks += blocks_per_huge_page(h);
24492450
spin_unlock(&inode->i_lock);
2450-
} else
2451+
} else {
24512452
lock_page(page);
2453+
page->mapping = HUGETLB_POISON;
2454+
}
24522455
}
24532456

24542457
/*

0 commit comments

Comments
 (0)