Re: [PATCH 02/42] x86, boot: Move compressed kernel to end of buffer before decompressing

From: Kees Cook
Date: Tue Jul 07 2015 - 17:22:38 EST


On Tue, Jul 7, 2015 at 1:19 PM, Yinghai Lu <yinghai@xxxxxxxxxx> wrote:
> So we can find out ZO position easily during run-time for kasl buffer
> searching.

Can you define VO and ZO for this changelog? I understand "VO" to mean
"uncompressed kernel", and "ZO" to mean "compressed kernel", is that
accurate? Maybe "ZO" should be "compressed kernel blob with
decompression code"? I'm not clear on the elements you're talking
about here.

> Current code is using extract_offset to control copied kernel position, it
> will put the copied kernel in the middle of buffer when kernel run size is
> bigger than decompressed needed buffer size.

Doesn't it unconditionally put the compressed kernel at extract_offset?

> Current layout:
> when init_size is the same as kernel run_size:
> run_size
> 0 extract_offset init_size
> |------------------|------------------------|
> VO text/data VO bss/brk
> input ZO text ZO data

I don't understand this picture. The locations of "VO bss/brk" and
"input ZO text ZO data" don't make sense to me. Are you trying to show
that they are aligned with extract_offset and init_size?

>
> This patch try to:
> move ZO to the end of buffer instead of middle of the buffer.
> When init_size is bigger than kernel run size, will have
>
> 0 run_size init_size
> |--------------------------------|----------|
> VO text/data VO bss/brk
> input ZO text ZO data

Won't run_size always be larger than init_size?

> We already have init_size the buffer size, we can find the end easily
> when copying ZO before decompressing.

Which buffer do you mean?

Another thing I'd like to understand is what problem does this patch
solve? I see that it rearranges things, but why is this useful?

Thanks for working on these!

-Kees

>
> Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
> ---
> arch/x86/boot/compressed/head_32.S | 11 +++++++++--
> arch/x86/boot/compressed/head_64.S | 8 ++++++--
> arch/x86/boot/compressed/mkpiggy.c | 7 ++-----
> arch/x86/boot/compressed/vmlinux.lds.S | 1 +
> arch/x86/boot/header.S | 2 +-
> arch/x86/kernel/asm-offsets.c | 1 +
> arch/x86/kernel/vmlinux.lds.S | 1 +
> 7 files changed, 21 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
> index 8ef964d..0c140f9 100644
> --- a/arch/x86/boot/compressed/head_32.S
> +++ b/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
> @@ -210,8 +212,13 @@ relocated:
> /* push arguments for decompress_kernel: */
> pushl $z_run_size /* size of kernel with .bss and .brk */
> pushl $z_output_len /* decompressed length, end of relocs */
> - 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 */
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index b0c0d16..67dd8d3 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/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
> diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
> index d8222f2..5faad09 100644
> --- a/arch/x86/boot/compressed/mkpiggy.c
> +++ b/arch/x86/boot/compressed/mkpiggy.c
> @@ -83,11 +83,8 @@ int main(int argc, char *argv[])
> printf("z_input_len = %lu\n", ilen);
> printf(".globl z_output_len\n");
> 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 z_min_extract_offset\n");
> + printf("z_min_extract_offset = 0x%lx\n", offs);
> printf(".globl z_run_size\n");
> printf("z_run_size = %lu\n", run_size);
>
> diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
> index 34d047c..e24e0a0 100644
> --- a/arch/x86/boot/compressed/vmlinux.lds.S
> +++ b/arch/x86/boot/compressed/vmlinux.lds.S
> @@ -70,5 +70,6 @@ SECTIONS
> _epgtable = . ;
> }
> #endif
> + . = ALIGN(PAGE_SIZE); /* keep ZO size page aligned */
> _end = .;
> }
> diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
> index 16ef025..9bfab22 100644
> --- a/arch/x86/boot/header.S
> +++ b/arch/x86/boot/header.S
> @@ -440,7 +440,7 @@ setup_data: .quad 0 # 64-bit physical pointer to
>
> pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
>
> -#define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset)
> +#define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_min_extract_offset)
> #define VO_INIT_SIZE (VO__end - VO__text)
> #if ZO_INIT_SIZE > VO_INIT_SIZE
> #define INIT_SIZE ZO_INIT_SIZE
> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
> index 8e3d22a1..d2e00bc 100644
> --- a/arch/x86/kernel/asm-offsets.c
> +++ b/arch/x86/kernel/asm-offsets.c
> @@ -87,6 +87,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);
>
> diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
> index 00bf300..5816920 100644
> --- a/arch/x86/kernel/vmlinux.lds.S
> +++ b/arch/x86/kernel/vmlinux.lds.S
> @@ -325,6 +325,7 @@ SECTIONS
> __brk_limit = .;
> }
>
> + . = ALIGN(PAGE_SIZE); /* keep VO_INIT_SIZE page aligned */
> _end = .;
>
> STABS_DEBUG
> --
> 1.8.4.5
>



--
Kees Cook
Chrome OS Security
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/