]> asedeno.scripts.mit.edu Git - linux.git/blob - arch/s390/mm/mmap.c
5ea09403bb878bbe08b7c2ac16eb0c276c303dcb
[linux.git] / arch / s390 / mm / mmap.c
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/elf-randomize.h>
26 #include <linux/personality.h>
27 #include <linux/mm.h>
28 #include <linux/mman.h>
29 #include <linux/sched/signal.h>
30 #include <linux/random.h>
31 #include <linux/compat.h>
32 #include <linux/security.h>
33 #include <asm/pgalloc.h>
34 #include <asm/elf.h>
35
36 static unsigned long stack_maxrandom_size(void)
37 {
38         if (!(current->flags & PF_RANDOMIZE))
39                 return 0;
40         if (current->personality & ADDR_NO_RANDOMIZE)
41                 return 0;
42         return STACK_RND_MASK << PAGE_SHIFT;
43 }
44
45 /*
46  * Top of mmap area (just below the process stack).
47  *
48  * Leave at least a ~32 MB hole.
49  */
50 #define MIN_GAP (32*1024*1024)
51 #define MAX_GAP (STACK_TOP/6*5)
52
53 static inline int mmap_is_legacy(void)
54 {
55         if (current->personality & ADDR_COMPAT_LAYOUT)
56                 return 1;
57         if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
58                 return 1;
59         return sysctl_legacy_va_layout;
60 }
61
62 unsigned long arch_mmap_rnd(void)
63 {
64         return (get_random_int() & MMAP_RND_MASK) << PAGE_SHIFT;
65 }
66
67 static unsigned long mmap_base_legacy(unsigned long rnd)
68 {
69         return TASK_UNMAPPED_BASE + rnd;
70 }
71
72 static 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         gap &= PAGE_MASK;
81         return STACK_TOP - stack_maxrandom_size() - rnd - gap;
82 }
83
84 unsigned long
85 arch_get_unmapped_area(struct file *filp, unsigned long addr,
86                 unsigned long len, unsigned long pgoff, unsigned long flags)
87 {
88         struct mm_struct *mm = current->mm;
89         struct vm_area_struct *vma;
90         struct vm_unmapped_area_info info;
91
92         if (len > TASK_SIZE - mmap_min_addr)
93                 return -ENOMEM;
94
95         if (flags & MAP_FIXED)
96                 return addr;
97
98         if (addr) {
99                 addr = PAGE_ALIGN(addr);
100                 vma = find_vma(mm, addr);
101                 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
102                     (!vma || addr + len <= vma->vm_start))
103                         return addr;
104         }
105
106         info.flags = 0;
107         info.length = len;
108         info.low_limit = mm->mmap_base;
109         info.high_limit = TASK_SIZE;
110         if (filp || (flags & MAP_SHARED))
111                 info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
112         else
113                 info.align_mask = 0;
114         info.align_offset = pgoff << PAGE_SHIFT;
115         return vm_unmapped_area(&info);
116 }
117
118 unsigned long
119 arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
120                           const unsigned long len, const unsigned long pgoff,
121                           const unsigned long flags)
122 {
123         struct vm_area_struct *vma;
124         struct mm_struct *mm = current->mm;
125         unsigned long addr = addr0;
126         struct vm_unmapped_area_info info;
127
128         /* requested length too big for entire address space */
129         if (len > TASK_SIZE - mmap_min_addr)
130                 return -ENOMEM;
131
132         if (flags & MAP_FIXED)
133                 return addr;
134
135         /* requesting a specific address */
136         if (addr) {
137                 addr = PAGE_ALIGN(addr);
138                 vma = find_vma(mm, addr);
139                 if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
140                                 (!vma || addr + len <= vma->vm_start))
141                         return addr;
142         }
143
144         info.flags = VM_UNMAPPED_AREA_TOPDOWN;
145         info.length = len;
146         info.low_limit = max(PAGE_SIZE, mmap_min_addr);
147         info.high_limit = mm->mmap_base;
148         if (filp || (flags & MAP_SHARED))
149                 info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
150         else
151                 info.align_mask = 0;
152         info.align_offset = pgoff << PAGE_SHIFT;
153         addr = vm_unmapped_area(&info);
154
155         /*
156          * A failed mmap() very likely causes application failure,
157          * so fall back to the bottom-up function here. This scenario
158          * can happen with large stack limits and large mmap()
159          * allocations.
160          */
161         if (addr & ~PAGE_MASK) {
162                 VM_BUG_ON(addr != -ENOMEM);
163                 info.flags = 0;
164                 info.low_limit = TASK_UNMAPPED_BASE;
165                 info.high_limit = TASK_SIZE;
166                 addr = vm_unmapped_area(&info);
167         }
168
169         return addr;
170 }
171
172 int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
173 {
174         if (is_compat_task() || TASK_SIZE >= TASK_MAX_SIZE)
175                 return 0;
176         if (!(flags & MAP_FIXED))
177                 addr = 0;
178         if ((addr + len) >= TASK_SIZE)
179                 return crst_table_upgrade(current->mm);
180         return 0;
181 }
182
183 static unsigned long
184 s390_get_unmapped_area(struct file *filp, unsigned long addr,
185                 unsigned long len, unsigned long pgoff, unsigned long flags)
186 {
187         struct mm_struct *mm = current->mm;
188         unsigned long area;
189         int rc;
190
191         area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
192         if (!(area & ~PAGE_MASK))
193                 return area;
194         if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) {
195                 /* Upgrade the page table to 4 levels and retry. */
196                 rc = crst_table_upgrade(mm);
197                 if (rc)
198                         return (unsigned long) rc;
199                 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
200         }
201         return area;
202 }
203
204 static unsigned long
205 s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
206                           const unsigned long len, const unsigned long pgoff,
207                           const unsigned long flags)
208 {
209         struct mm_struct *mm = current->mm;
210         unsigned long area;
211         int rc;
212
213         area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
214         if (!(area & ~PAGE_MASK))
215                 return area;
216         if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < TASK_MAX_SIZE) {
217                 /* Upgrade the page table to 4 levels and retry. */
218                 rc = crst_table_upgrade(mm);
219                 if (rc)
220                         return (unsigned long) rc;
221                 area = arch_get_unmapped_area_topdown(filp, addr, len,
222                                                       pgoff, flags);
223         }
224         return area;
225 }
226 /*
227  * This function, called very early during the creation of a new
228  * process VM image, sets up which VM layout function to use:
229  */
230 void arch_pick_mmap_layout(struct mm_struct *mm)
231 {
232         unsigned long random_factor = 0UL;
233
234         if (current->flags & PF_RANDOMIZE)
235                 random_factor = arch_mmap_rnd();
236
237         /*
238          * Fall back to the standard layout if the personality
239          * bit is set, or if the expected stack growth is unlimited:
240          */
241         if (mmap_is_legacy()) {
242                 mm->mmap_base = mmap_base_legacy(random_factor);
243                 mm->get_unmapped_area = s390_get_unmapped_area;
244         } else {
245                 mm->mmap_base = mmap_base(random_factor);
246                 mm->get_unmapped_area = s390_get_unmapped_area_topdown;
247         }
248 }