Commit 23be7468e8802a2ac1de6ee3eecb3ec7f14dc703
Committed by
Linus Torvalds
1 parent
9a6a1ecd9e
Exists in
master
and in
4 other branches
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. [akpm@linux-foundation.org: mel cant spel] Signed-off-by: Mel Gorman <mel@csn.ul.ie> Acked-by: Peter Zijlstra <peterz@infradead.org> Acked-by: Darren Hart <darren@dvhart.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 2 changed files with 13 additions and 1 deletions Side-by-side Diff
include/linux/poison.h
... | ... | @@ -48,6 +48,15 @@ |
48 | 48 | #define POISON_FREE 0x6b /* for use-after-free poisoning */ |
49 | 49 | #define POISON_END 0xa5 /* end-byte of poisoning */ |
50 | 50 | |
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 | + | |
51 | 60 | /********** arch/$ARCH/mm/init.c **********/ |
52 | 61 | #define POISON_FREE_INITMEM 0xcc |
53 | 62 |
mm/hugetlb.c
... | ... | @@ -546,6 +546,7 @@ |
546 | 546 | |
547 | 547 | mapping = (struct address_space *) page_private(page); |
548 | 548 | set_page_private(page, 0); |
549 | + page->mapping = NULL; | |
549 | 550 | BUG_ON(page_count(page)); |
550 | 551 | INIT_LIST_HEAD(&page->lru); |
551 | 552 | |
552 | 553 | |
... | ... | @@ -2447,8 +2448,10 @@ |
2447 | 2448 | spin_lock(&inode->i_lock); |
2448 | 2449 | inode->i_blocks += blocks_per_huge_page(h); |
2449 | 2450 | spin_unlock(&inode->i_lock); |
2450 | - } else | |
2451 | + } else { | |
2451 | 2452 | lock_page(page); |
2453 | + page->mapping = HUGETLB_POISON; | |
2454 | + } | |
2452 | 2455 | } |
2453 | 2456 | |
2454 | 2457 | /* |