Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kees Cook and committed by
H. Peter Anvin
8ab3820f dd78b973

+106 -24
+4
Documentation/kernel-parameters.txt
··· 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
+34 -4
arch/x86/Kconfig
··· 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---
+1 -1
arch/x86/boot/compressed/Makefile
··· 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
+23
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 */
+1 -1
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)
+6 -4
arch/x86/boot/compressed/head_32.S
··· 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 ··· 193 191 leal boot_heap(%ebx), %eax 194 192 pushl %eax /* heap area */ 195 193 pushl %esi /* real mode pointer */ 196 - call decompress_kernel 194 + call decompress_kernel /* returns kernel location in %eax */ 197 195 addl $24, %esp 198 196 199 197 /* 200 198 * Jump to the decompressed kernel. 201 199 */ 202 200 xorl %ebx, %ebx 203 - jmp *%ebp 201 + jmp *%eax 204 202 205 203 /* 206 204 * Stack and heap for uncompression
+10 -6
arch/x86/boot/compressed/head_64.S
··· 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 ··· 271 269 addq %rax, %rbp 272 270 notq %rax 273 271 andq %rax, %rbp 274 - #else 275 - movq $LOAD_PHYSICAL_ADDR, %rbp 272 + cmpq $LOAD_PHYSICAL_ADDR, %rbp 273 + jge 1f 276 274 #endif 275 + movq $LOAD_PHYSICAL_ADDR, %rbp 276 + 1: 277 277 278 278 /* Target address to relocate to for decompression */ 279 279 leaq z_extract_offset(%rbp), %rbx ··· 343 339 movl $z_input_len, %ecx /* input_len */ 344 340 movq %rbp, %r8 /* output target address */ 345 341 movq $z_output_len, %r9 /* decompressed length */ 346 - call decompress_kernel 342 + call decompress_kernel /* returns kernel location in %rax */ 347 343 popq %rsi 348 344 349 345 /* 350 346 * Jump to the decompressed kernel. 351 347 */ 352 - jmp *%rbp 348 + jmp *%rax 353 349 354 350 .code32 355 351 no_longmode:
+6 -2
arch/x86/boot/compressed/misc.c
··· 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 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 ··· 445 441 parse_elf(output); 446 442 handle_relocations(output, output_len); 447 443 debug_putstr("done.\nBooting the kernel.\n"); 448 - return; 444 + return output; 449 445 }
+21 -6
arch/x86/boot/compressed/misc.h
··· 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 + 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); 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 65 + 66 + #ifdef CONFIG_EARLY_PRINTK 48 67 /* early_serial_console.c */ 49 68 extern int early_serial_base; 50 69 void console_init(void); 51 - 52 70 #else 53 - 54 - /* early_serial_console.c */ 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