powerpc: Ensure random space between stack and mmaps
[linux-2.6-block.git] / arch / powerpc / mm / mmap.c
CommitLineData
1da177e4 1/*
1da177e4
LT
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>
9f14c42d 27#include <linux/random.h>
e8edc6e0 28#include <linux/sched.h>
1da177e4
LT
29
30/*
31 * Top of mmap area (just below the process stack).
32 *
33 * Leave an at least ~128 MB hole.
34 */
35#define MIN_GAP (128*1024*1024)
36#define MAX_GAP (TASK_SIZE/6*5)
37
13a2cb36
AB
38static inline int mmap_is_legacy(void)
39{
40 if (current->personality & ADDR_COMPAT_LAYOUT)
41 return 1;
42
43 if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
44 return 1;
45
46 return sysctl_legacy_va_layout;
47}
48
a5adc91a
AB
49/*
50 * Since get_random_int() returns the same value within a 1 jiffy window,
51 * we will almost always get the same randomisation for the stack and mmap
52 * region. This will mean the relative distance between stack and mmap will
53 * be the same.
54 *
55 * To avoid this we can shift the randomness by 1 bit.
56 */
9f14c42d
AB
57static unsigned long mmap_rnd(void)
58{
59 unsigned long rnd = 0;
60
61 if (current->flags & PF_RANDOMIZE) {
62 /* 8MB for 32bit, 1GB for 64bit */
63 if (is_32bit_task())
a5adc91a 64 rnd = (long)(get_random_int() % (1<<(22-PAGE_SHIFT)));
9f14c42d 65 else
a5adc91a 66 rnd = (long)(get_random_int() % (1<<(29-PAGE_SHIFT)));
9f14c42d 67 }
a5adc91a 68 return (rnd << PAGE_SHIFT) * 2;
9f14c42d
AB
69}
70
1da177e4
LT
71static inline unsigned long mmap_base(void)
72{
73 unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
74
75 if (gap < MIN_GAP)
76 gap = MIN_GAP;
77 else if (gap > MAX_GAP)
78 gap = MAX_GAP;
79
9f14c42d 80 return PAGE_ALIGN(TASK_SIZE - gap - mmap_rnd());
1da177e4
LT
81}
82
1da177e4
LT
83/*
84 * This function, called very early during the creation of a new
85 * process VM image, sets up which VM layout function to use:
86 */
87void arch_pick_mmap_layout(struct mm_struct *mm)
88{
89 /*
90 * Fall back to the standard layout if the personality
91 * bit is set, or if the expected stack growth is unlimited:
92 */
93 if (mmap_is_legacy()) {
94 mm->mmap_base = TASK_UNMAPPED_BASE;
95 mm->get_unmapped_area = arch_get_unmapped_area;
96 mm->unmap_area = arch_unmap_area;
97 } else {
98 mm->mmap_base = mmap_base();
99 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
100 mm->unmap_area = arch_unmap_area_topdown;
101 }
102}