1675a0813SHarvey Harrison /* 2675a0813SHarvey Harrison * Flexible mmap layout support 3675a0813SHarvey Harrison * 4675a0813SHarvey Harrison * Based on code by Ingo Molnar and Andi Kleen, copyrighted 5675a0813SHarvey Harrison * as follows: 6675a0813SHarvey Harrison * 78f47e163SIngo Molnar * Copyright 2003-2009 Red Hat Inc. 8675a0813SHarvey Harrison * All Rights Reserved. 9675a0813SHarvey Harrison * Copyright 2005 Andi Kleen, SUSE Labs. 10675a0813SHarvey Harrison * Copyright 2007 Jiri Kosina, SUSE Labs. 11675a0813SHarvey Harrison * 12675a0813SHarvey Harrison * This program is free software; you can redistribute it and/or modify 13675a0813SHarvey Harrison * it under the terms of the GNU General Public License as published by 14675a0813SHarvey Harrison * the Free Software Foundation; either version 2 of the License, or 15675a0813SHarvey Harrison * (at your option) any later version. 16675a0813SHarvey Harrison * 17675a0813SHarvey Harrison * This program is distributed in the hope that it will be useful, 18675a0813SHarvey Harrison * but WITHOUT ANY WARRANTY; without even the implied warranty of 19675a0813SHarvey Harrison * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20675a0813SHarvey Harrison * GNU General Public License for more details. 21675a0813SHarvey Harrison * 22675a0813SHarvey Harrison * You should have received a copy of the GNU General Public License 23675a0813SHarvey Harrison * along with this program; if not, write to the Free Software 24675a0813SHarvey Harrison * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25675a0813SHarvey Harrison */ 26675a0813SHarvey Harrison 27675a0813SHarvey Harrison #include <linux/personality.h> 28675a0813SHarvey Harrison #include <linux/mm.h> 29675a0813SHarvey Harrison #include <linux/random.h> 30675a0813SHarvey Harrison #include <linux/limits.h> 313f07c014SIngo Molnar #include <linux/sched/signal.h> 3201042607SIngo Molnar #include <linux/sched/mm.h> 33e13b73ddSDmitry Safonov #include <linux/compat.h> 3480938332SMichal Hocko #include <asm/elf.h> 3580938332SMichal Hocko 36cc99535eSJan-Simon Möller struct va_alignment __read_mostly va_align = { 379387f774SBorislav Petkov .flags = -1, 389387f774SBorislav Petkov }; 399387f774SBorislav Petkov 401b028f78SDmitry Safonov unsigned long tasksize_32bit(void) 418f3e474fSDmitry Safonov { 428f3e474fSDmitry Safonov return IA32_PAGE_OFFSET; 438f3e474fSDmitry Safonov } 448f3e474fSDmitry Safonov 451b028f78SDmitry Safonov unsigned long tasksize_64bit(void) 461b028f78SDmitry Safonov { 471b028f78SDmitry Safonov return TASK_SIZE_MAX; 481b028f78SDmitry Safonov } 491b028f78SDmitry Safonov 508f3e474fSDmitry Safonov static unsigned long stack_maxrandom_size(unsigned long task_size) 5180938332SMichal Hocko { 524e7c22d4SHector Marco-Gisbert unsigned long max = 0; 53*01578e36SOleg Nesterov if (current->flags & PF_RANDOMIZE) { 548f3e474fSDmitry Safonov max = (-1UL) & __STACK_RND_MASK(task_size == tasksize_32bit()); 558f3e474fSDmitry Safonov max <<= PAGE_SHIFT; 5680938332SMichal Hocko } 5780938332SMichal Hocko 5880938332SMichal Hocko return max; 5980938332SMichal Hocko } 6080938332SMichal Hocko 616a0b41d1SDmitry Safonov #ifdef CONFIG_COMPAT 626a0b41d1SDmitry Safonov # define mmap32_rnd_bits mmap_rnd_compat_bits 636a0b41d1SDmitry Safonov # define mmap64_rnd_bits mmap_rnd_bits 646a0b41d1SDmitry Safonov #else 656a0b41d1SDmitry Safonov # define mmap32_rnd_bits mmap_rnd_bits 666a0b41d1SDmitry Safonov # define mmap64_rnd_bits mmap_rnd_bits 676a0b41d1SDmitry Safonov #endif 686a0b41d1SDmitry Safonov 698f3e474fSDmitry Safonov #define SIZE_128M (128 * 1024 * 1024UL) 708f3e474fSDmitry Safonov 71675a0813SHarvey Harrison static int mmap_is_legacy(void) 72675a0813SHarvey Harrison { 73675a0813SHarvey Harrison if (current->personality & ADDR_COMPAT_LAYOUT) 74675a0813SHarvey Harrison return 1; 75675a0813SHarvey Harrison 76675a0813SHarvey Harrison return sysctl_legacy_va_layout; 77675a0813SHarvey Harrison } 78675a0813SHarvey Harrison 796a0b41d1SDmitry Safonov static unsigned long arch_rnd(unsigned int rndbits) 806a0b41d1SDmitry Safonov { 8147ac5484SOleg Nesterov if (!(current->flags & PF_RANDOMIZE)) 8247ac5484SOleg Nesterov return 0; 836a0b41d1SDmitry Safonov return (get_random_long() & ((1UL << rndbits) - 1)) << PAGE_SHIFT; 846a0b41d1SDmitry Safonov } 856a0b41d1SDmitry Safonov 862b68f6caSKees Cook unsigned long arch_mmap_rnd(void) 87675a0813SHarvey Harrison { 886a0b41d1SDmitry Safonov return arch_rnd(mmap_is_ia32() ? mmap32_rnd_bits : mmap64_rnd_bits); 89675a0813SHarvey Harrison } 90675a0813SHarvey Harrison 918f3e474fSDmitry Safonov static unsigned long mmap_base(unsigned long rnd, unsigned long task_size) 92675a0813SHarvey Harrison { 932854e72bSJiri Slaby unsigned long gap = rlimit(RLIMIT_STACK); 94c204d21fSRik van Riel unsigned long pad = stack_maxrandom_size(task_size) + stack_guard_gap; 958f3e474fSDmitry Safonov unsigned long gap_min, gap_max; 96675a0813SHarvey Harrison 97c204d21fSRik van Riel /* Values close to RLIM_INFINITY can overflow. */ 98c204d21fSRik van Riel if (gap + pad > gap) 99c204d21fSRik van Riel gap += pad; 100c204d21fSRik van Riel 1018f3e474fSDmitry Safonov /* 1028f3e474fSDmitry Safonov * Top of mmap area (just below the process stack). 1038f3e474fSDmitry Safonov * Leave an at least ~128 MB hole with possible stack randomization. 1048f3e474fSDmitry Safonov */ 105c204d21fSRik van Riel gap_min = SIZE_128M; 1068f3e474fSDmitry Safonov gap_max = (task_size / 6) * 5; 107675a0813SHarvey Harrison 1088f3e474fSDmitry Safonov if (gap < gap_min) 1098f3e474fSDmitry Safonov gap = gap_min; 1108f3e474fSDmitry Safonov else if (gap > gap_max) 1118f3e474fSDmitry Safonov gap = gap_max; 1128f3e474fSDmitry Safonov 1138f3e474fSDmitry Safonov return PAGE_ALIGN(task_size - gap - rnd); 1148f3e474fSDmitry Safonov } 1158f3e474fSDmitry Safonov 1168f3e474fSDmitry Safonov static unsigned long mmap_legacy_base(unsigned long rnd, 1178f3e474fSDmitry Safonov unsigned long task_size) 1188f3e474fSDmitry Safonov { 1198f3e474fSDmitry Safonov return __TASK_UNMAPPED_BASE(task_size) + rnd; 120675a0813SHarvey Harrison } 121675a0813SHarvey Harrison 122675a0813SHarvey Harrison /* 123675a0813SHarvey Harrison * This function, called very early during the creation of a new 124675a0813SHarvey Harrison * process VM image, sets up which VM layout function to use: 125675a0813SHarvey Harrison */ 1261b028f78SDmitry Safonov static void arch_pick_mmap_base(unsigned long *base, unsigned long *legacy_base, 1271b028f78SDmitry Safonov unsigned long random_factor, unsigned long task_size) 1281b028f78SDmitry Safonov { 1291b028f78SDmitry Safonov *legacy_base = mmap_legacy_base(random_factor, task_size); 1301b028f78SDmitry Safonov if (mmap_is_legacy()) 1311b028f78SDmitry Safonov *base = *legacy_base; 1321b028f78SDmitry Safonov else 1331b028f78SDmitry Safonov *base = mmap_base(random_factor, task_size); 1341b028f78SDmitry Safonov } 1351b028f78SDmitry Safonov 136675a0813SHarvey Harrison void arch_pick_mmap_layout(struct mm_struct *mm) 137675a0813SHarvey Harrison { 1381b028f78SDmitry Safonov if (mmap_is_legacy()) 139675a0813SHarvey Harrison mm->get_unmapped_area = arch_get_unmapped_area; 1401b028f78SDmitry Safonov else 141675a0813SHarvey Harrison mm->get_unmapped_area = arch_get_unmapped_area_topdown; 1421b028f78SDmitry Safonov 1431b028f78SDmitry Safonov arch_pick_mmap_base(&mm->mmap_base, &mm->mmap_legacy_base, 1441b028f78SDmitry Safonov arch_rnd(mmap64_rnd_bits), tasksize_64bit()); 1451b028f78SDmitry Safonov 1461b028f78SDmitry Safonov #ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES 1471b028f78SDmitry Safonov /* 1481b028f78SDmitry Safonov * The mmap syscall mapping base decision depends solely on the 1491b028f78SDmitry Safonov * syscall type (64-bit or compat). This applies for 64bit 1501b028f78SDmitry Safonov * applications and 32bit applications. The 64bit syscall uses 1511b028f78SDmitry Safonov * mmap_base, the compat syscall uses mmap_compat_base. 1521b028f78SDmitry Safonov */ 1531b028f78SDmitry Safonov arch_pick_mmap_base(&mm->mmap_compat_base, &mm->mmap_compat_legacy_base, 1541b028f78SDmitry Safonov arch_rnd(mmap32_rnd_bits), tasksize_32bit()); 1551b028f78SDmitry Safonov #endif 156675a0813SHarvey Harrison } 157a8965276SKirill A. Shutemov 158e13b73ddSDmitry Safonov unsigned long get_mmap_base(int is_legacy) 159e13b73ddSDmitry Safonov { 160e13b73ddSDmitry Safonov struct mm_struct *mm = current->mm; 161e13b73ddSDmitry Safonov 162e13b73ddSDmitry Safonov #ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES 163e13b73ddSDmitry Safonov if (in_compat_syscall()) { 164e13b73ddSDmitry Safonov return is_legacy ? mm->mmap_compat_legacy_base 165e13b73ddSDmitry Safonov : mm->mmap_compat_base; 166e13b73ddSDmitry Safonov } 167e13b73ddSDmitry Safonov #endif 168e13b73ddSDmitry Safonov return is_legacy ? mm->mmap_legacy_base : mm->mmap_base; 169e13b73ddSDmitry Safonov } 170e13b73ddSDmitry Safonov 171a8965276SKirill A. Shutemov const char *arch_vma_name(struct vm_area_struct *vma) 172a8965276SKirill A. Shutemov { 173a8965276SKirill A. Shutemov if (vma->vm_flags & VM_MPX) 174a8965276SKirill A. Shutemov return "[mpx]"; 175a8965276SKirill A. Shutemov return NULL; 176a8965276SKirill A. Shutemov } 177