x86/KASLR: Clarify purpose of kaslr.c
[deliverable/linux.git] / arch / x86 / boot / compressed / kaslr.c
CommitLineData
7de828df
KC
1/*
2 * kaslr.c
3 *
4 * This contains the routines needed to generate a reasonable level of
5 * entropy to choose a randomized kernel base address offset in support
6 * of Kernel Address Space Layout Randomization (KASLR). Additionally
7 * handles walking the physical memory maps (and tracking memory regions
8 * to avoid) in order to select a physical memory location that can
9 * contain the entire properly aligned running kernel image.
10 *
11 */
8ab3820f
KC
12#include "misc.h"
13
5bfce5ef
KC
14#include <asm/msr.h>
15#include <asm/archrandom.h>
82fa9637 16#include <asm/e820.h>
5bfce5ef 17
a653f356
KC
18#include <generated/compile.h>
19#include <linux/module.h>
20#include <linux/uts.h>
21#include <linux/utsname.h>
22#include <generated/utsrelease.h>
a653f356
KC
23
24/* Simplified build-specific string for starting entropy. */
327f7d72 25static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
a653f356
KC
26 LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
27
5bfce5ef
KC
28#define I8254_PORT_CONTROL 0x43
29#define I8254_PORT_COUNTER0 0x40
30#define I8254_CMD_READBACK 0xC0
31#define I8254_SELECT_COUNTER0 0x02
32#define I8254_STATUS_NOTREADY 0x40
33static inline u16 i8254(void)
34{
35 u16 status, timer;
36
37 do {
38 outb(I8254_PORT_CONTROL,
39 I8254_CMD_READBACK | I8254_SELECT_COUNTER0);
40 status = inb(I8254_PORT_COUNTER0);
41 timer = inb(I8254_PORT_COUNTER0);
42 timer |= inb(I8254_PORT_COUNTER0) << 8;
43 } while (status & I8254_STATUS_NOTREADY);
44
45 return timer;
46}
47
a653f356
KC
48static unsigned long rotate_xor(unsigned long hash, const void *area,
49 size_t size)
50{
51 size_t i;
52 unsigned long *ptr = (unsigned long *)area;
53
54 for (i = 0; i < size / sizeof(hash); i++) {
55 /* Rotate by odd number of bits and XOR. */
56 hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
57 hash ^= ptr[i];
58 }
59
60 return hash;
61}
62
63/* Attempt to create a simple but unpredictable starting entropy. */
64static unsigned long get_random_boot(void)
65{
66 unsigned long hash = 0;
67
68 hash = rotate_xor(hash, build_str, sizeof(build_str));
6655e0aa 69 hash = rotate_xor(hash, boot_params, sizeof(*boot_params));
a653f356
KC
70
71 return hash;
72}
73
5bfce5ef
KC
74static unsigned long get_random_long(void)
75{
e8236c4d
PA
76#ifdef CONFIG_X86_64
77 const unsigned long mix_const = 0x5d6008cbf3848dd3UL;
78#else
79 const unsigned long mix_const = 0x3f39e593UL;
80#endif
a653f356
KC
81 unsigned long raw, random = get_random_boot();
82 bool use_i8254 = true;
83
84 debug_putstr("KASLR using");
5bfce5ef
KC
85
86 if (has_cpuflag(X86_FEATURE_RDRAND)) {
a653f356
KC
87 debug_putstr(" RDRAND");
88 if (rdrand_long(&raw)) {
89 random ^= raw;
90 use_i8254 = false;
91 }
5bfce5ef
KC
92 }
93
94 if (has_cpuflag(X86_FEATURE_TSC)) {
a653f356 95 debug_putstr(" RDTSC");
4ea1636b 96 raw = rdtsc();
5bfce5ef 97
a653f356
KC
98 random ^= raw;
99 use_i8254 = false;
100 }
5bfce5ef 101
a653f356
KC
102 if (use_i8254) {
103 debug_putstr(" i8254");
104 random ^= i8254();
5bfce5ef
KC
105 }
106
e8236c4d
PA
107 /* Circular multiply for better bit diffusion */
108 asm("mul %3"
109 : "=a" (random), "=d" (raw)
110 : "a" (random), "rm" (mix_const));
111 random += raw;
112
a653f356
KC
113 debug_putstr("...\n");
114
5bfce5ef
KC
115 return random;
116}
8ab3820f 117
82fa9637
KC
118struct mem_vector {
119 unsigned long start;
120 unsigned long size;
121};
122
123#define MEM_AVOID_MAX 5
e290e8c5 124static struct mem_vector mem_avoid[MEM_AVOID_MAX];
82fa9637
KC
125
126static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
127{
128 /* Item at least partially before region. */
129 if (item->start < region->start)
130 return false;
131 /* Item at least partially after region. */
132 if (item->start + item->size > region->start + region->size)
133 return false;
134 return true;
135}
136
137static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
138{
139 /* Item one is entirely before item two. */
140 if (one->start + one->size <= two->start)
141 return false;
142 /* Item one is entirely after item two. */
143 if (one->start >= two->start + two->size)
144 return false;
145 return true;
146}
147
148static void mem_avoid_init(unsigned long input, unsigned long input_size,
149 unsigned long output, unsigned long output_size)
150{
151 u64 initrd_start, initrd_size;
152 u64 cmd_line, cmd_line_size;
153 unsigned long unsafe, unsafe_len;
154 char *ptr;
155
156 /*
157 * Avoid the region that is unsafe to overlap during
158 * decompression (see calculations at top of misc.c).
159 */
160 unsafe_len = (output_size >> 12) + 32768 + 18;
161 unsafe = (unsigned long)input + input_size - unsafe_len;
162 mem_avoid[0].start = unsafe;
163 mem_avoid[0].size = unsafe_len;
164
165 /* Avoid initrd. */
6655e0aa
KC
166 initrd_start = (u64)boot_params->ext_ramdisk_image << 32;
167 initrd_start |= boot_params->hdr.ramdisk_image;
168 initrd_size = (u64)boot_params->ext_ramdisk_size << 32;
169 initrd_size |= boot_params->hdr.ramdisk_size;
82fa9637
KC
170 mem_avoid[1].start = initrd_start;
171 mem_avoid[1].size = initrd_size;
172
173 /* Avoid kernel command line. */
6655e0aa
KC
174 cmd_line = (u64)boot_params->ext_cmd_line_ptr << 32;
175 cmd_line |= boot_params->hdr.cmd_line_ptr;
82fa9637
KC
176 /* Calculate size of cmd_line. */
177 ptr = (char *)(unsigned long)cmd_line;
178 for (cmd_line_size = 0; ptr[cmd_line_size++]; )
179 ;
180 mem_avoid[2].start = cmd_line;
181 mem_avoid[2].size = cmd_line_size;
182
183 /* Avoid heap memory. */
184 mem_avoid[3].start = (unsigned long)free_mem_ptr;
185 mem_avoid[3].size = BOOT_HEAP_SIZE;
186
187 /* Avoid stack memory. */
188 mem_avoid[4].start = (unsigned long)free_mem_end_ptr;
189 mem_avoid[4].size = BOOT_STACK_SIZE;
190}
191
192/* Does this memory vector overlap a known avoided area? */
e290e8c5 193static bool mem_avoid_overlap(struct mem_vector *img)
82fa9637
KC
194{
195 int i;
0cacbfbe 196 struct setup_data *ptr;
82fa9637
KC
197
198 for (i = 0; i < MEM_AVOID_MAX; i++) {
199 if (mem_overlaps(img, &mem_avoid[i]))
200 return true;
201 }
202
0cacbfbe 203 /* Avoid all entries in the setup_data linked list. */
6655e0aa 204 ptr = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
0cacbfbe
KC
205 while (ptr) {
206 struct mem_vector avoid;
207
20cc2888 208 avoid.start = (unsigned long)ptr;
0cacbfbe
KC
209 avoid.size = sizeof(*ptr) + ptr->len;
210
211 if (mem_overlaps(img, &avoid))
212 return true;
213
214 ptr = (struct setup_data *)(unsigned long)ptr->next;
215 }
216
82fa9637
KC
217 return false;
218}
219
e290e8c5
KC
220static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
221 CONFIG_PHYSICAL_ALIGN];
222static unsigned long slot_max;
82fa9637
KC
223
224static void slots_append(unsigned long addr)
225{
226 /* Overflowing the slots list should be impossible. */
227 if (slot_max >= CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
228 CONFIG_PHYSICAL_ALIGN)
229 return;
230
231 slots[slot_max++] = addr;
232}
233
234static unsigned long slots_fetch_random(void)
235{
236 /* Handle case of no slots stored. */
237 if (slot_max == 0)
238 return 0;
239
240 return slots[get_random_long() % slot_max];
241}
242
243static void process_e820_entry(struct e820entry *entry,
244 unsigned long minimum,
245 unsigned long image_size)
246{
247 struct mem_vector region, img;
248
249 /* Skip non-RAM entries. */
250 if (entry->type != E820_RAM)
251 return;
252
253 /* Ignore entries entirely above our maximum. */
254 if (entry->addr >= CONFIG_RANDOMIZE_BASE_MAX_OFFSET)
255 return;
256
257 /* Ignore entries entirely below our minimum. */
258 if (entry->addr + entry->size < minimum)
259 return;
260
261 region.start = entry->addr;
262 region.size = entry->size;
263
264 /* Potentially raise address to minimum location. */
265 if (region.start < minimum)
266 region.start = minimum;
267
268 /* Potentially raise address to meet alignment requirements. */
269 region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
270
271 /* Did we raise the address above the bounds of this e820 region? */
272 if (region.start > entry->addr + entry->size)
273 return;
274
275 /* Reduce size by any delta from the original address. */
276 region.size -= region.start - entry->addr;
277
278 /* Reduce maximum size to fit end of image within maximum limit. */
279 if (region.start + region.size > CONFIG_RANDOMIZE_BASE_MAX_OFFSET)
280 region.size = CONFIG_RANDOMIZE_BASE_MAX_OFFSET - region.start;
281
282 /* Walk each aligned slot and check for avoided areas. */
283 for (img.start = region.start, img.size = image_size ;
284 mem_contains(&region, &img) ;
285 img.start += CONFIG_PHYSICAL_ALIGN) {
286 if (mem_avoid_overlap(&img))
287 continue;
288 slots_append(img.start);
289 }
290}
291
292static unsigned long find_random_addr(unsigned long minimum,
293 unsigned long size)
294{
295 int i;
296 unsigned long addr;
297
298 /* Make sure minimum is aligned. */
299 minimum = ALIGN(minimum, CONFIG_PHYSICAL_ALIGN);
300
301 /* Verify potential e820 positions, appending to slots list. */
6655e0aa
KC
302 for (i = 0; i < boot_params->e820_entries; i++) {
303 process_e820_entry(&boot_params->e820_map[i], minimum, size);
82fa9637
KC
304 }
305
306 return slots_fetch_random();
307}
308
7de828df 309unsigned char *choose_random_location(unsigned char *input,
8ab3820f
KC
310 unsigned long input_size,
311 unsigned char *output,
312 unsigned long output_size)
313{
314 unsigned long choice = (unsigned long)output;
82fa9637 315 unsigned long random;
8ab3820f 316
24f2e027
KC
317#ifdef CONFIG_HIBERNATION
318 if (!cmdline_find_option_bool("kaslr")) {
319 debug_putstr("KASLR disabled by default...\n");
320 goto out;
321 }
322#else
8ab3820f 323 if (cmdline_find_option_bool("nokaslr")) {
24f2e027 324 debug_putstr("KASLR disabled by cmdline...\n");
8ab3820f
KC
325 goto out;
326 }
24f2e027 327#endif
8ab3820f 328
6655e0aa 329 boot_params->hdr.loadflags |= KASLR_FLAG;
78cac48c 330
82fa9637
KC
331 /* Record the various known unsafe memory ranges. */
332 mem_avoid_init((unsigned long)input, input_size,
333 (unsigned long)output, output_size);
334
335 /* Walk e820 and find a random address. */
336 random = find_random_addr(choice, output_size);
337 if (!random) {
338 debug_putstr("KASLR could not find suitable E820 region...\n");
339 goto out;
340 }
341
342 /* Always enforce the minimum. */
343 if (random < choice)
344 goto out;
8ab3820f 345
82fa9637 346 choice = random;
8ab3820f
KC
347out:
348 return (unsigned char *)choice;
349}
This page took 0.126805 seconds and 5 git commands to generate.