Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/mm: Implement ASLR for hugetlb mappings

Matthew noticed that hugetlb mappings don't participate in ASLR on x86-64:

% for i in `seq 3`; do
> tools/testing/selftests/vm/map_hugetlb | grep address
> done
Returned address is 0x2aaaaac00000
Returned address is 0x2aaaaac00000
Returned address is 0x2aaaaac00000

/proc/PID/maps entries for the mapping are always the same
(except inode number):

2aaaaac00000-2aaabac00000 rw-p 00000000 00:0c 8200 /anon_hugepage (deleted)
2aaaaac00000-2aaabac00000 rw-p 00000000 00:0c 256 /anon_hugepage (deleted)
2aaaaac00000-2aaabac00000 rw-p 00000000 00:0c 7180 /anon_hugepage (deleted)

The reason is the generic hugetlb_get_unmapped_area() function
which is used on x86-64. It doesn't support randomization and
use bottom-up unmapped area lookup, instead of usual top-down
on x86-64.

x86 has arch-specific hugetlb_get_unmapped_area(), but it's used
only on x86-32.

Let's use arch-specific hugetlb_get_unmapped_area() on x86-64
too. That adds ASLR and switches hugetlb mappings to use top-down
unmapped area lookup:

% for i in `seq 3`; do
> tools/testing/selftests/vm/map_hugetlb | grep address
> done
Returned address is 0x7f4f08a00000
Returned address is 0x7fdda4200000
Returned address is 0x7febe0000000

/proc/PID/maps entries:

7f4f08a00000-7f4f18a00000 rw-p 00000000 00:0c 1168 /anon_hugepage (deleted)
7fdda4200000-7fddb4200000 rw-p 00000000 00:0c 7092 /anon_hugepage (deleted)
7febe0000000-7febf0000000 rw-p 00000000 00:0c 7183 /anon_hugepage (deleted)

Unmapped area lookup policy for hugetlb mappings is consistent
with normal mappings now -- the only difference is alignment
requirements for huge pages.

libhugetlbfs test-suite didn't detect any regressions with the
patch applied (although it shows few failures on my machine
regardless the patch).

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Matthew Wilcox <willy@linux.intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mel Gorman <mgorman@suse.de>
Link: http://lkml.kernel.org/r/20131119131750.EA45CE0090@blue.fi.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Kirill A. Shutemov and committed by
Ingo Molnar
fd8526ad 5305ca10

+4 -10
+1
arch/x86/include/asm/page.h
··· 71 71 #include <asm-generic/getorder.h> 72 72 73 73 #define __HAVE_ARCH_GATE_AREA 1 74 + #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA 74 75 75 76 #endif /* __KERNEL__ */ 76 77 #endif /* _ASM_X86_PAGE_H */
-4
arch/x86/include/asm/page_32.h
··· 5 5 6 6 #ifndef __ASSEMBLY__ 7 7 8 - #ifdef CONFIG_HUGETLB_PAGE 9 - #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA 10 - #endif 11 - 12 8 #define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET) 13 9 #ifdef CONFIG_DEBUG_VIRTUAL 14 10 extern unsigned long __phys_addr(unsigned long);
+3 -6
arch/x86/mm/hugetlbpage.c
··· 87 87 } 88 88 #endif 89 89 90 - /* x86_64 also uses this file */ 91 - 92 - #ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA 90 + #ifdef CONFIG_HUGETLB_PAGE 93 91 static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, 94 92 unsigned long addr, unsigned long len, 95 93 unsigned long pgoff, unsigned long flags) ··· 97 99 98 100 info.flags = 0; 99 101 info.length = len; 100 - info.low_limit = TASK_UNMAPPED_BASE; 102 + info.low_limit = current->mm->mmap_legacy_base; 101 103 info.high_limit = TASK_SIZE; 102 104 info.align_mask = PAGE_MASK & ~huge_page_mask(h); 103 105 info.align_offset = 0; ··· 170 172 return hugetlb_get_unmapped_area_topdown(file, addr, len, 171 173 pgoff, flags); 172 174 } 173 - 174 - #endif /*HAVE_ARCH_HUGETLB_UNMAPPED_AREA*/ 175 + #endif /* CONFIG_HUGETLB_PAGE */ 175 176 176 177 #ifdef CONFIG_X86_64 177 178 static __init int setup_hugepagesz(char *opt)