aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2016-05-05 18:13:47 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-06 03:00:59 -0400
commit9dc1969c24eff8b7d7a9a565d1047b624921ba06 (patch)
tree4e8d8340cd8c8ae9f458405495edf3d0306e49da
parent2bc1cd39fa9f659956b25e500422e700a6cd4ec3 (diff)
x86/KASLR: Consolidate mem_avoid[] entries
The mem_avoid[] array is used to track positions that should be avoided (like the compressed kernel, decompression code, etc) when selecting a memory position for the randomly relocated kernel. Since ZO is now at the end of the decompression buffer and the decompression code (and its heap and stack) are at the front, we can safely consolidate the decompression entry, the heap entry, and the stack entry. The boot_params memory, however, could be elsewhere, so it should be explicitly included. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Baoquan He <bhe@redhat.com> [ Rwrote changelog, cleaned up code comments. ] Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Dave Young <dyoung@redhat.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vivek Goyal <vgoyal@redhat.com> Cc: kernel-hardening@lists.openwall.com Cc: lasse.collin@tukaani.org Link: http://lkml.kernel.org/r/1462486436-3707-3-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/boot/compressed/kaslr.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
index 2072d82c1911..6392f0041b8a 100644
--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -121,7 +121,7 @@ struct mem_vector {
121 unsigned long size; 121 unsigned long size;
122}; 122};
123 123
124#define MEM_AVOID_MAX 5 124#define MEM_AVOID_MAX 4
125static struct mem_vector mem_avoid[MEM_AVOID_MAX]; 125static struct mem_vector mem_avoid[MEM_AVOID_MAX];
126 126
127static bool mem_contains(struct mem_vector *region, struct mem_vector *item) 127static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
@@ -146,22 +146,71 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
146 return true; 146 return true;
147} 147}
148 148
149/*
150 * In theroy, KASLR can put the kernel anywhere in area of [16M, 64T). The
151 * mem_avoid array is used to store the ranges that need to be avoided when
152 * KASLR searches for a an appropriate random address. We must avoid any
153 * regions that are unsafe to overlap with during decompression, and other
154 * things like the initrd, cmdline and boot_params.
155 *
156 * How to calculate the unsafe areas is detailed here, and is informed by
157 * the decompression calculations in header.S, and the diagram in misc.c.
158 *
159 * The compressed vmlinux (ZO) plus relocs and the run space of ZO can't be
160 * overwritten by decompression output.
161 *
162 * ZO sits against the end of the decompression buffer, so we can calculate
163 * where text, data, bss, etc of ZO are positioned.
164 *
165 * The follow are already enforced by the code:
166 * - init_size >= kernel_total_size
167 * - input + input_len >= output + output_len
168 * - kernel_total_size could be >= or < output_len
169 *
170 * From this, we can make several observations, illustrated by a diagram:
171 * - init_size >= kernel_total_size
172 * - input + input_len > output + output_len
173 * - kernel_total_size >= output_len
174 *
175 * 0 output input input+input_len output+init_size
176 * | | | | |
177 * | | | | |
178 * |-----|--------|--------|------------------|----|------------|----------|
179 * | | |
180 * | | |
181 * output+init_size-ZO_INIT_SIZE output+output_len output+kernel_total_size
182 *
183 * [output, output+init_size) is for the buffer for decompressing the
184 * compressed kernel (ZO).
185 *
186 * [output, output+kernel_total_size) is for the uncompressed kernel (VO)
187 * and its bss, brk, etc.
188 * [output, output+output_len) is VO plus relocs
189 *
190 * [output+init_size-ZO_INIT_SIZE, output+init_size) is the copied ZO.
191 * [input, input+input_len) is the copied compressed (VO (vmlinux after
192 * objcopy) plus relocs), not the ZO.
193 *
194 * [input+input_len, output+init_size) is [_text, _end) for ZO. That was the
195 * first range in mem_avoid, which included ZO's heap and stack. Also
196 * [input, input+input_size) need be put in mem_avoid array, but since it
197 * is adjacent to the first entry, they can be merged. This is how we get
198 * the first entry in mem_avoid[].
199 */
149static void mem_avoid_init(unsigned long input, unsigned long input_size, 200static void mem_avoid_init(unsigned long input, unsigned long input_size,
150 unsigned long output, unsigned long output_size) 201 unsigned long output)
151{ 202{
203 unsigned long init_size = boot_params->hdr.init_size;
152 u64 initrd_start, initrd_size; 204 u64 initrd_start, initrd_size;
153 u64 cmd_line, cmd_line_size; 205 u64 cmd_line, cmd_line_size;
154 unsigned long unsafe, unsafe_len;
155 char *ptr; 206 char *ptr;
156 207
157 /* 208 /*
158 * Avoid the region that is unsafe to overlap during 209 * Avoid the region that is unsafe to overlap during
159 * decompression (see calculations in ../header.S). 210 * decompression.
160 */ 211 */
161 unsafe_len = (output_size >> 12) + 32768 + 18; 212 mem_avoid[0].start = input;
162 unsafe = (unsigned long)input + input_size - unsafe_len; 213 mem_avoid[0].size = (output + init_size) - input;
163 mem_avoid[0].start = unsafe;
164 mem_avoid[0].size = unsafe_len;
165 214
166 /* Avoid initrd. */ 215 /* Avoid initrd. */
167 initrd_start = (u64)boot_params->ext_ramdisk_image << 32; 216 initrd_start = (u64)boot_params->ext_ramdisk_image << 32;
@@ -181,13 +230,9 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
181 mem_avoid[2].start = cmd_line; 230 mem_avoid[2].start = cmd_line;
182 mem_avoid[2].size = cmd_line_size; 231 mem_avoid[2].size = cmd_line_size;
183 232
184 /* Avoid heap memory. */ 233 /* Avoid params */
185 mem_avoid[3].start = (unsigned long)free_mem_ptr; 234 mem_avoid[3].start = (unsigned long)boot_params;
186 mem_avoid[3].size = BOOT_HEAP_SIZE; 235 mem_avoid[3].size = sizeof(*boot_params);
187
188 /* Avoid stack memory. */
189 mem_avoid[4].start = (unsigned long)free_mem_end_ptr;
190 mem_avoid[4].size = BOOT_STACK_SIZE;
191} 236}
192 237
193/* Does this memory vector overlap a known avoided area? */ 238/* Does this memory vector overlap a known avoided area? */
@@ -337,7 +382,7 @@ unsigned char *choose_random_location(unsigned char *input_ptr,
337 boot_params->hdr.loadflags |= KASLR_FLAG; 382 boot_params->hdr.loadflags |= KASLR_FLAG;
338 383
339 /* Record the various known unsafe memory ranges. */ 384 /* Record the various known unsafe memory ranges. */
340 mem_avoid_init(input, input_size, output, output_size); 385 mem_avoid_init(input, input_size, output);
341 386
342 /* Walk e820 and find a random address. */ 387 /* Walk e820 and find a random address. */
343 random_addr = find_random_addr(output, output_size); 388 random_addr = find_random_addr(output, output_size);