Add support for MAP_BELOW_HINT to mmap by restricting high_limit to
addr when the flag is enabled.

Signed-off-by: Charlie Jenkins <char...@rivosinc.com>
---
 arch/x86/kernel/sys_x86_64.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 01d7cd85ef97..fa16b38f3702 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -86,7 +86,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
        return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 }
 
-static void find_start_end(unsigned long addr, unsigned long flags,
+static void find_start_end(unsigned long addr, unsigned long len, unsigned 
long flags,
                unsigned long *begin, unsigned long *end)
 {
        if (!in_32bit_syscall() && (flags & MAP_32BIT)) {
@@ -106,10 +106,14 @@ static void find_start_end(unsigned long addr, unsigned 
long flags,
        }
 
        *begin  = get_mmap_base(1);
+
        if (in_32bit_syscall())
                *end = task_size_32bit();
        else
                *end = task_size_64bit(addr > DEFAULT_MAP_WINDOW);
+
+       if (flags & MAP_BELOW_HINT)
+               *end = MIN(*end, addr + len);
 }
 
 static inline unsigned long stack_guard_placement(vm_flags_t vm_flags)
@@ -132,7 +136,7 @@ arch_get_unmapped_area_vmflags(struct file *filp, unsigned 
long addr, unsigned l
        if (flags & MAP_FIXED)
                return addr;
 
-       find_start_end(addr, flags, &begin, &end);
+       find_start_end(addr, len, flags, &begin, &end);
 
        if (len > end)
                return -ENOMEM;
@@ -166,6 +170,7 @@ arch_get_unmapped_area_topdown_vmflags(struct file *filp, 
unsigned long addr0,
        struct mm_struct *mm = current->mm;
        unsigned long addr = addr0;
        struct vm_unmapped_area_info info = {};
+       unsigned long task_size, mmap_base;
 
        /* requested length too big for entire address space */
        if (len > TASK_SIZE)
@@ -198,7 +203,8 @@ arch_get_unmapped_area_topdown_vmflags(struct file *filp, 
unsigned long addr0,
        else
                info.low_limit = PAGE_SIZE;
 
-       info.high_limit = get_mmap_base(0);
+       mmap_base = get_mmap_base(0);
+       info.high_limit = mmap_base;
        info.start_gap = stack_guard_placement(vm_flags);
 
        /*
@@ -210,6 +216,19 @@ arch_get_unmapped_area_topdown_vmflags(struct file *filp, 
unsigned long addr0,
         */
        if (addr > DEFAULT_MAP_WINDOW && !in_32bit_syscall())
                info.high_limit += TASK_SIZE_MAX - DEFAULT_MAP_WINDOW;
+       if (flags & MAP_BELOW_HINT) {
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+               task_size = task_size_32bit();
+#else
+               task_size = task_size_64bit(0);
+#endif
+               /*
+                * mmap_base is defined by PAGE_ALIGN(task_size - gap - rnd) so
+                * subtract out the task_size to isolate the gap + rnd.
+                */
+               info.high_limit = MIN(info.high_limit,
+                                     (addr + len) - (task_size - mmap_base));
+       }
 
        info.align_offset = pgoff << PAGE_SHIFT;
        if (filp) {

-- 
2.45.0


Reply via email to