aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2013-10-10 20:18:14 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-10-13 06:12:07 -0400
commit8ab3820fd5b2896d66da7bb2a906bc382e63e7bc (patch)
tree50f6f4458f86eb66552c13bef81169e44d27dc28
parentdd78b97367bd575918204cc89107c1479d3fc1a7 (diff)
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>
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/x86/Kconfig38
-rw-r--r--arch/x86/boot/compressed/Makefile2
-rw-r--r--arch/x86/boot/compressed/aslr.c23
-rw-r--r--arch/x86/boot/compressed/cmdline.c2
-rw-r--r--arch/x86/boot/compressed/head_32.S10
-rw-r--r--arch/x86/boot/compressed/head_64.S16
-rw-r--r--arch/x86/boot/compressed/misc.c8
-rw-r--r--arch/x86/boot/compressed/misc.h27
9 files changed, 106 insertions, 24 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index fcbb736d55fe..773fc4c077b4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1975,6 +1975,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
1975 noapic [SMP,APIC] Tells the kernel to not make use of any 1975 noapic [SMP,APIC] Tells the kernel to not make use of any
1976 IOAPICs that may be present in the system. 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 noautogroup Disable scheduler automatic task group creation. 1982 noautogroup Disable scheduler automatic task group creation.
1979 1983
1980 nobats [PPC] Do not use BATs for mapping kernel lowmem 1984 nobats [PPC] Do not use BATs for mapping kernel lowmem
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ee2fb9d37745..992701d4d4f8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1722,16 +1722,46 @@ config RELOCATABLE
1722 1722
1723 Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address 1723 Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
1724 it has been loaded at and the compile time physical address 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 1727config 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
1746config 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
1728config X86_NEED_RELOCS 1758config X86_NEED_RELOCS
1729 def_bool y 1759 def_bool y
1730 depends on X86_32 && RELOCATABLE 1760 depends on RANDOMIZE_BASE || (X86_32 && RELOCATABLE)
1731 1761
1732config PHYSICAL_ALIGN 1762config PHYSICAL_ALIGN
1733 hex "Alignment value to which kernel should be aligned" 1763 hex "Alignment value to which kernel should be aligned"
1734 default "0x1000000" 1764 default "0x200000"
1735 range 0x2000 0x1000000 if X86_32 1765 range 0x2000 0x1000000 if X86_32
1736 range 0x200000 0x1000000 if X86_64 1766 range 0x200000 0x1000000 if X86_64
1737 ---help--- 1767 ---help---
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 3312f1be9fd9..ae8b5dbbd8c5 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
27 27
28VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ 28VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
29 $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ 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$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone 32$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
33 33
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
new file mode 100644
index 000000000000..b73cc66d201e
--- /dev/null
+++ b/arch/x86/boot/compressed/aslr.c
@@ -0,0 +1,23 @@
1#include "misc.h"
2
3#ifdef CONFIG_RANDOMIZE_BASE
4
5unsigned 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
19out:
20 return (unsigned char *)choice;
21}
22
23#endif /* CONFIG_RANDOMIZE_BASE */
diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c
index bffd73b45b1f..b68e3033e6b9 100644
--- a/arch/x86/boot/compressed/cmdline.c
+++ b/arch/x86/boot/compressed/cmdline.c
@@ -1,6 +1,6 @@
1#include "misc.h" 1#include "misc.h"
2 2
3#ifdef CONFIG_EARLY_PRINTK 3#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
4 4
5static unsigned long fs; 5static unsigned long fs;
6static inline void set_fs(unsigned long seg) 6static inline void set_fs(unsigned long seg)
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 5d6f6891b188..9116aac232c7 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -117,9 +117,11 @@ preferred_addr:
117 addl %eax, %ebx 117 addl %eax, %ebx
118 notl %eax 118 notl %eax
119 andl %eax, %ebx 119 andl %eax, %ebx
120#else 120 cmpl $LOAD_PHYSICAL_ADDR, %ebx
121 movl $LOAD_PHYSICAL_ADDR, %ebx 121 jge 1f
122#endif 122#endif
123 movl $LOAD_PHYSICAL_ADDR, %ebx
1241:
123 125
124 /* Target address to relocate to for decompression */ 126 /* Target address to relocate to for decompression */
125 addl $z_extract_offset, %ebx 127 addl $z_extract_offset, %ebx
@@ -191,14 +193,14 @@ relocated:
191 leal boot_heap(%ebx), %eax 193 leal boot_heap(%ebx), %eax
192 pushl %eax /* heap area */ 194 pushl %eax /* heap area */
193 pushl %esi /* real mode pointer */ 195 pushl %esi /* real mode pointer */
194 call decompress_kernel 196 call decompress_kernel /* returns kernel location in %eax */
195 addl $24, %esp 197 addl $24, %esp
196 198
197/* 199/*
198 * Jump to the decompressed kernel. 200 * Jump to the decompressed kernel.
199 */ 201 */
200 xorl %ebx, %ebx 202 xorl %ebx, %ebx
201 jmp *%ebp 203 jmp *%eax
202 204
203/* 205/*
204 * Stack and heap for uncompression 206 * Stack and heap for uncompression
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index c337422b575d..c5c1ae0997e7 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -94,9 +94,11 @@ ENTRY(startup_32)
94 addl %eax, %ebx 94 addl %eax, %ebx
95 notl %eax 95 notl %eax
96 andl %eax, %ebx 96 andl %eax, %ebx
97#else 97 cmpl $LOAD_PHYSICAL_ADDR, %ebx
98 movl $LOAD_PHYSICAL_ADDR, %ebx 98 jge 1f
99#endif 99#endif
100 movl $LOAD_PHYSICAL_ADDR, %ebx
1011:
100 102
101 /* Target address to relocate to for decompression */ 103 /* Target address to relocate to for decompression */
102 addl $z_extract_offset, %ebx 104 addl $z_extract_offset, %ebx
@@ -269,9 +271,11 @@ preferred_addr:
269 addq %rax, %rbp 271 addq %rax, %rbp
270 notq %rax 272 notq %rax
271 andq %rax, %rbp 273 andq %rax, %rbp
272#else 274 cmpq $LOAD_PHYSICAL_ADDR, %rbp
273 movq $LOAD_PHYSICAL_ADDR, %rbp 275 jge 1f
274#endif 276#endif
277 movq $LOAD_PHYSICAL_ADDR, %rbp
2781:
275 279
276 /* Target address to relocate to for decompression */ 280 /* Target address to relocate to for decompression */
277 leaq z_extract_offset(%rbp), %rbx 281 leaq z_extract_offset(%rbp), %rbx
@@ -339,13 +343,13 @@ relocated:
339 movl $z_input_len, %ecx /* input_len */ 343 movl $z_input_len, %ecx /* input_len */
340 movq %rbp, %r8 /* output target address */ 344 movq %rbp, %r8 /* output target address */
341 movq $z_output_len, %r9 /* decompressed length */ 345 movq $z_output_len, %r9 /* decompressed length */
342 call decompress_kernel 346 call decompress_kernel /* returns kernel location in %rax */
343 popq %rsi 347 popq %rsi
344 348
345/* 349/*
346 * Jump to the decompressed kernel. 350 * Jump to the decompressed kernel.
347 */ 351 */
348 jmp *%rbp 352 jmp *%rax
349 353
350 .code32 354 .code32
351no_longmode: 355no_longmode:
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 434f077d2c4d..71387685dc16 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -395,7 +395,7 @@ static void parse_elf(void *output)
395 free(phdrs); 395 free(phdrs);
396} 396}
397 397
398asmlinkage void decompress_kernel(void *rmode, memptr heap, 398asmlinkage void *decompress_kernel(void *rmode, memptr heap,
399 unsigned char *input_data, 399 unsigned char *input_data,
400 unsigned long input_len, 400 unsigned long input_len,
401 unsigned char *output, 401 unsigned char *output,
@@ -422,6 +422,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
422 free_mem_ptr = heap; /* Heap */ 422 free_mem_ptr = heap; /* Heap */
423 free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 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 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 429 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
426 error("Destination address inappropriately aligned"); 430 error("Destination address inappropriately aligned");
427#ifdef CONFIG_X86_64 431#ifdef CONFIG_X86_64
@@ -441,5 +445,5 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
441 parse_elf(output); 445 parse_elf(output);
442 handle_relocations(output, output_len); 446 handle_relocations(output, output_len);
443 debug_putstr("done.\nBooting the kernel.\n"); 447 debug_putstr("done.\nBooting the kernel.\n");
444 return; 448 return output;
445} 449}
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 674019d8e235..9077af7fd0b8 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -39,23 +39,38 @@ static inline void debug_putstr(const char *s)
39 39
40#endif 40#endif
41 41
42#ifdef CONFIG_EARLY_PRINTK 42#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
43
44/* cmdline.c */ 43/* cmdline.c */
45int cmdline_find_option(const char *option, char *buffer, int bufsize); 44int cmdline_find_option(const char *option, char *buffer, int bufsize);
46int cmdline_find_option_bool(const char *option); 45int cmdline_find_option_bool(const char *option);
46#endif
47 47
48/* early_serial_console.c */
49extern int early_serial_base;
50void console_init(void);
51 48
49#if CONFIG_RANDOMIZE_BASE
50/* aslr.c */
51unsigned char *choose_kernel_location(unsigned char *input,
52 unsigned long input_size,
53 unsigned char *output,
54 unsigned long output_size);
52#else 55#else
56static inline
57unsigned 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/* early_serial_console.c */ 67/* early_serial_console.c */
68extern int early_serial_base;
69void console_init(void);
70#else
55static const int early_serial_base; 71static const int early_serial_base;
56static inline void console_init(void) 72static inline void console_init(void)
57{ } 73{ }
58
59#endif 74#endif
60 75
61#endif 76#endif