From: Xiongwei Song <sxwjean@xxxxxxxxx> With CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES enabled, archs can support 64bit process invoke 32bit syscall via compatible mmap(), which uses mmap_compat_base and mmap_compat_legacy_base of mm_struct, which only x86 uses so far. Here we assume other archs will support CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES as well. Signed-off-by: Xiongwei Song <sxwjean@xxxxxxxxx> --- arch/x86/include/asm/processor.h | 4 ++++ mm/util.c | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 577f342dbfb2..fb7a4f21d412 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -787,6 +787,10 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip, #define __TASK_UNMAPPED_BASE(task_size) (PAGE_ALIGN(task_size / 3)) #define TASK_UNMAPPED_BASE __TASK_UNMAPPED_BASE(TASK_SIZE_LOW) +#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES +#define TASK_UNMAPPED_COMPAT_BASE __TASK_UNMAPPED_BASE(task_size_32bit()) +#endif + #define KSTK_EIP(task) (task_pt_regs(task)->ip) /* Get/set a process' ability to use the timestamp counter instruction */ diff --git a/mm/util.c b/mm/util.c index 38326ef21a3b..ab3711c445e6 100644 --- a/mm/util.c +++ b/mm/util.c @@ -357,8 +357,9 @@ unsigned long arch_mmap_rnd(void) { unsigned long rnd; -#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS - if (is_compat_task()) +#if defined(CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS) \ + || defined(CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES) + if (is_compat_task() || in_compat_syscall()) rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1); else #endif /* CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS */ @@ -422,6 +423,22 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) mm->mmap_base = mmap_base(random_factor, STACK_TOP, rlim_stack); mm->get_unmapped_area = arch_get_unmapped_area_topdown; } +#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES + /* + * The mmap syscall mapping base decision depends solely on the + * syscall type (64-bit or compat). This applies for 64bit + * applications and 32bit applications. The 64bit syscall uses + * mmap_base, the compat syscall uses mmap_compat_base. + */ + if (mmap_is_legacy(rlim_stack)) { + mm->mmap_compat_legacy_base = + TASK_UNMAPPED_COMPAT_BASE + random_factor; + mm->mmap_compat_base = mm->mmap_compat_legacy_base; + } else { + mm->mmap_compat_base = mmap_base(random_factor, + task_size_32bit(), rlim_stack); + } +#endif } #elif defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT) void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) -- 2.30.2