Commit | Line | Data |
---|---|---|
6f6c3c33 RB |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2011 Wind River Systems, | |
7 | * written by Ralf Baechle <ralf@linux-mips.org> | |
8 | */ | |
9 | #include <linux/errno.h> | |
10 | #include <linux/mm.h> | |
11 | #include <linux/mman.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/random.h> | |
14 | #include <linux/sched.h> | |
15 | ||
16 | unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ | |
17 | ||
18 | EXPORT_SYMBOL(shm_align_mask); | |
19 | ||
20 | #define COLOUR_ALIGN(addr,pgoff) \ | |
21 | ((((addr) + shm_align_mask) & ~shm_align_mask) + \ | |
22 | (((pgoff) << PAGE_SHIFT) & shm_align_mask)) | |
23 | ||
24 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | |
25 | unsigned long len, unsigned long pgoff, unsigned long flags) | |
26 | { | |
27 | struct vm_area_struct * vmm; | |
28 | int do_color_align; | |
29 | ||
30 | if (len > TASK_SIZE) | |
31 | return -ENOMEM; | |
32 | ||
33 | if (flags & MAP_FIXED) { | |
34 | /* Even MAP_FIXED mappings must reside within TASK_SIZE. */ | |
35 | if (TASK_SIZE - len < addr) | |
36 | return -EINVAL; | |
37 | ||
38 | /* | |
39 | * We do not accept a shared mapping if it would violate | |
40 | * cache aliasing constraints. | |
41 | */ | |
42 | if ((flags & MAP_SHARED) && | |
43 | ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) | |
44 | return -EINVAL; | |
45 | return addr; | |
46 | } | |
47 | ||
48 | do_color_align = 0; | |
49 | if (filp || (flags & MAP_SHARED)) | |
50 | do_color_align = 1; | |
51 | if (addr) { | |
52 | if (do_color_align) | |
53 | addr = COLOUR_ALIGN(addr, pgoff); | |
54 | else | |
55 | addr = PAGE_ALIGN(addr); | |
56 | vmm = find_vma(current->mm, addr); | |
57 | if (TASK_SIZE - len >= addr && | |
58 | (!vmm || addr + len <= vmm->vm_start)) | |
59 | return addr; | |
60 | } | |
61 | addr = current->mm->mmap_base; | |
62 | if (do_color_align) | |
63 | addr = COLOUR_ALIGN(addr, pgoff); | |
64 | else | |
65 | addr = PAGE_ALIGN(addr); | |
66 | ||
67 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { | |
68 | /* At this point: (!vmm || addr < vmm->vm_end). */ | |
69 | if (TASK_SIZE - len < addr) | |
70 | return -ENOMEM; | |
71 | if (!vmm || addr + len <= vmm->vm_start) | |
72 | return addr; | |
73 | addr = vmm->vm_end; | |
74 | if (do_color_align) | |
75 | addr = COLOUR_ALIGN(addr, pgoff); | |
76 | } | |
77 | } | |
78 | ||
79 | void arch_pick_mmap_layout(struct mm_struct *mm) | |
80 | { | |
81 | unsigned long random_factor = 0UL; | |
82 | ||
83 | if (current->flags & PF_RANDOMIZE) { | |
84 | random_factor = get_random_int(); | |
85 | random_factor = random_factor << PAGE_SHIFT; | |
86 | if (TASK_IS_32BIT_ADDR) | |
87 | random_factor &= 0xfffffful; | |
88 | else | |
89 | random_factor &= 0xffffffful; | |
90 | } | |
91 | ||
92 | mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; | |
93 | mm->get_unmapped_area = arch_get_unmapped_area; | |
94 | mm->unmap_area = arch_unmap_area; | |
95 | } | |
96 | ||
97 | static inline unsigned long brk_rnd(void) | |
98 | { | |
99 | unsigned long rnd = get_random_int(); | |
100 | ||
101 | rnd = rnd << PAGE_SHIFT; | |
102 | /* 8MB for 32bit, 256MB for 64bit */ | |
103 | if (TASK_IS_32BIT_ADDR) | |
104 | rnd = rnd & 0x7ffffful; | |
105 | else | |
106 | rnd = rnd & 0xffffffful; | |
107 | ||
108 | return rnd; | |
109 | } | |
110 | ||
111 | unsigned long arch_randomize_brk(struct mm_struct *mm) | |
112 | { | |
113 | unsigned long base = mm->brk; | |
114 | unsigned long ret; | |
115 | ||
116 | ret = PAGE_ALIGN(base + brk_rnd()); | |
117 | ||
118 | if (ret < mm->brk) | |
119 | return mm->brk; | |
120 | ||
121 | return ret; | |
122 | } |