Skip to content

Commit 9611487

Browse files
rpedgecoakpm00
authored andcommitted
mm: introduce arch_get_unmapped_area_vmflags()
When memory is being placed, mmap() will take care to respect the guard gaps of certain types of memory (VM_SHADOWSTACK, VM_GROWSUP and VM_GROWSDOWN). In order to ensure guard gaps between mappings, mmap() needs to consider two things: 1. That the new mapping isn't placed in an any existing mappings guard gaps. 2. That the new mapping isn't placed such that any existing mappings are not in *its* guard gaps. The longstanding behavior of mmap() is to ensure 1, but not take any care around 2. So for example, if there is a PAGE_SIZE free area, and a mmap() with a PAGE_SIZE size, and a type that has a guard gap is being placed, mmap() may place the shadow stack in the PAGE_SIZE free area. Then the mapping that is supposed to have a guard gap will not have a gap to the adjacent VMA. In order to take the start gap into account, the maple tree search needs to know the size of start gap the new mapping will need. The call chain from do_mmap() to the actual maple tree search looks like this: do_mmap(size, vm_flags, map_flags, ..) mm/mmap.c:get_unmapped_area(size, map_flags, ...) arch_get_unmapped_area(size, map_flags, ...) vm_unmapped_area(struct vm_unmapped_area_info) One option would be to add another MAP_ flag to mean a one page start gap (as is for shadow stack), but this consumes a flag unnecessarily. Another option could be to simply increase the size passed in do_mmap() by the start gap size, and adjust after the fact, but this will interfere with the alignment requirements passed in struct vm_unmapped_area_info, and unknown to mmap.c. Instead, introduce variants of arch_get_unmapped_area/_topdown() that take vm_flags. In future changes, these variants can be used in mmap.c:get_unmapped_area() to allow the vm_flags to be passed through to vm_unmapped_area(), while preserving the normal arch_get_unmapped_area/_topdown() for the existing callers. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Rick Edgecombe <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Aneesh Kumar K.V <[email protected]> Cc: Borislav Petkov (AMD) <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Dan Williams <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Deepak Gupta <[email protected]> Cc: Guo Ren <[email protected]> Cc: Helge Deller <[email protected]> Cc: H. Peter Anvin (Intel) <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Kees Cook <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Liam R. Howlett <[email protected]> Cc: Mark Brown <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Naveen N. Rao <[email protected]> Cc: Nicholas Piggin <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 529ce23 commit 9611487

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

include/linux/sched/mm.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,23 @@ unsigned long mm_get_unmapped_area(struct mm_struct *mm, struct file *filp,
191191
unsigned long addr, unsigned long len,
192192
unsigned long pgoff, unsigned long flags);
193193

194+
unsigned long
195+
arch_get_unmapped_area_vmflags(struct file *filp, unsigned long addr,
196+
unsigned long len, unsigned long pgoff,
197+
unsigned long flags, vm_flags_t vm_flags);
198+
unsigned long
199+
arch_get_unmapped_area_topdown_vmflags(struct file *filp, unsigned long addr,
200+
unsigned long len, unsigned long pgoff,
201+
unsigned long flags, vm_flags_t);
202+
203+
unsigned long mm_get_unmapped_area_vmflags(struct mm_struct *mm,
204+
struct file *filp,
205+
unsigned long addr,
206+
unsigned long len,
207+
unsigned long pgoff,
208+
unsigned long flags,
209+
vm_flags_t vm_flags);
210+
194211
unsigned long
195212
generic_get_unmapped_area(struct file *filp, unsigned long addr,
196213
unsigned long len, unsigned long pgoff,

mm/mmap.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,34 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
18071807
}
18081808
#endif
18091809

1810+
#ifndef HAVE_ARCH_UNMAPPED_AREA_VMFLAGS
1811+
unsigned long
1812+
arch_get_unmapped_area_vmflags(struct file *filp, unsigned long addr, unsigned long len,
1813+
unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags)
1814+
{
1815+
return arch_get_unmapped_area(filp, addr, len, pgoff, flags);
1816+
}
1817+
1818+
unsigned long
1819+
arch_get_unmapped_area_topdown_vmflags(struct file *filp, unsigned long addr,
1820+
unsigned long len, unsigned long pgoff,
1821+
unsigned long flags, vm_flags_t vm_flags)
1822+
{
1823+
return arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
1824+
}
1825+
#endif
1826+
1827+
unsigned long mm_get_unmapped_area_vmflags(struct mm_struct *mm, struct file *filp,
1828+
unsigned long addr, unsigned long len,
1829+
unsigned long pgoff, unsigned long flags,
1830+
vm_flags_t vm_flags)
1831+
{
1832+
if (test_bit(MMF_TOPDOWN, &mm->flags))
1833+
return arch_get_unmapped_area_topdown_vmflags(filp, addr, len, pgoff,
1834+
flags, vm_flags);
1835+
return arch_get_unmapped_area_vmflags(filp, addr, len, pgoff, flags, vm_flags);
1836+
}
1837+
18101838
unsigned long
18111839
get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
18121840
unsigned long pgoff, unsigned long flags)

0 commit comments

Comments
 (0)