Skip to content

Commit dffe24e

Browse files
donettom-1akpm00
authored andcommitted
hugetlbfs: ensure generic_hugetlb_get_unmapped_area() returns higher address than mmap_min_addr
generic_hugetlb_get_unmapped_area() was returning an address less than mmap_min_addr if the mmap argument addr, after alignment, was less than mmap_min_addr, causing mmap to fail. This is because current generic_hugetlb_get_unmapped_area() code does not take into account mmap_min_addr. This patch ensures that generic_hugetlb_get_unmapped_area() always returns an address that is greater than mmap_min_addr. Additionally, similar to generic_get_unmapped_area(), vm_end_gap() checks are included to maintain stack gap. How to reproduce ================ #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #define HUGEPAGE_SIZE (16 * 1024 * 1024) int main() { void *addr = mmap((void *)-1, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); if (addr == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } snprintf((char *)addr, HUGEPAGE_SIZE, "Hello, Huge Pages!"); printf("%s\n", (char *)addr); if (munmap(addr, HUGEPAGE_SIZE) == -1) { perror("munmap"); exit(EXIT_FAILURE); } return 0; } Result without fix ================== # cat /proc/meminfo |grep -i HugePages_Free HugePages_Free: 20 # ./test mmap: Permission denied # Result with fix =============== # cat /proc/meminfo |grep -i HugePages_Free HugePages_Free: 20 # ./test Hello, Huge Pages! # Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Donet Tom <[email protected]> Reported-by Pavithra Prakash <[email protected]> Acked-by: Kirill A. Shutemov <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Aneesh Kumar K.V <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Cc: Mike Rapoport (IBM) <[email protected]> Cc: Muchun Song <[email protected]> Cc: Nicholas Piggin <[email protected]> Cc: Ritesh Harjani (IBM) <[email protected]> Cc: Tony Battersby <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 63d9866 commit dffe24e

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

fs/hugetlbfs/inode.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,13 @@ generic_hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
222222
unsigned long flags)
223223
{
224224
struct mm_struct *mm = current->mm;
225-
struct vm_area_struct *vma;
225+
struct vm_area_struct *vma, *prev;
226226
struct hstate *h = hstate_file(file);
227227
const unsigned long mmap_end = arch_get_mmap_end(addr, len, flags);
228228

229229
if (len & ~huge_page_mask(h))
230230
return -EINVAL;
231-
if (len > TASK_SIZE)
231+
if (len > mmap_end - mmap_min_addr)
232232
return -ENOMEM;
233233

234234
if (flags & MAP_FIXED) {
@@ -239,9 +239,10 @@ generic_hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
239239

240240
if (addr) {
241241
addr = ALIGN(addr, huge_page_size(h));
242-
vma = find_vma(mm, addr);
243-
if (mmap_end - len >= addr &&
244-
(!vma || addr + len <= vm_start_gap(vma)))
242+
vma = find_vma_prev(mm, addr, &prev);
243+
if (mmap_end - len >= addr && addr >= mmap_min_addr &&
244+
(!vma || addr + len <= vm_start_gap(vma)) &&
245+
(!prev || addr >= vm_end_gap(prev)))
245246
return addr;
246247
}
247248

0 commit comments

Comments
 (0)