Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 1:00 AM, Borislav Petkov wrote: > Final patch: > > --- > From: Yinghai Lu > Date: Sat, 7 Mar 2015 14:07:16 -0800 > Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer > > Boris found that passing KASLR status through setup_data from the boot > stage cannot be used later in the kernel stage, see commit > > f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") > > Here's some background: > > The boot loader allocates a buffer of size init_size in concordance with > the value passed in the setup header and it loads the compressed, i.e. > first kernel (arch/x86/boot/compressed/vmlinux) in it. > > First kernel then moves itself somewhere around the middle of the > buffer at z_extract_offset to make sure that the decompressor does not > overwrite input data. > > After the decompressor is finished, kernel proper (vmlinux) uses the > whole buffer from the beginning and the compressed kernel's code and > data section is overlapped with the kernel proper's bss section. > > Later on, clear_bss() in kernel proper clears .bss before code in > arch/x86/kernel/setup.c can access setup_data passed in the first, > compressed kernel. > > To make sure that data survives, we should avoid the overlapping. > > As a first step, move the first kernel closer to the end of the buffer > instead of the middle. As a result, this will place first kernel's data > area out of kernel proper's .bss area. > > This way we can find out where the data section of the copied first > kernel is instead of guessing. In addition, it will make the KASLR > mem_avoid array preparation for the search of a fitting buffer much > simpler. > > While at it, rename z_extract_offset to z_min_extract_offset as it is > actually the minimum extract offset now. > > In order to keep the final extract offset page-aligned we need to > make both kernels' _end markers page-aligned too so that init_size is > page-aligned as a result. > > Signed-off-by: Yinghai Lu > Cc: "H. Peter Anvin" > Cc: Matt Fleming > Cc: Kees Cook > Cc: Thomas Gleixner > Cc: Jiri Kosina > Cc: linux-...@vger.kernel.org > Cc: Ingo Molnar > Cc: Baoquan He > Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") > Link: > http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org > [ Commit message massively rewritten ] Acked-by: Kees Cook Thanks! -Kees > Signed-off-by: > --- > 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 cbed1407a5cd..a9b56f1d8e75 100644 > --- a/arch/x86/boot/compressed/head_32.S > +++ b/arch/x86/boot/compressed/head_32.S > @@ -147,7 +147,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* Set up the stack */ > lealboot_stack_end(%ebx), %esp > @@ -208,8 +210,13 @@ relocated: > */ > /* push arguments for decompress_kernel: */ > pushl $z_output_len /* decompressed length */ > - lealz_extract_offset_negative(%ebx), %ebp > + > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + movl%ebx, %ebp > + subl%eax, %ebp > pushl %ebp/* output address */ > + > pushl $z_input_len/* input_len */ > lealinput_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 2884e0c3e8a5..69015b576cf6 100644 > --- a/arch/x86/boot/compressed/head_64.S > +++ b/arch/x86/boot/compressed/head_64.S > @@ -101,7 +101,9 @@ ENTRY(startup_32) > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* > * Prepare for entering 64 bit mode > @@ -329,7 +331,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - leaqz_extract_offset(%rbp), %rbx > + movlBP_init_size(%rsi), %ebx > + subl$_end, %ebx > + addq%rbp, %rbx > > /* Set up the stack */ > leaqboot_stack_end(%rbx), %rsp > diff --git a/arch/x86/boot/compressed/mkpiggy.c > b/arch/x86/boot/compressed/mkpiggy.c > index b669ab65bf6c..c03b0097ce58 100644 > ---
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 08:11:03AM -0700, Yinghai Lu wrote: > Also stop using "compressed kernel" please, that is confusing. Why? > Just use > > ZO: arch/x86/boot/compressed/vmlinux > VO: vmlinux and this is not confusing? Yeah, right. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 1:00 AM, Borislav Petkov wrote: > Final patch: > > --- > From: Yinghai Lu > Date: Sat, 7 Mar 2015 14:07:16 -0800 > Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer setup should only about arch/x86/boot/setup.ld related. So please keep x86, boot. Also stop using "compressed kernel" please, that is confusing. Just use ZO: arch/x86/boot/compressed/vmlinux VO: vmlinux Thanks Yinghai -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 10:34:31AM +0100, Jiri Kosina wrote: > Thanks a lot for fixing my oversight. Bah, it was my suggestion to use setup_data in the first place, sorry about that. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, 10 Mar 2015, Borislav Petkov wrote: > Final patch: > > --- > From: Yinghai Lu > Date: Sat, 7 Mar 2015 14:07:16 -0800 > Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer [ ... ] > Signed-off-by: Yinghai Lu > Cc: "H. Peter Anvin" > Cc: Matt Fleming > Cc: Kees Cook > Cc: Thomas Gleixner > Cc: Jiri Kosina > Cc: linux-...@vger.kernel.org > Cc: Ingo Molnar > Cc: Baoquan He > Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") Thanks a lot for fixing my oversight. Acked-by: Jiri Kosina > Link: > http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org > [ Commit message massively rewritten ] > Signed-off-by: > --- > 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 cbed1407a5cd..a9b56f1d8e75 100644 > --- a/arch/x86/boot/compressed/head_32.S > +++ b/arch/x86/boot/compressed/head_32.S > @@ -147,7 +147,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* Set up the stack */ > lealboot_stack_end(%ebx), %esp > @@ -208,8 +210,13 @@ relocated: > */ > /* push arguments for decompress_kernel: */ > pushl $z_output_len /* decompressed length */ > - lealz_extract_offset_negative(%ebx), %ebp > + > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + movl%ebx, %ebp > + subl%eax, %ebp > pushl %ebp/* output address */ > + > pushl $z_input_len/* input_len */ > lealinput_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 2884e0c3e8a5..69015b576cf6 100644 > --- a/arch/x86/boot/compressed/head_64.S > +++ b/arch/x86/boot/compressed/head_64.S > @@ -101,7 +101,9 @@ ENTRY(startup_32) > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* > * Prepare for entering 64 bit mode > @@ -329,7 +331,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - leaqz_extract_offset(%rbp), %rbx > + movlBP_init_size(%rsi), %ebx > + subl$_end, %ebx > + addq%rbp, %rbx > > /* Set up the stack */ > leaqboot_stack_end(%rbx), %rsp > diff --git a/arch/x86/boot/compressed/mkpiggy.c > b/arch/x86/boot/compressed/mkpiggy.c > index b669ab65bf6c..c03b0097ce58 100644 > --- a/arch/x86/boot/compressed/mkpiggy.c > +++ b/arch/x86/boot/compressed/mkpiggy.c > @@ -80,11 +80,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 input_data, input_data_end\n"); > printf("input_data:\n"); > diff --git a/arch/x86/boot/compressed/vmlinux.lds.S > b/arch/x86/boot/compressed/vmlinux.lds.S > index 34d047c98284..a80acabb80ec 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 size page-aligned */ > _end = .; > } > diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S > index 16ef02596db2..9bfab22efdf7 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
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
Final patch: --- From: Yinghai Lu Date: Sat, 7 Mar 2015 14:07:16 -0800 Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer Boris found that passing KASLR status through setup_data from the boot stage cannot be used later in the kernel stage, see commit f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") Here's some background: The boot loader allocates a buffer of size init_size in concordance with the value passed in the setup header and it loads the compressed, i.e. first kernel (arch/x86/boot/compressed/vmlinux) in it. First kernel then moves itself somewhere around the middle of the buffer at z_extract_offset to make sure that the decompressor does not overwrite input data. After the decompressor is finished, kernel proper (vmlinux) uses the whole buffer from the beginning and the compressed kernel's code and data section is overlapped with the kernel proper's bss section. Later on, clear_bss() in kernel proper clears .bss before code in arch/x86/kernel/setup.c can access setup_data passed in the first, compressed kernel. To make sure that data survives, we should avoid the overlapping. As a first step, move the first kernel closer to the end of the buffer instead of the middle. As a result, this will place first kernel's data area out of kernel proper's .bss area. This way we can find out where the data section of the copied first kernel is instead of guessing. In addition, it will make the KASLR mem_avoid array preparation for the search of a fitting buffer much simpler. While at it, rename z_extract_offset to z_min_extract_offset as it is actually the minimum extract offset now. In order to keep the final extract offset page-aligned we need to make both kernels' _end markers page-aligned too so that init_size is page-aligned as a result. Signed-off-by: Yinghai Lu Cc: "H. Peter Anvin" Cc: Matt Fleming Cc: Kees Cook Cc: Thomas Gleixner Cc: Jiri Kosina Cc: linux-...@vger.kernel.org Cc: Ingo Molnar Cc: Baoquan He Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") Link: http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org [ Commit message massively rewritten ] Signed-off-by: --- 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 cbed1407a5cd..a9b56f1d8e75 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c3e8a5..69015b576cf6 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab65bf6c..c03b0097ce58 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,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"); -
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Mon, Mar 09, 2015 at 05:54:01PM -0700, Kees Cook wrote: > On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu wrote: > > Boris found data from boot stage can not be used kernel stage. > > "... be used during kernel stage." > > Also, can you give a specific example of this problem? (Which data, used how?) Yeah, I'm filling stuff in, no worries. It just takes twice as long as I'm decyphering early boot code *and* Yinghai. :-) -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Mon, Mar 09, 2015 at 05:54:01PM -0700, Kees Cook wrote: On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu ying...@kernel.org wrote: Boris found data from boot stage can not be used kernel stage. ... be used during kernel stage. Also, can you give a specific example of this problem? (Which data, used how?) Yeah, I'm filling stuff in, no worries. It just takes twice as long as I'm decyphering early boot code *and* Yinghai. :-) -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, 10 Mar 2015, Borislav Petkov wrote: Final patch: --- From: Yinghai Lu ying...@kernel.org Date: Sat, 7 Mar 2015 14:07:16 -0800 Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer [ ... ] Signed-off-by: Yinghai Lu ying...@kernel.org Cc: H. Peter Anvin h...@zytor.com Cc: Matt Fleming matt.flem...@intel.com Cc: Kees Cook keesc...@chromium.org Cc: Thomas Gleixner t...@linutronix.de Cc: Jiri Kosina jkos...@suse.cz Cc: linux-...@vger.kernel.org Cc: Ingo Molnar mi...@redhat.com Cc: Baoquan He b...@redhat.com Fixes: f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Thanks a lot for fixing my oversight. Acked-by: Jiri Kosina jkos...@suse.cz Link: http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org [ Commit message massively rewritten ] Signed-off-by: --- 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 cbed1407a5cd..a9b56f1d8e75 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c3e8a5..69015b576cf6 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab65bf6c..c03b0097ce58 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,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 input_data, input_data_end\n); printf(input_data:\n); diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 34d047c98284..a80acabb80ec 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 size page-aligned */ _end = .; } diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 16ef02596db2..9bfab22efdf7 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
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 10:34:31AM +0100, Jiri Kosina wrote: Thanks a lot for fixing my oversight. Bah, it was my suggestion to use setup_data in the first place, sorry about that. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 1:00 AM, Borislav Petkov b...@suse.de wrote: Final patch: --- From: Yinghai Lu ying...@kernel.org Date: Sat, 7 Mar 2015 14:07:16 -0800 Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer Boris found that passing KASLR status through setup_data from the boot stage cannot be used later in the kernel stage, see commit f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Here's some background: The boot loader allocates a buffer of size init_size in concordance with the value passed in the setup header and it loads the compressed, i.e. first kernel (arch/x86/boot/compressed/vmlinux) in it. First kernel then moves itself somewhere around the middle of the buffer at z_extract_offset to make sure that the decompressor does not overwrite input data. After the decompressor is finished, kernel proper (vmlinux) uses the whole buffer from the beginning and the compressed kernel's code and data section is overlapped with the kernel proper's bss section. Later on, clear_bss() in kernel proper clears .bss before code in arch/x86/kernel/setup.c can access setup_data passed in the first, compressed kernel. To make sure that data survives, we should avoid the overlapping. As a first step, move the first kernel closer to the end of the buffer instead of the middle. As a result, this will place first kernel's data area out of kernel proper's .bss area. This way we can find out where the data section of the copied first kernel is instead of guessing. In addition, it will make the KASLR mem_avoid array preparation for the search of a fitting buffer much simpler. While at it, rename z_extract_offset to z_min_extract_offset as it is actually the minimum extract offset now. In order to keep the final extract offset page-aligned we need to make both kernels' _end markers page-aligned too so that init_size is page-aligned as a result. Signed-off-by: Yinghai Lu ying...@kernel.org Cc: H. Peter Anvin h...@zytor.com Cc: Matt Fleming matt.flem...@intel.com Cc: Kees Cook keesc...@chromium.org Cc: Thomas Gleixner t...@linutronix.de Cc: Jiri Kosina jkos...@suse.cz Cc: linux-...@vger.kernel.org Cc: Ingo Molnar mi...@redhat.com Cc: Baoquan He b...@redhat.com Fixes: f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Link: http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org [ Commit message massively rewritten ] Acked-by: Kees Cook keesc...@chromium.org Thanks! -Kees Signed-off-by: --- 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 cbed1407a5cd..a9b56f1d8e75 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c3e8a5..69015b576cf6 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 1:00 AM, Borislav Petkov b...@suse.de wrote: Final patch: --- From: Yinghai Lu ying...@kernel.org Date: Sat, 7 Mar 2015 14:07:16 -0800 Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer setup should only about arch/x86/boot/setup.ld related. So please keep x86, boot. Also stop using compressed kernel please, that is confusing. Just use ZO: arch/x86/boot/compressed/vmlinux VO: vmlinux Thanks Yinghai -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Tue, Mar 10, 2015 at 08:11:03AM -0700, Yinghai Lu wrote: Also stop using compressed kernel please, that is confusing. Why? Just use ZO: arch/x86/boot/compressed/vmlinux VO: vmlinux and this is not confusing? Yeah, right. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
Final patch: --- From: Yinghai Lu ying...@kernel.org Date: Sat, 7 Mar 2015 14:07:16 -0800 Subject: [PATCH] x86/setup: Move compressed kernel to the end of the buffer Boris found that passing KASLR status through setup_data from the boot stage cannot be used later in the kernel stage, see commit f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Here's some background: The boot loader allocates a buffer of size init_size in concordance with the value passed in the setup header and it loads the compressed, i.e. first kernel (arch/x86/boot/compressed/vmlinux) in it. First kernel then moves itself somewhere around the middle of the buffer at z_extract_offset to make sure that the decompressor does not overwrite input data. After the decompressor is finished, kernel proper (vmlinux) uses the whole buffer from the beginning and the compressed kernel's code and data section is overlapped with the kernel proper's bss section. Later on, clear_bss() in kernel proper clears .bss before code in arch/x86/kernel/setup.c can access setup_data passed in the first, compressed kernel. To make sure that data survives, we should avoid the overlapping. As a first step, move the first kernel closer to the end of the buffer instead of the middle. As a result, this will place first kernel's data area out of kernel proper's .bss area. This way we can find out where the data section of the copied first kernel is instead of guessing. In addition, it will make the KASLR mem_avoid array preparation for the search of a fitting buffer much simpler. While at it, rename z_extract_offset to z_min_extract_offset as it is actually the minimum extract offset now. In order to keep the final extract offset page-aligned we need to make both kernels' _end markers page-aligned too so that init_size is page-aligned as a result. Signed-off-by: Yinghai Lu ying...@kernel.org Cc: H. Peter Anvin h...@zytor.com Cc: Matt Fleming matt.flem...@intel.com Cc: Kees Cook keesc...@chromium.org Cc: Thomas Gleixner t...@linutronix.de Cc: Jiri Kosina jkos...@suse.cz Cc: linux-...@vger.kernel.org Cc: Ingo Molnar mi...@redhat.com Cc: Baoquan He b...@redhat.com Fixes: f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Link: http://lkml.kernel.org/r/1425766041-6551-3-git-send-email-ying...@kernel.org [ Commit message massively rewritten ] Signed-off-by: --- 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 cbed1407a5cd..a9b56f1d8e75 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c3e8a5..69015b576cf6 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab65bf6c..c03b0097ce58 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,8 @@ int main(int argc, char *argv[]) printf(z_input_len = %lu\n, ilen); printf(.globl
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Mon, Mar 9, 2015 at 5:54 PM, Kees Cook wrote: > On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu wrote: >> Boris found data from boot stage can not be used kernel stage. > > "... be used during kernel stage." > > Also, can you give a specific example of this problem? (Which data, used how?) > >> Bootloader allocate buffer according to init_size in hdr, and load the >> ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. >> During running of ZO, ZO move itself to the middle of buffer at >> z_extract_offset to make sure that decompressor would not have output >> overwrite input data before input data get consumed. >> After decompressor is called, VO (vmlinux) use whole buffer from start, >> and ZO code and data section is overlapped with VO bss section. >> And later VO/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. >> At first move ZO close the end of buffer instead of middle of the buffer, >> that will move out ZO data out of VO bss area. >> >> Also after that we can find out where is data section of copied ZO >> instead of guessing. That will aslr mem_avoid array filling for > > "That will make aslr mem_avoid array ..." > >> new buffer seaching much simple. >> >> And rename z_extract_offset to z_min_extract_offset, as it is >> actually the minimum offset for extracting now. >> >> To keep the final real extract_offset to be page aligned like >> min_extract_offset, we need make VO _end and ZO _end both >> page aligned to make sure init_size always page aligned. >> >> Next patch will add ZO data size to init_size, so it will make sure >> ZO data is even out of VO brk area. > > This seems like a reasonable idea, but I think the changes should be > noted/updated in misc.c since a lot of effort was made to make the > in-memory foot print as small as possible. Yes, that explanation in misc.c is very good about extra bytes, and it should still stand. Also need to make mkpiggy.c to point to it. We need to add more info about in head_32/64.c actually we need move to end of the buffer. > These changes do expand the > size of the loaded kernel, IIUC. If not in this patch, maybe in 5/7? It extend about 256k for init_size. should be 3/7. but that is only for decompress time. Final VO (vmlinux) run size is not changed. Thanks Yinghai -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu wrote: > Boris found data from boot stage can not be used kernel stage. "... be used during kernel stage." Also, can you give a specific example of this problem? (Which data, used how?) > Bootloader allocate buffer according to init_size in hdr, and load the > ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. > During running of ZO, ZO move itself to the middle of buffer at > z_extract_offset to make sure that decompressor would not have output > overwrite input data before input data get consumed. > After decompressor is called, VO (vmlinux) use whole buffer from start, > and ZO code and data section is overlapped with VO bss section. > And later VO/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. > At first move ZO close the end of buffer instead of middle of the buffer, > that will move out ZO data out of VO bss area. > > Also after that we can find out where is data section of copied ZO > instead of guessing. That will aslr mem_avoid array filling for "That will make aslr mem_avoid array ..." > new buffer seaching much simple. > > And rename z_extract_offset to z_min_extract_offset, as it is > actually the minimum offset for extracting now. > > To keep the final real extract_offset to be page aligned like > min_extract_offset, we need make VO _end and ZO _end both > page aligned to make sure init_size always page aligned. > > Next patch will add ZO data size to init_size, so it will make sure > ZO data is even out of VO brk area. This seems like a reasonable idea, but I think the changes should be noted/updated in misc.c since a lot of effort was made to make the in-memory foot print as small as possible. These changes do expand the size of the loaded kernel, IIUC. If not in this patch, maybe in 5/7? -Kees > > Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") > Cc: "H. Peter Anvin" > Cc: Matt Fleming > Cc: Kees Cook > Signed-off-by: Yinghai Lu > --- > 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 cbed140..a9b56f1 100644 > --- a/arch/x86/boot/compressed/head_32.S > +++ b/arch/x86/boot/compressed/head_32.S > @@ -147,7 +147,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* Set up the stack */ > lealboot_stack_end(%ebx), %esp > @@ -208,8 +210,13 @@ relocated: > */ > /* push arguments for decompress_kernel: */ > pushl $z_output_len /* decompressed length */ > - lealz_extract_offset_negative(%ebx), %ebp > + > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + movl%ebx, %ebp > + subl%eax, %ebp > pushl %ebp/* output address */ > + > pushl $z_input_len/* input_len */ > lealinput_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 2884e0c..69015b5 100644 > --- a/arch/x86/boot/compressed/head_64.S > +++ b/arch/x86/boot/compressed/head_64.S > @@ -101,7 +101,9 @@ ENTRY(startup_32) > 1: > > /* Target address to relocate to for decompression */ > - addl$z_extract_offset, %ebx > + movlBP_init_size(%esi), %eax > + subl$_end, %eax > + addl%eax, %ebx > > /* > * Prepare for entering 64 bit mode > @@ -329,7 +331,9 @@ preferred_addr: > 1: > > /* Target address to relocate to for decompression */ > - leaqz_extract_offset(%rbp), %rbx > + movlBP_init_size(%rsi), %ebx > + subl$_end, %ebx > + addq%rbp, %rbx > > /* Set up the stack */ > leaqboot_stack_end(%rbx), %rsp > diff --git a/arch/x86/boot/compressed/mkpiggy.c > b/arch/x86/boot/compressed/mkpiggy.c > index b669ab6..c03b009 100644 > --- a/arch/x86/boot/compressed/mkpiggy.c > +++ b/arch/x86/boot/compressed/mkpiggy.c > @@ -80,11 +80,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); > -
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Mon, Mar 9, 2015 at 5:54 PM, Kees Cook keesc...@chromium.org wrote: On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu ying...@kernel.org wrote: Boris found data from boot stage can not be used kernel stage. ... be used during kernel stage. Also, can you give a specific example of this problem? (Which data, used how?) Bootloader allocate buffer according to init_size in hdr, and load the ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. During running of ZO, ZO move itself to the middle of buffer at z_extract_offset to make sure that decompressor would not have output overwrite input data before input data get consumed. After decompressor is called, VO (vmlinux) use whole buffer from start, and ZO code and data section is overlapped with VO bss section. And later VO/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. At first move ZO close the end of buffer instead of middle of the buffer, that will move out ZO data out of VO bss area. Also after that we can find out where is data section of copied ZO instead of guessing. That will aslr mem_avoid array filling for That will make aslr mem_avoid array ... new buffer seaching much simple. And rename z_extract_offset to z_min_extract_offset, as it is actually the minimum offset for extracting now. To keep the final real extract_offset to be page aligned like min_extract_offset, we need make VO _end and ZO _end both page aligned to make sure init_size always page aligned. Next patch will add ZO data size to init_size, so it will make sure ZO data is even out of VO brk area. This seems like a reasonable idea, but I think the changes should be noted/updated in misc.c since a lot of effort was made to make the in-memory foot print as small as possible. Yes, that explanation in misc.c is very good about extra bytes, and it should still stand. Also need to make mkpiggy.c to point to it. We need to add more info about in head_32/64.c actually we need move to end of the buffer. These changes do expand the size of the loaded kernel, IIUC. If not in this patch, maybe in 5/7? It extend about 256k for init_size. should be 3/7. but that is only for decompress time. Final VO (vmlinux) run size is not changed. Thanks Yinghai -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 2/7] x86, boot: Move ZO to end of buffer
On Sat, Mar 7, 2015 at 2:07 PM, Yinghai Lu ying...@kernel.org wrote: Boris found data from boot stage can not be used kernel stage. ... be used during kernel stage. Also, can you give a specific example of this problem? (Which data, used how?) Bootloader allocate buffer according to init_size in hdr, and load the ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. During running of ZO, ZO move itself to the middle of buffer at z_extract_offset to make sure that decompressor would not have output overwrite input data before input data get consumed. After decompressor is called, VO (vmlinux) use whole buffer from start, and ZO code and data section is overlapped with VO bss section. And later VO/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. At first move ZO close the end of buffer instead of middle of the buffer, that will move out ZO data out of VO bss area. Also after that we can find out where is data section of copied ZO instead of guessing. That will aslr mem_avoid array filling for That will make aslr mem_avoid array ... new buffer seaching much simple. And rename z_extract_offset to z_min_extract_offset, as it is actually the minimum offset for extracting now. To keep the final real extract_offset to be page aligned like min_extract_offset, we need make VO _end and ZO _end both page aligned to make sure init_size always page aligned. Next patch will add ZO data size to init_size, so it will make sure ZO data is even out of VO brk area. This seems like a reasonable idea, but I think the changes should be noted/updated in misc.c since a lot of effort was made to make the in-memory foot print as small as possible. These changes do expand the size of the loaded kernel, IIUC. If not in this patch, maybe in 5/7? -Kees Fixes: f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Cc: H. Peter Anvin h...@zytor.com Cc: Matt Fleming matt.flem...@intel.com Cc: Kees Cook keesc...@chromium.org Signed-off-by: Yinghai Lu ying...@kernel.org --- 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 cbed140..a9b56f1 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c..69015b5 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab6..c03b009 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,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
[PATCH v3 2/7] x86, boot: Move ZO to end of buffer
Boris found data from boot stage can not be used kernel stage. Bootloader allocate buffer according to init_size in hdr, and load the ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. During running of ZO, ZO move itself to the middle of buffer at z_extract_offset to make sure that decompressor would not have output overwrite input data before input data get consumed. After decompressor is called, VO (vmlinux) use whole buffer from start, and ZO code and data section is overlapped with VO bss section. And later VO/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. At first move ZO close the end of buffer instead of middle of the buffer, that will move out ZO data out of VO bss area. Also after that we can find out where is data section of copied ZO instead of guessing. That will aslr mem_avoid array filling for new buffer seaching much simple. And rename z_extract_offset to z_min_extract_offset, as it is actually the minimum offset for extracting now. To keep the final real extract_offset to be page aligned like min_extract_offset, we need make VO _end and ZO _end both page aligned to make sure init_size always page aligned. Next patch will add ZO data size to init_size, so it will make sure ZO data is even out of VO brk area. Fixes: f47233c2d34f ("x86/mm/ASLR: Propagate base load address calculation") Cc: "H. Peter Anvin" Cc: Matt Fleming Cc: Kees Cook Signed-off-by: Yinghai Lu --- 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 cbed140..a9b56f1 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c..69015b5 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab6..c03b009 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,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 input_data, input_data_end\n"); printf("input_data:\n"); 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); /*
[PATCH v3 2/7] x86, boot: Move ZO to end of buffer
Boris found data from boot stage can not be used kernel stage. Bootloader allocate buffer according to init_size in hdr, and load the ZO (arch/x86/boot/compressed/vmlinux) from start of that buffer. During running of ZO, ZO move itself to the middle of buffer at z_extract_offset to make sure that decompressor would not have output overwrite input data before input data get consumed. After decompressor is called, VO (vmlinux) use whole buffer from start, and ZO code and data section is overlapped with VO bss section. And later VO/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. At first move ZO close the end of buffer instead of middle of the buffer, that will move out ZO data out of VO bss area. Also after that we can find out where is data section of copied ZO instead of guessing. That will aslr mem_avoid array filling for new buffer seaching much simple. And rename z_extract_offset to z_min_extract_offset, as it is actually the minimum offset for extracting now. To keep the final real extract_offset to be page aligned like min_extract_offset, we need make VO _end and ZO _end both page aligned to make sure init_size always page aligned. Next patch will add ZO data size to init_size, so it will make sure ZO data is even out of VO brk area. Fixes: f47233c2d34f (x86/mm/ASLR: Propagate base load address calculation) Cc: H. Peter Anvin h...@zytor.com Cc: Matt Fleming matt.flem...@intel.com Cc: Kees Cook keesc...@chromium.org Signed-off-by: Yinghai Lu ying...@kernel.org --- 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 cbed140..a9b56f1 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -147,7 +147,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* Set up the stack */ lealboot_stack_end(%ebx), %esp @@ -208,8 +210,13 @@ relocated: */ /* push arguments for decompress_kernel: */ pushl $z_output_len /* decompressed length */ - lealz_extract_offset_negative(%ebx), %ebp + + movlBP_init_size(%esi), %eax + subl$_end, %eax + movl%ebx, %ebp + subl%eax, %ebp pushl %ebp/* output address */ + pushl $z_input_len/* input_len */ lealinput_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 2884e0c..69015b5 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -101,7 +101,9 @@ ENTRY(startup_32) 1: /* Target address to relocate to for decompression */ - addl$z_extract_offset, %ebx + movlBP_init_size(%esi), %eax + subl$_end, %eax + addl%eax, %ebx /* * Prepare for entering 64 bit mode @@ -329,7 +331,9 @@ preferred_addr: 1: /* Target address to relocate to for decompression */ - leaqz_extract_offset(%rbp), %rbx + movlBP_init_size(%rsi), %ebx + subl$_end, %ebx + addq%rbp, %rbx /* Set up the stack */ leaqboot_stack_end(%rbx), %rsp diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab6..c03b009 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -80,11 +80,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 input_data, input_data_end\n); printf(input_data:\n); 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 = . ;