Commit 8ab3820f authored by Kees Cook's avatar Kees Cook Committed by H. Peter Anvin

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: default avatarKees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1381450698-28710-3-git-send-email-keescook@chromium.orgSigned-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent dd78b973
...@@ -1975,6 +1975,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1975,6 +1975,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
noapic [SMP,APIC] Tells the kernel to not make use of any noapic [SMP,APIC] Tells the kernel to not make use of any
IOAPICs that may be present in the system. IOAPICs that may be present in the system.
nokaslr [X86]
Disable kernel base offset ASLR (Address Space
Layout Randomization) if built into the kernel.
noautogroup Disable scheduler automatic task group creation. noautogroup Disable scheduler automatic task group creation.
nobats [PPC] Do not use BATs for mapping kernel lowmem nobats [PPC] Do not use BATs for mapping kernel lowmem
......
...@@ -1722,16 +1722,46 @@ config RELOCATABLE ...@@ -1722,16 +1722,46 @@ config RELOCATABLE
Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
it has been loaded at and the compile time physical address it has been loaded at and the compile time physical address
(CONFIG_PHYSICAL_START) is ignored. (CONFIG_PHYSICAL_START) is used as the minimum location.
# Relocation on x86-32 needs some additional build support config RANDOMIZE_BASE
bool "Randomize the address of the kernel image"
depends on RELOCATABLE
depends on !HIBERNATION
default n
---help---
Randomizes the physical and virtual address at which the
kernel image is decompressed, as a security feature that
deters exploit attempts relying on knowledge of the location
of kernel internals.
Entropy is generated using the RDRAND instruction if it
is supported. If not, then RDTSC is used, if supported. If
neither RDRAND nor RDTSC are supported, then no randomness
is introduced.
The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET,
and aligned according to PHYSICAL_ALIGN.
config RANDOMIZE_BASE_MAX_OFFSET
hex "Maximum ASLR offset allowed"
depends on RANDOMIZE_BASE
default "0x10000000"
range 0x0 0x10000000
---help---
Determines the maximal offset in bytes that will be applied to the
kernel when Address Space Layout Randomization (ASLR) is active.
Must be less than or equal to the actual physical memory on the
system. This must be a power of two.
# Relocation on x86 needs some additional build support
config X86_NEED_RELOCS config X86_NEED_RELOCS
def_bool y def_bool y
depends on X86_32 && RELOCATABLE depends on RANDOMIZE_BASE || (X86_32 && RELOCATABLE)
config PHYSICAL_ALIGN config PHYSICAL_ALIGN
hex "Alignment value to which kernel should be aligned" hex "Alignment value to which kernel should be aligned"
default "0x1000000" default "0x200000"
range 0x2000 0x1000000 if X86_32 range 0x2000 0x1000000 if X86_32
range 0x200000 0x1000000 if X86_64 range 0x200000 0x1000000 if X86_64
---help--- ---help---
......
...@@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include ...@@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
$(obj)/piggy.o $(obj)/cpuflags.o $(obj)/piggy.o $(obj)/cpuflags.o $(obj)/aslr.o
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
......
#include "misc.h"
#ifdef CONFIG_RANDOMIZE_BASE
unsigned char *choose_kernel_location(unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size)
{
unsigned long choice = (unsigned long)output;
if (cmdline_find_option_bool("nokaslr")) {
debug_putstr("KASLR disabled...\n");
goto out;
}
/* XXX: choose random location. */
out:
return (unsigned char *)choice;
}
#endif /* CONFIG_RANDOMIZE_BASE */
#include "misc.h" #include "misc.h"
#ifdef CONFIG_EARLY_PRINTK #if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
static unsigned long fs; static unsigned long fs;
static inline void set_fs(unsigned long seg) static inline void set_fs(unsigned long seg)
......
...@@ -117,9 +117,11 @@ preferred_addr: ...@@ -117,9 +117,11 @@ preferred_addr:
addl %eax, %ebx addl %eax, %ebx
notl %eax notl %eax
andl %eax, %ebx andl %eax, %ebx
#else cmpl $LOAD_PHYSICAL_ADDR, %ebx
movl $LOAD_PHYSICAL_ADDR, %ebx jge 1f
#endif #endif
movl $LOAD_PHYSICAL_ADDR, %ebx
1:
/* Target address to relocate to for decompression */ /* Target address to relocate to for decompression */
addl $z_extract_offset, %ebx addl $z_extract_offset, %ebx
...@@ -191,14 +193,14 @@ relocated: ...@@ -191,14 +193,14 @@ relocated:
leal boot_heap(%ebx), %eax leal boot_heap(%ebx), %eax
pushl %eax /* heap area */ pushl %eax /* heap area */
pushl %esi /* real mode pointer */ pushl %esi /* real mode pointer */
call decompress_kernel call decompress_kernel /* returns kernel location in %eax */
addl $24, %esp addl $24, %esp
/* /*
* Jump to the decompressed kernel. * Jump to the decompressed kernel.
*/ */
xorl %ebx, %ebx xorl %ebx, %ebx
jmp *%ebp jmp *%eax
/* /*
* Stack and heap for uncompression * Stack and heap for uncompression
......
...@@ -94,9 +94,11 @@ ENTRY(startup_32) ...@@ -94,9 +94,11 @@ ENTRY(startup_32)
addl %eax, %ebx addl %eax, %ebx
notl %eax notl %eax
andl %eax, %ebx andl %eax, %ebx
#else cmpl $LOAD_PHYSICAL_ADDR, %ebx
movl $LOAD_PHYSICAL_ADDR, %ebx jge 1f
#endif #endif
movl $LOAD_PHYSICAL_ADDR, %ebx
1:
/* Target address to relocate to for decompression */ /* Target address to relocate to for decompression */
addl $z_extract_offset, %ebx addl $z_extract_offset, %ebx
...@@ -269,9 +271,11 @@ preferred_addr: ...@@ -269,9 +271,11 @@ preferred_addr:
addq %rax, %rbp addq %rax, %rbp
notq %rax notq %rax
andq %rax, %rbp andq %rax, %rbp
#else cmpq $LOAD_PHYSICAL_ADDR, %rbp
movq $LOAD_PHYSICAL_ADDR, %rbp jge 1f
#endif #endif
movq $LOAD_PHYSICAL_ADDR, %rbp
1:
/* Target address to relocate to for decompression */ /* Target address to relocate to for decompression */
leaq z_extract_offset(%rbp), %rbx leaq z_extract_offset(%rbp), %rbx
...@@ -339,13 +343,13 @@ relocated: ...@@ -339,13 +343,13 @@ relocated:
movl $z_input_len, %ecx /* input_len */ movl $z_input_len, %ecx /* input_len */
movq %rbp, %r8 /* output target address */ movq %rbp, %r8 /* output target address */
movq $z_output_len, %r9 /* decompressed length */ movq $z_output_len, %r9 /* decompressed length */
call decompress_kernel call decompress_kernel /* returns kernel location in %rax */
popq %rsi popq %rsi
/* /*
* Jump to the decompressed kernel. * Jump to the decompressed kernel.
*/ */
jmp *%rbp jmp *%rax
.code32 .code32
no_longmode: no_longmode:
......
...@@ -395,7 +395,7 @@ static void parse_elf(void *output) ...@@ -395,7 +395,7 @@ static void parse_elf(void *output)
free(phdrs); free(phdrs);
} }
asmlinkage void decompress_kernel(void *rmode, memptr heap, asmlinkage void *decompress_kernel(void *rmode, memptr heap,
unsigned char *input_data, unsigned char *input_data,
unsigned long input_len, unsigned long input_len,
unsigned char *output, unsigned char *output,
...@@ -422,6 +422,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, ...@@ -422,6 +422,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
free_mem_ptr = heap; /* Heap */ free_mem_ptr = heap; /* Heap */
free_mem_end_ptr = heap + BOOT_HEAP_SIZE; free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
output = choose_kernel_location(input_data, input_len,
output, output_len);
/* Validate memory location choices. */
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
error("Destination address inappropriately aligned"); error("Destination address inappropriately aligned");
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -441,5 +445,5 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, ...@@ -441,5 +445,5 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
parse_elf(output); parse_elf(output);
handle_relocations(output, output_len); handle_relocations(output, output_len);
debug_putstr("done.\nBooting the kernel.\n"); debug_putstr("done.\nBooting the kernel.\n");
return; return output;
} }
...@@ -39,23 +39,38 @@ static inline void debug_putstr(const char *s) ...@@ -39,23 +39,38 @@ static inline void debug_putstr(const char *s)
#endif #endif
#ifdef CONFIG_EARLY_PRINTK #if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
/* cmdline.c */ /* cmdline.c */
int cmdline_find_option(const char *option, char *buffer, int bufsize); int cmdline_find_option(const char *option, char *buffer, int bufsize);
int cmdline_find_option_bool(const char *option); int cmdline_find_option_bool(const char *option);
#endif
/* early_serial_console.c */
extern int early_serial_base;
void console_init(void);
#if CONFIG_RANDOMIZE_BASE
/* aslr.c */
unsigned char *choose_kernel_location(unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size);
#else #else
static inline
unsigned char *choose_kernel_location(unsigned char *input,
unsigned long input_size,
unsigned char *output,
unsigned long output_size)
{
return output;
}
#endif
#ifdef CONFIG_EARLY_PRINTK
/* early_serial_console.c */ /* early_serial_console.c */
extern int early_serial_base;
void console_init(void);
#else
static const int early_serial_base; static const int early_serial_base;
static inline void console_init(void) static inline void console_init(void)
{ } { }
#endif #endif
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment