Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc2 213 lines 5.8 kB view raw
1/* 2 * flexible mmap layout support 3 * 4 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. 5 * All Rights Reserved. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * 22 * Started by Ingo Molnar <mingo@elte.hu> 23 */ 24 25#include <linux/personality.h> 26#include <linux/mm.h> 27#include <linux/random.h> 28#include <linux/sched.h> 29#include <linux/elf-randomize.h> 30#include <linux/security.h> 31#include <linux/mman.h> 32 33/* 34 * Top of mmap area (just below the process stack). 35 * 36 * Leave at least a ~128 MB hole on 32bit applications. 37 * 38 * On 64bit applications we randomise the stack by 1GB so we need to 39 * space our mmap start address by a further 1GB, otherwise there is a 40 * chance the mmap area will end up closer to the stack than our ulimit 41 * requires. 42 */ 43#define MIN_GAP32 (128*1024*1024) 44#define MIN_GAP64 ((128 + 1024)*1024*1024UL) 45#define MIN_GAP ((is_32bit_task()) ? MIN_GAP32 : MIN_GAP64) 46#define MAX_GAP (TASK_SIZE/6*5) 47 48static inline int mmap_is_legacy(void) 49{ 50 if (current->personality & ADDR_COMPAT_LAYOUT) 51 return 1; 52 53 if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) 54 return 1; 55 56 return sysctl_legacy_va_layout; 57} 58 59unsigned long arch_mmap_rnd(void) 60{ 61 unsigned long rnd; 62 63 /* 8MB for 32bit, 1GB for 64bit */ 64 if (is_32bit_task()) 65 rnd = get_random_long() % (1<<(23-PAGE_SHIFT)); 66 else 67 rnd = get_random_long() % (1UL<<(30-PAGE_SHIFT)); 68 69 return rnd << PAGE_SHIFT; 70} 71 72static inline unsigned long mmap_base(unsigned long rnd) 73{ 74 unsigned long gap = rlimit(RLIMIT_STACK); 75 76 if (gap < MIN_GAP) 77 gap = MIN_GAP; 78 else if (gap > MAX_GAP) 79 gap = MAX_GAP; 80 81 return PAGE_ALIGN(TASK_SIZE - gap - rnd); 82} 83 84#ifdef CONFIG_PPC_RADIX_MMU 85/* 86 * Same function as generic code used only for radix, because we don't need to overload 87 * the generic one. But we will have to duplicate, because hash select 88 * HAVE_ARCH_UNMAPPED_AREA 89 */ 90static unsigned long 91radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, 92 unsigned long len, unsigned long pgoff, 93 unsigned long flags) 94{ 95 struct mm_struct *mm = current->mm; 96 struct vm_area_struct *vma; 97 struct vm_unmapped_area_info info; 98 99 if (len > TASK_SIZE - mmap_min_addr) 100 return -ENOMEM; 101 102 if (flags & MAP_FIXED) 103 return addr; 104 105 if (addr) { 106 addr = PAGE_ALIGN(addr); 107 vma = find_vma(mm, addr); 108 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && 109 (!vma || addr + len <= vma->vm_start)) 110 return addr; 111 } 112 113 info.flags = 0; 114 info.length = len; 115 info.low_limit = mm->mmap_base; 116 info.high_limit = TASK_SIZE; 117 info.align_mask = 0; 118 return vm_unmapped_area(&info); 119} 120 121static unsigned long 122radix__arch_get_unmapped_area_topdown(struct file *filp, 123 const unsigned long addr0, 124 const unsigned long len, 125 const unsigned long pgoff, 126 const unsigned long flags) 127{ 128 struct vm_area_struct *vma; 129 struct mm_struct *mm = current->mm; 130 unsigned long addr = addr0; 131 struct vm_unmapped_area_info info; 132 133 /* requested length too big for entire address space */ 134 if (len > TASK_SIZE - mmap_min_addr) 135 return -ENOMEM; 136 137 if (flags & MAP_FIXED) 138 return addr; 139 140 /* requesting a specific address */ 141 if (addr) { 142 addr = PAGE_ALIGN(addr); 143 vma = find_vma(mm, addr); 144 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && 145 (!vma || addr + len <= vma->vm_start)) 146 return addr; 147 } 148 149 info.flags = VM_UNMAPPED_AREA_TOPDOWN; 150 info.length = len; 151 info.low_limit = max(PAGE_SIZE, mmap_min_addr); 152 info.high_limit = mm->mmap_base; 153 info.align_mask = 0; 154 addr = vm_unmapped_area(&info); 155 156 /* 157 * A failed mmap() very likely causes application failure, 158 * so fall back to the bottom-up function here. This scenario 159 * can happen with large stack limits and large mmap() 160 * allocations. 161 */ 162 if (addr & ~PAGE_MASK) { 163 VM_BUG_ON(addr != -ENOMEM); 164 info.flags = 0; 165 info.low_limit = TASK_UNMAPPED_BASE; 166 info.high_limit = TASK_SIZE; 167 addr = vm_unmapped_area(&info); 168 } 169 170 return addr; 171} 172 173static void radix__arch_pick_mmap_layout(struct mm_struct *mm, 174 unsigned long random_factor) 175{ 176 if (mmap_is_legacy()) { 177 mm->mmap_base = TASK_UNMAPPED_BASE; 178 mm->get_unmapped_area = radix__arch_get_unmapped_area; 179 } else { 180 mm->mmap_base = mmap_base(random_factor); 181 mm->get_unmapped_area = radix__arch_get_unmapped_area_topdown; 182 } 183} 184#else 185/* dummy */ 186extern void radix__arch_pick_mmap_layout(struct mm_struct *mm, 187 unsigned long random_factor); 188#endif 189/* 190 * This function, called very early during the creation of a new 191 * process VM image, sets up which VM layout function to use: 192 */ 193void arch_pick_mmap_layout(struct mm_struct *mm) 194{ 195 unsigned long random_factor = 0UL; 196 197 if (current->flags & PF_RANDOMIZE) 198 random_factor = arch_mmap_rnd(); 199 200 if (radix_enabled()) 201 return radix__arch_pick_mmap_layout(mm, random_factor); 202 /* 203 * Fall back to the standard layout if the personality 204 * bit is set, or if the expected stack growth is unlimited: 205 */ 206 if (mmap_is_legacy()) { 207 mm->mmap_base = TASK_UNMAPPED_BASE; 208 mm->get_unmapped_area = arch_get_unmapped_area; 209 } else { 210 mm->mmap_base = mmap_base(random_factor); 211 mm->get_unmapped_area = arch_get_unmapped_area_topdown; 212 } 213}