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/signal.h> 29 #include <linux/sched/mm.h> 30 #include <linux/elf-randomize.h> 31 #include <linux/security.h> 32 #include <linux/mman.h> 33 34 /* 35 * Top of mmap area (just below the process stack). 36 * 37 * Leave at least a ~128 MB hole. 38 */ 39 #define MIN_GAP (128*1024*1024) 40 #define MAX_GAP (TASK_SIZE/6*5) 41 42 static inline int mmap_is_legacy(struct rlimit *rlim_stack) 43 { 44 if (current->personality & ADDR_COMPAT_LAYOUT) 45 return 1; 46 47 if (rlim_stack->rlim_cur == RLIM_INFINITY) 48 return 1; 49 50 return sysctl_legacy_va_layout; 51 } 52 53 unsigned long arch_mmap_rnd(void) 54 { 55 unsigned long shift, rnd; 56 57 shift = mmap_rnd_bits; 58 #ifdef CONFIG_COMPAT 59 if (is_32bit_task()) 60 shift = mmap_rnd_compat_bits; 61 #endif 62 rnd = get_random_long() % (1ul << shift); 63 64 return rnd << PAGE_SHIFT; 65 } 66 67 static inline unsigned long stack_maxrandom_size(void) 68 { 69 if (!(current->flags & PF_RANDOMIZE)) 70 return 0; 71 72 /* 8MB for 32bit, 1GB for 64bit */ 73 if (is_32bit_task()) 74 return (1<<23); 75 else 76 return (1<<30); 77 } 78 79 static inline unsigned long mmap_base(unsigned long rnd, 80 struct rlimit *rlim_stack) 81 { 82 unsigned long gap = rlim_stack->rlim_cur; 83 unsigned long pad = stack_maxrandom_size() + stack_guard_gap; 84 85 /* Values close to RLIM_INFINITY can overflow. */ 86 if (gap + pad > gap) 87 gap += pad; 88 89 if (gap < MIN_GAP) 90 gap = MIN_GAP; 91 else if (gap > MAX_GAP) 92 gap = MAX_GAP; 93 94 return PAGE_ALIGN(DEFAULT_MAP_WINDOW - gap - rnd); 95 } 96 97 #ifdef CONFIG_PPC_RADIX_MMU 98 /* 99 * Same function as generic code used only for radix, because we don't need to overload 100 * the generic one. But we will have to duplicate, because hash select 101 * HAVE_ARCH_UNMAPPED_AREA 102 */ 103 static unsigned long 104 radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, 105 unsigned long len, unsigned long pgoff, 106 unsigned long flags) 107 { 108 struct mm_struct *mm = current->mm; 109 struct vm_area_struct *vma; 110 int fixed = (flags & MAP_FIXED); 111 unsigned long high_limit; 112 struct vm_unmapped_area_info info; 113 114 high_limit = DEFAULT_MAP_WINDOW; 115 if (addr >= high_limit || (fixed && (addr + len > high_limit))) 116 high_limit = TASK_SIZE; 117 118 if (len > high_limit) 119 return -ENOMEM; 120 121 if (fixed) { 122 if (addr > high_limit - len) 123 return -ENOMEM; 124 return addr; 125 } 126 127 if (addr) { 128 addr = PAGE_ALIGN(addr); 129 vma = find_vma(mm, addr); 130 if (high_limit - len >= addr && addr >= mmap_min_addr && 131 (!vma || addr + len <= vm_start_gap(vma))) 132 return addr; 133 } 134 135 info.flags = 0; 136 info.length = len; 137 info.low_limit = mm->mmap_base; 138 info.high_limit = high_limit; 139 info.align_mask = 0; 140 141 return vm_unmapped_area(&info); 142 } 143 144 static unsigned long 145 radix__arch_get_unmapped_area_topdown(struct file *filp, 146 const unsigned long addr0, 147 const unsigned long len, 148 const unsigned long pgoff, 149 const unsigned long flags) 150 { 151 struct vm_area_struct *vma; 152 struct mm_struct *mm = current->mm; 153 unsigned long addr = addr0; 154 int fixed = (flags & MAP_FIXED); 155 unsigned long high_limit; 156 struct vm_unmapped_area_info info; 157 158 high_limit = DEFAULT_MAP_WINDOW; 159 if (addr >= high_limit || (fixed && (addr + len > high_limit))) 160 high_limit = TASK_SIZE; 161 162 if (len > high_limit) 163 return -ENOMEM; 164 165 if (fixed) { 166 if (addr > high_limit - len) 167 return -ENOMEM; 168 return addr; 169 } 170 171 if (addr) { 172 addr = PAGE_ALIGN(addr); 173 vma = find_vma(mm, addr); 174 if (high_limit - len >= addr && addr >= mmap_min_addr && 175 (!vma || addr + len <= vm_start_gap(vma))) 176 return addr; 177 } 178 179 info.flags = VM_UNMAPPED_AREA_TOPDOWN; 180 info.length = len; 181 info.low_limit = max(PAGE_SIZE, mmap_min_addr); 182 info.high_limit = mm->mmap_base + (high_limit - DEFAULT_MAP_WINDOW); 183 info.align_mask = 0; 184 185 addr = vm_unmapped_area(&info); 186 if (!(addr & ~PAGE_MASK)) 187 return addr; 188 VM_BUG_ON(addr != -ENOMEM); 189 190 /* 191 * A failed mmap() very likely causes application failure, 192 * so fall back to the bottom-up function here. This scenario 193 * can happen with large stack limits and large mmap() 194 * allocations. 195 */ 196 return radix__arch_get_unmapped_area(filp, addr0, len, pgoff, flags); 197 } 198 199 static void radix__arch_pick_mmap_layout(struct mm_struct *mm, 200 unsigned long random_factor, 201 struct rlimit *rlim_stack) 202 { 203 if (mmap_is_legacy(rlim_stack)) { 204 mm->mmap_base = TASK_UNMAPPED_BASE; 205 mm->get_unmapped_area = radix__arch_get_unmapped_area; 206 } else { 207 mm->mmap_base = mmap_base(random_factor, rlim_stack); 208 mm->get_unmapped_area = radix__arch_get_unmapped_area_topdown; 209 } 210 } 211 #else 212 /* dummy */ 213 extern void radix__arch_pick_mmap_layout(struct mm_struct *mm, 214 unsigned long random_factor, 215 struct rlimit *rlim_stack); 216 #endif 217 /* 218 * This function, called very early during the creation of a new 219 * process VM image, sets up which VM layout function to use: 220 */ 221 void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) 222 { 223 unsigned long random_factor = 0UL; 224 225 if (current->flags & PF_RANDOMIZE) 226 random_factor = arch_mmap_rnd(); 227 228 if (radix_enabled()) 229 return radix__arch_pick_mmap_layout(mm, random_factor, 230 rlim_stack); 231 /* 232 * Fall back to the standard layout if the personality 233 * bit is set, or if the expected stack growth is unlimited: 234 */ 235 if (mmap_is_legacy(rlim_stack)) { 236 mm->mmap_base = TASK_UNMAPPED_BASE; 237 mm->get_unmapped_area = arch_get_unmapped_area; 238 } else { 239 mm->mmap_base = mmap_base(random_factor, rlim_stack); 240 mm->get_unmapped_area = arch_get_unmapped_area_topdown; 241 } 242 } 243
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.