Commit 8ab3820fd5b2896d66da7bb2a906bc382e63e7bc

Authored by Kees Cook
Committed by H. Peter Anvin
1 parent dd78b97367

x86, kaslr: Return location from decompress_kernel

This allows decompress_kernel to return a new location for the kernel to
be relocated to. Additionally, enforces CONFIG_PHYSICAL_START as the
minimum relocation position when building with CONFIG_RELOCATABLE.

With CONFIG_RANDOMIZE_BASE set, the choose_kernel_location routine
will select a new location to decompress the kernel, though here it is
presently a no-op. The kernel command line option "nokaslr" is introduced
to bypass these routines.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1381450698-28710-3-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

Showing 9 changed files with 106 additions and 24 deletions Side-by-side Diff

Documentation/kernel-parameters.txt
... ... @@ -1975,6 +1975,10 @@
1975 1975 noapic [SMP,APIC] Tells the kernel to not make use of any
1976 1976 IOAPICs that may be present in the system.
1977 1977  
  1978 + nokaslr [X86]
  1979 + Disable kernel base offset ASLR (Address Space
  1980 + Layout Randomization) if built into the kernel.
  1981 +
1978 1982 noautogroup Disable scheduler automatic task group creation.
1979 1983  
1980 1984 nobats [PPC] Do not use BATs for mapping kernel lowmem
... ... @@ -1722,16 +1722,46 @@
1722 1722  
1723 1723 Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
1724 1724 it has been loaded at and the compile time physical address
1725   - (CONFIG_PHYSICAL_START) is ignored.
  1725 + (CONFIG_PHYSICAL_START) is used as the minimum location.
1726 1726  
1727   -# Relocation on x86-32 needs some additional build support
  1727 +config RANDOMIZE_BASE
  1728 + bool "Randomize the address of the kernel image"
  1729 + depends on RELOCATABLE
  1730 + depends on !HIBERNATION
  1731 + default n
  1732 + ---help---
  1733 + Randomizes the physical and virtual address at which the
  1734 + kernel image is decompressed, as a security feature that
  1735 + deters exploit attempts relying on knowledge of the location
  1736 + of kernel internals.
  1737 +
  1738 + Entropy is generated using the RDRAND instruction if it
  1739 + is supported. If not, then RDTSC is used, if supported. If
  1740 + neither RDRAND nor RDTSC are supported, then no randomness
  1741 + is introduced.
  1742 +
  1743 + The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET,
  1744 + and aligned according to PHYSICAL_ALIGN.
  1745 +
  1746 +config RANDOMIZE_BASE_MAX_OFFSET
  1747 + hex "Maximum ASLR offset allowed"
  1748 + depends on RANDOMIZE_BASE
  1749 + default "0x10000000"
  1750 + range 0x0 0x10000000
  1751 + ---help---
  1752 + Determines the maximal offset in bytes that will be applied to the
  1753 + kernel when Address Space Layout Randomization (ASLR) is active.
  1754 + Must be less than or equal to the actual physical memory on the
  1755 + system. This must be a power of two.
  1756 +
  1757 +# Relocation on x86 needs some additional build support
1728 1758 config X86_NEED_RELOCS
1729 1759 def_bool y
1730   - depends on X86_32 && RELOCATABLE
  1760 + depends on RANDOMIZE_BASE || (X86_32 && RELOCATABLE)
1731 1761  
1732 1762 config PHYSICAL_ALIGN
1733 1763 hex "Alignment value to which kernel should be aligned"
1734   - default "0x1000000"
  1764 + default "0x200000"
1735 1765 range 0x2000 0x1000000 if X86_32
1736 1766 range 0x200000 0x1000000 if X86_64
1737 1767 ---help---
arch/x86/boot/compressed/Makefile
... ... @@ -27,7 +27,7 @@
27 27  
28 28 VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
29 29 $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
30   - $(obj)/piggy.o $(obj)/cpuflags.o
  30 + $(obj)/piggy.o $(obj)/cpuflags.o $(obj)/aslr.o
31 31  
32 32 $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
33 33  
arch/x86/boot/compressed/aslr.c
  1 +#include "misc.h"
  2 +
  3 +#ifdef CONFIG_RANDOMIZE_BASE
  4 +
  5 +unsigned char *choose_kernel_location(unsigned char *input,
  6 + unsigned long input_size,
  7 + unsigned char *output,
  8 + unsigned long output_size)
  9 +{
  10 + unsigned long choice = (unsigned long)output;
  11 +
  12 + if (cmdline_find_option_bool("nokaslr")) {
  13 + debug_putstr("KASLR disabled...\n");
  14 + goto out;
  15 + }
  16 +
  17 + /* XXX: choose random location. */
  18 +
  19 +out:
  20 + return (unsigned char *)choice;
  21 +}
  22 +
  23 +#endif /* CONFIG_RANDOMIZE_BASE */
arch/x86/boot/compressed/cmdline.c
1 1 #include "misc.h"
2 2  
3   -#ifdef CONFIG_EARLY_PRINTK
  3 +#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
4 4  
5 5 static unsigned long fs;
6 6 static inline void set_fs(unsigned long seg)
arch/x86/boot/compressed/head_32.S
... ... @@ -117,9 +117,11 @@
117 117 addl %eax, %ebx
118 118 notl %eax
119 119 andl %eax, %ebx
120   -#else
121   - movl $LOAD_PHYSICAL_ADDR, %ebx
  120 + cmpl $LOAD_PHYSICAL_ADDR, %ebx
  121 + jge 1f
122 122 #endif
  123 + movl $LOAD_PHYSICAL_ADDR, %ebx
  124 +1:
123 125  
124 126 /* Target address to relocate to for decompression */
125 127 addl $z_extract_offset, %ebx
126 128  
... ... @@ -191,14 +193,14 @@
191 193 leal boot_heap(%ebx), %eax
192 194 pushl %eax /* heap area */
193 195 pushl %esi /* real mode pointer */
194   - call decompress_kernel
  196 + call decompress_kernel /* returns kernel location in %eax */
195 197 addl $24, %esp
196 198  
197 199 /*
198 200 * Jump to the decompressed kernel.
199 201 */
200 202 xorl %ebx, %ebx
201   - jmp *%ebp
  203 + jmp *%eax
202 204  
203 205 /*
204 206 * Stack and heap for uncompression
arch/x86/boot/compressed/head_64.S
... ... @@ -94,9 +94,11 @@
94 94 addl %eax, %ebx
95 95 notl %eax
96 96 andl %eax, %ebx
97   -#else
98   - movl $LOAD_PHYSICAL_ADDR, %ebx
  97 + cmpl $LOAD_PHYSICAL_ADDR, %ebx
  98 + jge 1f
99 99 #endif
  100 + movl $LOAD_PHYSICAL_ADDR, %ebx
  101 +1:
100 102  
101 103 /* Target address to relocate to for decompression */
102 104 addl $z_extract_offset, %ebx
103 105  
... ... @@ -269,9 +271,11 @@
269 271 addq %rax, %rbp
270 272 notq %rax
271 273 andq %rax, %rbp
272   -#else
273   - movq $LOAD_PHYSICAL_ADDR, %rbp
  274 + cmpq $LOAD_PHYSICAL_ADDR, %rbp
  275 + jge 1f
274 276 #endif
  277 + movq $LOAD_PHYSICAL_ADDR, %rbp
  278 +1:
275 279  
276 280 /* Target address to relocate to for decompression */
277 281 leaq z_extract_offset(%rbp), %rbx
278 282  
... ... @@ -339,13 +343,13 @@
339 343 movl $z_input_len, %ecx /* input_len */
340 344 movq %rbp, %r8 /* output target address */
341 345 movq $z_output_len, %r9 /* decompressed length */
342   - call decompress_kernel
  346 + call decompress_kernel /* returns kernel location in %rax */
343 347 popq %rsi
344 348  
345 349 /*
346 350 * Jump to the decompressed kernel.
347 351 */
348   - jmp *%rbp
  352 + jmp *%rax
349 353  
350 354 .code32
351 355 no_longmode:
arch/x86/boot/compressed/misc.c
... ... @@ -395,7 +395,7 @@
395 395 free(phdrs);
396 396 }
397 397  
398   -asmlinkage void decompress_kernel(void *rmode, memptr heap,
  398 +asmlinkage void *decompress_kernel(void *rmode, memptr heap,
399 399 unsigned char *input_data,
400 400 unsigned long input_len,
401 401 unsigned char *output,
... ... @@ -422,6 +422,10 @@
422 422 free_mem_ptr = heap; /* Heap */
423 423 free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
424 424  
  425 + output = choose_kernel_location(input_data, input_len,
  426 + output, output_len);
  427 +
  428 + /* Validate memory location choices. */
425 429 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
426 430 error("Destination address inappropriately aligned");
427 431 #ifdef CONFIG_X86_64
... ... @@ -441,6 +445,6 @@
441 445 parse_elf(output);
442 446 handle_relocations(output, output_len);
443 447 debug_putstr("done.\nBooting the kernel.\n");
444   - return;
  448 + return output;
445 449 }
arch/x86/boot/compressed/misc.h
... ... @@ -39,23 +39,38 @@
39 39  
40 40 #endif
41 41  
42   -#ifdef CONFIG_EARLY_PRINTK
43   -
  42 +#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
44 43 /* cmdline.c */
45 44 int cmdline_find_option(const char *option, char *buffer, int bufsize);
46 45 int cmdline_find_option_bool(const char *option);
  46 +#endif
47 47  
48   -/* early_serial_console.c */
49   -extern int early_serial_base;
50   -void console_init(void);
51 48  
  49 +#if CONFIG_RANDOMIZE_BASE
  50 +/* aslr.c */
  51 +unsigned char *choose_kernel_location(unsigned char *input,
  52 + unsigned long input_size,
  53 + unsigned char *output,
  54 + unsigned long output_size);
52 55 #else
  56 +static inline
  57 +unsigned char *choose_kernel_location(unsigned char *input,
  58 + unsigned long input_size,
  59 + unsigned char *output,
  60 + unsigned long output_size)
  61 +{
  62 + return output;
  63 +}
  64 +#endif
53 65  
  66 +#ifdef CONFIG_EARLY_PRINTK
54 67 /* early_serial_console.c */
  68 +extern int early_serial_base;
  69 +void console_init(void);
  70 +#else
55 71 static const int early_serial_base;
56 72 static inline void console_init(void)
57 73 { }
58   -
59 74 #endif
60 75  
61 76 #endif