Commit 8ab3820fd5b2896d66da7bb2a906bc382e63e7bc
Committed by
H. Peter Anvin
1 parent
dd78b97367
Exists in
master
and in
16 other branches
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 |
arch/x86/Kconfig
... | ... | @@ -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
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 |