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>
This commit is contained in:
parent
dd78b97367
commit
8ab3820fd5
9 changed files with 106 additions and 24 deletions
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
23
arch/x86/boot/compressed/aslr.c
Normal file
23
arch/x86/boot/compressed/aslr.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#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 */
|
|
@ -1,6 +1,6 @@
|
||||||
#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:
|
||||||
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:
|
||||||
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)
|
||||||
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:
|
||||||
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:
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
#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
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
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;
|
extern int early_serial_base;
|
||||||
void console_init(void);
|
void console_init(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* early_serial_console.c */
|
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue