1#include <linux/errno.h>
2#include <linux/sched.h>
3#include <linux/syscalls.h>
4#include <linux/mm.h>
5#include <linux/fs.h>
6#include <linux/smp.h>
7#include <linux/sem.h>
8#include <linux/msg.h>
9#include <linux/shm.h>
10#include <linux/stat.h>
11#include <linux/mman.h>
12#include <linux/file.h>
13#include <linux/utsname.h>
14#include <linux/personality.h>
15#include <linux/random.h>
16#include <linux/uaccess.h>
17#include <linux/elf.h>
18
19#include <asm/ia32.h>
20#include <asm/syscalls.h>
21
22
23
24
25static unsigned long get_align_mask(void)
26{
27
28 if (va_align.flags < 0 || !(va_align.flags & (2 - mmap_is_ia32())))
29 return 0;
30
31 if (!(current->flags & PF_RANDOMIZE))
32 return 0;
33
34 return va_align.mask;
35}
36
37unsigned long align_vdso_addr(unsigned long addr)
38{
39 unsigned long align_mask = get_align_mask();
40 return (addr + align_mask) & ~align_mask;
41}
42
43static int __init control_va_addr_alignment(char *str)
44{
45
46 if (va_align.flags < 0)
47 return 1;
48
49 if (*str == 0)
50 return 1;
51
52 if (*str == '=')
53 str++;
54
55 if (!strcmp(str, "32"))
56 va_align.flags = ALIGN_VA_32;
57 else if (!strcmp(str, "64"))
58 va_align.flags = ALIGN_VA_64;
59 else if (!strcmp(str, "off"))
60 va_align.flags = 0;
61 else if (!strcmp(str, "on"))
62 va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;
63 else
64 return 0;
65
66 return 1;
67}
68__setup("align_va_addr", control_va_addr_alignment);
69
70SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
71 unsigned long, prot, unsigned long, flags,
72 unsigned long, fd, unsigned long, off)
73{
74 long error;
75 error = -EINVAL;
76 if (off & ~PAGE_MASK)
77 goto out;
78
79 error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
80out:
81 return error;
82}
83
84static void find_start_end(unsigned long flags, unsigned long *begin,
85 unsigned long *end)
86{
87 if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) {
88 unsigned long new_begin;
89
90
91
92
93
94
95
96 *begin = 0x40000000;
97 *end = 0x80000000;
98 if (current->flags & PF_RANDOMIZE) {
99 new_begin = randomize_range(*begin, *begin + 0x02000000, 0);
100 if (new_begin)
101 *begin = new_begin;
102 }
103 } else {
104 *begin = current->mm->mmap_legacy_base;
105 *end = TASK_SIZE;
106 }
107}
108
109unsigned long
110arch_get_unmapped_area(struct file *filp, unsigned long addr,
111 unsigned long len, unsigned long pgoff, unsigned long flags)
112{
113 struct mm_struct *mm = current->mm;
114 struct vm_area_struct *vma;
115 struct vm_unmapped_area_info info;
116 unsigned long begin, end;
117
118 if (flags & MAP_FIXED)
119 return addr;
120
121 find_start_end(flags, &begin, &end);
122
123 if (len > end)
124 return -ENOMEM;
125
126 if (addr) {
127 addr = PAGE_ALIGN(addr);
128 vma = find_vma(mm, addr);
129 if (end - len >= addr &&
130 (!vma || addr + len <= vma->vm_start))
131 return addr;
132 }
133
134 info.flags = 0;
135 info.length = len;
136 info.low_limit = begin;
137 info.high_limit = end;
138 info.align_mask = filp ? get_align_mask() : 0;
139 info.align_offset = pgoff << PAGE_SHIFT;
140 return vm_unmapped_area(&info);
141}
142
143unsigned long
144arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
145 const unsigned long len, const unsigned long pgoff,
146 const unsigned long flags)
147{
148 struct vm_area_struct *vma;
149 struct mm_struct *mm = current->mm;
150 unsigned long addr = addr0;
151 struct vm_unmapped_area_info info;
152
153
154 if (len > TASK_SIZE)
155 return -ENOMEM;
156
157 if (flags & MAP_FIXED)
158 return addr;
159
160
161 if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
162 goto bottomup;
163
164
165 if (addr) {
166 addr = PAGE_ALIGN(addr);
167 vma = find_vma(mm, addr);
168 if (TASK_SIZE - len >= addr &&
169 (!vma || addr + len <= vma->vm_start))
170 return addr;
171 }
172
173 info.flags = VM_UNMAPPED_AREA_TOPDOWN;
174 info.length = len;
175 info.low_limit = PAGE_SIZE;
176 info.high_limit = mm->mmap_base;
177 info.align_mask = filp ? get_align_mask() : 0;
178 info.align_offset = pgoff << PAGE_SHIFT;
179 addr = vm_unmapped_area(&info);
180 if (!(addr & ~PAGE_MASK))
181 return addr;
182 VM_BUG_ON(addr != -ENOMEM);
183
184bottomup:
185
186
187
188
189
190
191 return arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
192}
193