mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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
@ -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
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
def_bool y
|
||||
depends on X86_32 && RELOCATABLE
|
||||
depends on RANDOMIZE_BASE || (X86_32 && RELOCATABLE)
|
||||
|
||||
config PHYSICAL_ALIGN
|
||||
hex "Alignment value to which kernel should be aligned"
|
||||
default "0x1000000"
|
||||
default "0x200000"
|
||||
range 0x2000 0x1000000 if X86_32
|
||||
range 0x200000 0x1000000 if X86_64
|
||||
---help---
|
||||
|
@ -27,7 +27,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
|
||||
|
||||
VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.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
|
||||
|
||||
|
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"
|
||||
|
||||
#ifdef CONFIG_EARLY_PRINTK
|
||||
#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
|
||||
|
||||
static unsigned long fs;
|
||||
static inline void set_fs(unsigned long seg)
|
||||
|
@ -117,9 +117,11 @@ preferred_addr:
|
||||
addl %eax, %ebx
|
||||
notl %eax
|
||||
andl %eax, %ebx
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
cmpl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
jge 1f
|
||||
#endif
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
1:
|
||||
|
||||
/* Target address to relocate to for decompression */
|
||||
addl $z_extract_offset, %ebx
|
||||
@ -191,14 +193,14 @@ relocated:
|
||||
leal boot_heap(%ebx), %eax
|
||||
pushl %eax /* heap area */
|
||||
pushl %esi /* real mode pointer */
|
||||
call decompress_kernel
|
||||
call decompress_kernel /* returns kernel location in %eax */
|
||||
addl $24, %esp
|
||||
|
||||
/*
|
||||
* Jump to the decompressed kernel.
|
||||
*/
|
||||
xorl %ebx, %ebx
|
||||
jmp *%ebp
|
||||
jmp *%eax
|
||||
|
||||
/*
|
||||
* Stack and heap for uncompression
|
||||
|
@ -94,9 +94,11 @@ ENTRY(startup_32)
|
||||
addl %eax, %ebx
|
||||
notl %eax
|
||||
andl %eax, %ebx
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
cmpl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
jge 1f
|
||||
#endif
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
1:
|
||||
|
||||
/* Target address to relocate to for decompression */
|
||||
addl $z_extract_offset, %ebx
|
||||
@ -269,9 +271,11 @@ preferred_addr:
|
||||
addq %rax, %rbp
|
||||
notq %rax
|
||||
andq %rax, %rbp
|
||||
#else
|
||||
movq $LOAD_PHYSICAL_ADDR, %rbp
|
||||
cmpq $LOAD_PHYSICAL_ADDR, %rbp
|
||||
jge 1f
|
||||
#endif
|
||||
movq $LOAD_PHYSICAL_ADDR, %rbp
|
||||
1:
|
||||
|
||||
/* Target address to relocate to for decompression */
|
||||
leaq z_extract_offset(%rbp), %rbx
|
||||
@ -339,13 +343,13 @@ relocated:
|
||||
movl $z_input_len, %ecx /* input_len */
|
||||
movq %rbp, %r8 /* output target address */
|
||||
movq $z_output_len, %r9 /* decompressed length */
|
||||
call decompress_kernel
|
||||
call decompress_kernel /* returns kernel location in %rax */
|
||||
popq %rsi
|
||||
|
||||
/*
|
||||
* Jump to the decompressed kernel.
|
||||
*/
|
||||
jmp *%rbp
|
||||
jmp *%rax
|
||||
|
||||
.code32
|
||||
no_longmode:
|
||||
|
@ -395,7 +395,7 @@ static void parse_elf(void *output)
|
||||
free(phdrs);
|
||||
}
|
||||
|
||||
asmlinkage void decompress_kernel(void *rmode, memptr heap,
|
||||
asmlinkage void *decompress_kernel(void *rmode, memptr heap,
|
||||
unsigned char *input_data,
|
||||
unsigned long input_len,
|
||||
unsigned char *output,
|
||||
@ -422,6 +422,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
|
||||
free_mem_ptr = heap; /* Heap */
|
||||
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))
|
||||
error("Destination address inappropriately aligned");
|
||||
#ifdef CONFIG_X86_64
|
||||
@ -441,5 +445,5 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
|
||||
parse_elf(output);
|
||||
handle_relocations(output, output_len);
|
||||
debug_putstr("done.\nBooting the kernel.\n");
|
||||
return;
|
||||
return output;
|
||||
}
|
||||
|
@ -39,23 +39,38 @@ static inline void debug_putstr(const char *s)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EARLY_PRINTK
|
||||
|
||||
#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE
|
||||
/* cmdline.c */
|
||||
int cmdline_find_option(const char *option, char *buffer, int bufsize);
|
||||
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 */
|
||||
extern int early_serial_base;
|
||||
void console_init(void);
|
||||
|
||||
#else
|
||||
|
||||
/* early_serial_console.c */
|
||||
static const int early_serial_base;
|
||||
static inline void console_init(void)
|
||||
{ }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user