Subject: [PATCH v2] x86, boot: keep data from boot stage to kernel stage. bp found data from boot stage can not be used kernel stage. Acctually those data area is overlapped with kernel bss stage, and clear_bss() clear them before code in arch/x86/kernel/setup.c access them. To make the data survive that later, we should avoid the overlapping. Need to: 1. move compressed kernel close the end of buffer instead of middle of it. 2. extend init_size so no one from kernel bss and brk will touch the data region from boot/compressed/misc.c -v2: add init_size in arch/x86/boot/header.S instead of BRK. Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Matt Fleming Cc: Kees Cook Signed-off-by: Yinghai Lu --- arch/x86/boot/Makefile | 2 +- arch/x86/boot/compressed/head_32.S | 11 +++++++++-- arch/x86/boot/compressed/head_64.S | 8 ++++++-- arch/x86/boot/compressed/mkpiggy.c | 3 --- arch/x86/boot/compressed/vmlinux.lds.S | 2 ++ arch/x86/boot/header.S | 7 +++++-- arch/x86/kernel/asm-offsets.c | 1 + 7 files changed, 24 insertions(+), 10 deletions(-) Index: linux-2.6/arch/x86/boot/compressed/head_64.S =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/head_64.S +++ linux-2.6/arch/x86/boot/compressed/head_64.S @@ -102,7 +102,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl $z_extract_offset, %ebx + movl BP_init_size(%esi), %eax + subl $_end, %eax + addl %eax, %ebx /* * Prepare for entering 64 bit mode @@ -330,7 +332,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaq z_extract_offset(%rbp), %rbx + movl BP_init_size(%rsi), %ebx + subl $_end, %ebx + addq %rbp, %rbx /* Set up the stack */ leaq boot_stack_end(%rbx), %rsp Index: linux-2.6/arch/x86/kernel/asm-offsets.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/asm-offsets.c +++ linux-2.6/arch/x86/kernel/asm-offsets.c @@ -66,6 +66,7 @@ void common(void) { OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); OFFSET(BP_version, boot_params, hdr.version); OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); + OFFSET(BP_init_size, boot_params, hdr.init_size); OFFSET(BP_pref_address, boot_params, hdr.pref_address); OFFSET(BP_code32_start, boot_params, hdr.code32_start); Index: linux-2.6/arch/x86/boot/compressed/head_32.S =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/head_32.S +++ linux-2.6/arch/x86/boot/compressed/head_32.S @@ -148,7 +148,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl $z_extract_offset, %ebx + movl BP_init_size(%esi), %eax + subl $_end, %eax + addl %eax, %ebx /* Set up the stack */ leal boot_stack_end(%ebx), %esp @@ -209,8 +211,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - leal z_extract_offset_negative(%ebx), %ebp + + movl BP_init_size(%esi), %eax + subl $_end, %eax + movl %ebx, %ebp + subl %eax, %ebp pushl %ebp /* output address */ + pushl $z_input_len /* input_len */ leal input_data(%ebx), %eax pushl %eax /* input_data */ Index: linux-2.6/arch/x86/boot/compressed/mkpiggy.c =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/mkpiggy.c +++ linux-2.6/arch/x86/boot/compressed/mkpiggy.c @@ -82,9 +82,6 @@ int main(int argc, char *argv[]) printf("z_output_len = %lu\n", (unsigned long)olen); printf(".globl z_extract_offset\n"); printf("z_extract_offset = 0x%lx\n", offs); - /* z_extract_offset_negative allows simplification of head_32.S */ - printf(".globl z_extract_offset_negative\n"); - printf("z_extract_offset_negative = -0x%lx\n", offs); printf(".globl input_data, input_data_end\n"); printf("input_data:\n"); Index: linux-2.6/arch/x86/boot/Makefile =================================================================== --- linux-2.6.orig/arch/x86/boot/Makefile +++ linux-2.6/arch/x86/boot/Makefile @@ -86,7 +86,7 @@ targets += voffset.h $(obj)/voffset.h: vmlinux FORCE $(call if_changed,voffset) -sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p' +sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_rodata\|z_.*\)$$/\#define ZO_\2 0x\1/p' quiet_cmd_zoffset = ZOFFSET $@ cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ Index: linux-2.6/arch/x86/boot/compressed/vmlinux.lds.S =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/vmlinux.lds.S +++ linux-2.6/arch/x86/boot/compressed/vmlinux.lds.S @@ -35,6 +35,7 @@ SECTIONS *(.text.*) _etext = . ; } + . = ALIGN(PAGE_SIZE); /* keep ADDON_ZO_SIZE page aligned */ .rodata : { _rodata = . ; *(.rodata) /* read-only data */ @@ -70,5 +71,6 @@ SECTIONS _epgtable = . ; } #endif + . = ALIGN(PAGE_SIZE); /* keep ADDON_ZO_SIZE page aligned */ _end = .; } Index: linux-2.6/arch/x86/boot/header.S =================================================================== --- linux-2.6.orig/arch/x86/boot/header.S +++ linux-2.6/arch/x86/boot/header.S @@ -440,12 +440,15 @@ setup_data: .quad 0 # 64-bit physical pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr +# don't overlap data area of ZO with VO +#define ADDON_ZO_SIZE (ZO__end - ZO__rodata) + #define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset) #define VO_INIT_SIZE (VO__end - VO__text) #if ZO_INIT_SIZE > VO_INIT_SIZE -#define INIT_SIZE ZO_INIT_SIZE +#define INIT_SIZE (ZO_INIT_SIZE + ADDON_ZO_SIZE) #else -#define INIT_SIZE VO_INIT_SIZE +#define INIT_SIZE (VO_INIT_SIZE + ADDON_ZO_SIZE) #endif init_size: .long INIT_SIZE # kernel initialization size handover_offset: .long 0 # Filled in by build.c