Skip to content

Commit 6b00864

Browse files
torvaldsakpm00
authored andcommitted
mm: move 'mmap_min_addr' logic from callers into vm_unmapped_area()
Instead of having callers care about the mmap_min_addr logic for the lowest valid mapping address (and some of them getting it wrong), just move the logic into vm_unmapped_area() itself. One less thing for various architecture cases (and generic helpers) to worry about. We should really try to make much more of this be common code, but baby steps.. Without this, vm_unmapped_area() could return an address below mmap_min_addr (because some caller forgot about that). That then causes the mmap machinery to think it has found a workable address, but then later security_mmap_addr(addr) is unhappy about it and the mmap() returns with a nonsensical error (EPERM). The proper action is to either return ENOMEM (if the virtual address space is exhausted), or try to find another address (ie do a bottom-up search for free addresses after the top-down one failed). See commit 2afc745 ("mm: ensure get_unmapped_area() returns higher address than mmap_min_addr"), which fixed this for one call site (the generic arch_get_unmapped_area_topdown() fallback) but left other cases alone. Link: https://lkml.kernel.org/r/20230418214009.1142926-1-Liam.Howlett@oracle.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Russell King <linux@armlinux.org.uk> Cc: Liam Howlett <liam.howlett@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent f724392 commit 6b00864

4 files changed

Lines changed: 16 additions & 9 deletions

File tree

arch/s390/mm/hugetlbpage.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
273273

274274
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
275275
info.length = len;
276-
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
276+
info.low_limit = PAGE_SIZE;
277277
info.high_limit = current->mm->mmap_base;
278278
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
279279
info.align_offset = 0;

arch/s390/mm/mmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long ad
136136

137137
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
138138
info.length = len;
139-
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
139+
info.low_limit = PAGE_SIZE;
140140
info.high_limit = mm->mmap_base;
141141
if (filp || (flags & MAP_SHARED))
142142
info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;

fs/hugetlbfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr,
208208

209209
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
210210
info.length = len;
211-
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
211+
info.low_limit = PAGE_SIZE;
212212
info.high_limit = arch_get_mmap_base(addr, current->mm->mmap_base);
213213
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
214214
info.align_offset = 0;

mm/mmap.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,7 +1548,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
15481548
*/
15491549
static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
15501550
{
1551-
unsigned long length, gap, low_limit;
1551+
unsigned long length, gap;
1552+
unsigned long low_limit, high_limit;
15521553
struct vm_area_struct *tmp;
15531554

15541555
MA_STATE(mas, &current->mm->mm_mt, 0, 0);
@@ -1559,8 +1560,11 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
15591560
return -ENOMEM;
15601561

15611562
low_limit = info->low_limit;
1563+
if (low_limit < mmap_min_addr)
1564+
low_limit = mmap_min_addr;
1565+
high_limit = info->high_limit;
15621566
retry:
1563-
if (mas_empty_area(&mas, low_limit, info->high_limit - 1, length))
1567+
if (mas_empty_area(&mas, low_limit, high_limit - 1, length))
15641568
return -ENOMEM;
15651569

15661570
gap = mas.index;
@@ -1596,7 +1600,8 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
15961600
*/
15971601
static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
15981602
{
1599-
unsigned long length, gap, high_limit, gap_end;
1603+
unsigned long length, gap, gap_end;
1604+
unsigned long low_limit, high_limit;
16001605
struct vm_area_struct *tmp;
16011606

16021607
MA_STATE(mas, &current->mm->mm_mt, 0, 0);
@@ -1605,10 +1610,12 @@ static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
16051610
if (length < info->length)
16061611
return -ENOMEM;
16071612

1613+
low_limit = info->low_limit;
1614+
if (low_limit < mmap_min_addr)
1615+
low_limit = mmap_min_addr;
16081616
high_limit = info->high_limit;
16091617
retry:
1610-
if (mas_empty_area_rev(&mas, info->low_limit, high_limit - 1,
1611-
length))
1618+
if (mas_empty_area_rev(&mas, low_limit, high_limit - 1, length))
16121619
return -ENOMEM;
16131620

16141621
gap = mas.last + 1 - info->length;
@@ -1743,7 +1750,7 @@ generic_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
17431750

17441751
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
17451752
info.length = len;
1746-
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
1753+
info.low_limit = PAGE_SIZE;
17471754
info.high_limit = arch_get_mmap_base(addr, mm->mmap_base);
17481755
info.align_mask = 0;
17491756
info.align_offset = 0;

0 commit comments

Comments
 (0)