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