[PATCH v2] lib/decompressors: Use real out buf size for gunzip with kernel
When loading x86 64bit kernel above 4GiB with patched grub2, got kernel gunzip error. | early console in decompress_kernel | decompress_kernel: | input: [0x807f2143b4-0x807ff61aee] | output: [0x807cc0-0x807f3ea29b] 0x027ea29c: output_len | boot via startup_64 | KASLR using RDTSC... | new output: [0x46fe00-0x470138cfff] 0x0338d000: output_run_size | decompress: [0x46fe00-0x47007ea29b] <=== [0x807f2143b4-0x807ff61aee] | | Decompressing Linux... gz... | | uncompression error | | -- System halted the new buffer is at 0x46fe00ULL, decompressor_gzip is using 0xffb901ff as out_len. gunzip in lib/zlib_inflate/inflate.c cap that len to 0x01ff and decompress fails later. We could hit this problem with crashkernel booting that uses kexec loading kernel above 4GiB. We have decompress_* support: 1. inbuf[]/outbuf[] for kernel preboot. 2. inbuf[]/flush() for initramfs 3. fill()/flush() for initrd. This bug only affect kernel preboot path that use outbuf[]. Add __decompress and take real out_buf_len for gunzip instead of guessing wrong buf size. -v2: fix unused warning on sh/arm/m32r from Fengguang. Signed-off-by: Yinghai Lu Fixes: 1431574a1c4 (lib/decompressors: fix "no limit" output buffer length) Cc: Alexandre Courbot Cc: Jon Medhurst Cc: Stephen Warren Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Russell King Cc: Yoshinori Sato Cc: Ralf Baechle Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Guan Xuetao Cc: linux-arm-ker...@lists.infradead.org Cc: uclinux-h8-de...@lists.sourceforge.jp Cc: linux-m...@linux-mips.org Cc: linux-s...@vger.kernel.org Cc: linux...@vger.kernel.org Cc: Fengguang Wu Cc: stable --- arch/arm/boot/compressed/decompress.c |2 +- arch/h8300/boot/compressed/misc.c |2 +- arch/m32r/boot/compressed/misc.c |3 ++- arch/mips/boot/compressed/decompress.c |4 ++-- arch/s390/boot/compressed/misc.c |2 +- arch/sh/boot/compressed/misc.c |2 +- arch/unicore32/boot/compressed/misc.c |4 ++-- arch/x86/boot/compressed/misc.c|3 ++- lib/decompress_bunzip2.c |6 +++--- lib/decompress_inflate.c | 31 ++- lib/decompress_unlz4.c |6 +++--- lib/decompress_unlzma.c|7 +++ lib/decompress_unlzo.c | 13 - lib/decompress_unxz.c | 12 +++- 14 files changed, 70 insertions(+), 27 deletions(-) Index: linux-2.6/arch/arm/boot/compressed/decompress.c === --- linux-2.6.orig/arch/arm/boot/compressed/decompress.c +++ linux-2.6/arch/arm/boot/compressed/decompress.c @@ -57,5 +57,5 @@ extern char * strstr(const char * s1, co int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { - return decompress(input, len, NULL, NULL, output, NULL, error); + return __decompress(input, len, NULL, NULL, output, 0, NULL, error); } Index: linux-2.6/arch/h8300/boot/compressed/misc.c === --- linux-2.6.orig/arch/h8300/boot/compressed/misc.c +++ linux-2.6/arch/h8300/boot/compressed/misc.c @@ -70,5 +70,5 @@ void decompress_kernel(void) free_mem_ptr = (unsigned long)&_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); } Index: linux-2.6/arch/m32r/boot/compressed/misc.c === --- linux-2.6.orig/arch/m32r/boot/compressed/misc.c +++ linux-2.6/arch/m32r/boot/compressed/misc.c @@ -86,6 +86,7 @@ decompress_kernel(int mmu_on, unsigned c free_mem_end_ptr = free_mem_ptr + BOOT_HEAP_SIZE; puts("\nDecompressing Linux... "); - decompress(input_data, input_len, NULL, NULL, output_data, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output_data, 0, + NULL, error); puts("done.\nBooting the kernel.\n"); } Index: linux-2.6/arch/mips/boot/compressed/decompress.c === --- linux-2.6.orig/arch/mips/boot/compressed/decompress.c +++ linux-2.6/arch/mips/boot/compressed/decompress.c @@ -111,8 +111,8 @@ void decompress_kernel(unsigned long boo puts("\n"); /* Decompress the kernel with according algorithm */ - decompress((char *)zimage_start, zimage_size, 0, 0, - (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error); + __decompress((char *)zimage_start, zimage_size, 0, 0, + (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, 0, error); /* FIXME: should we flush cache here? */ puts("Now, booting the kernel...\n"); Index: linux-2.6/arch/s390/boot/compressed/misc.c
[PATCH v2] lib/decompressors: Use real out buf size for gunzip with kernel
When loading x86 64bit kernel above 4GiB with patched grub2, got kernel gunzip error. | early console in decompress_kernel | decompress_kernel: | input: [0x807f2143b4-0x807ff61aee] | output: [0x807cc0-0x807f3ea29b] 0x027ea29c: output_len | boot via startup_64 | KASLR using RDTSC... | new output: [0x46fe00-0x470138cfff] 0x0338d000: output_run_size | decompress: [0x46fe00-0x47007ea29b] === [0x807f2143b4-0x807ff61aee] | | Decompressing Linux... gz... | | uncompression error | | -- System halted the new buffer is at 0x46fe00ULL, decompressor_gzip is using 0xffb901ff as out_len. gunzip in lib/zlib_inflate/inflate.c cap that len to 0x01ff and decompress fails later. We could hit this problem with crashkernel booting that uses kexec loading kernel above 4GiB. We have decompress_* support: 1. inbuf[]/outbuf[] for kernel preboot. 2. inbuf[]/flush() for initramfs 3. fill()/flush() for initrd. This bug only affect kernel preboot path that use outbuf[]. Add __decompress and take real out_buf_len for gunzip instead of guessing wrong buf size. -v2: fix unused warning on sh/arm/m32r from Fengguang. Signed-off-by: Yinghai Lu ying...@kernel.org Fixes: 1431574a1c4 (lib/decompressors: fix no limit output buffer length) Cc: Alexandre Courbot acour...@nvidia.com Cc: Jon Medhurst t...@linaro.org Cc: Stephen Warren swar...@wwwdotorg.org Cc: H. Peter Anvin h...@zytor.com Cc: Thomas Gleixner t...@linutronix.de Cc: Ingo Molnar mi...@redhat.com Cc: Russell King li...@arm.linux.org.uk Cc: Yoshinori Sato ys...@users.sourceforge.jp Cc: Ralf Baechle r...@linux-mips.org Cc: Martin Schwidefsky schwidef...@de.ibm.com Cc: Heiko Carstens heiko.carst...@de.ibm.com Cc: Guan Xuetao g...@mprc.pku.edu.cn Cc: linux-arm-ker...@lists.infradead.org Cc: uclinux-h8-de...@lists.sourceforge.jp Cc: linux-m...@linux-mips.org Cc: linux-s...@vger.kernel.org Cc: linux...@vger.kernel.org Cc: Fengguang Wu fengguang...@intel.com Cc: stable sta...@vger.kernel.org --- arch/arm/boot/compressed/decompress.c |2 +- arch/h8300/boot/compressed/misc.c |2 +- arch/m32r/boot/compressed/misc.c |3 ++- arch/mips/boot/compressed/decompress.c |4 ++-- arch/s390/boot/compressed/misc.c |2 +- arch/sh/boot/compressed/misc.c |2 +- arch/unicore32/boot/compressed/misc.c |4 ++-- arch/x86/boot/compressed/misc.c|3 ++- lib/decompress_bunzip2.c |6 +++--- lib/decompress_inflate.c | 31 ++- lib/decompress_unlz4.c |6 +++--- lib/decompress_unlzma.c|7 +++ lib/decompress_unlzo.c | 13 - lib/decompress_unxz.c | 12 +++- 14 files changed, 70 insertions(+), 27 deletions(-) Index: linux-2.6/arch/arm/boot/compressed/decompress.c === --- linux-2.6.orig/arch/arm/boot/compressed/decompress.c +++ linux-2.6/arch/arm/boot/compressed/decompress.c @@ -57,5 +57,5 @@ extern char * strstr(const char * s1, co int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { - return decompress(input, len, NULL, NULL, output, NULL, error); + return __decompress(input, len, NULL, NULL, output, 0, NULL, error); } Index: linux-2.6/arch/h8300/boot/compressed/misc.c === --- linux-2.6.orig/arch/h8300/boot/compressed/misc.c +++ linux-2.6/arch/h8300/boot/compressed/misc.c @@ -70,5 +70,5 @@ void decompress_kernel(void) free_mem_ptr = (unsigned long)_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); } Index: linux-2.6/arch/m32r/boot/compressed/misc.c === --- linux-2.6.orig/arch/m32r/boot/compressed/misc.c +++ linux-2.6/arch/m32r/boot/compressed/misc.c @@ -86,6 +86,7 @@ decompress_kernel(int mmu_on, unsigned c free_mem_end_ptr = free_mem_ptr + BOOT_HEAP_SIZE; puts(\nDecompressing Linux... ); - decompress(input_data, input_len, NULL, NULL, output_data, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output_data, 0, + NULL, error); puts(done.\nBooting the kernel.\n); } Index: linux-2.6/arch/mips/boot/compressed/decompress.c === --- linux-2.6.orig/arch/mips/boot/compressed/decompress.c +++ linux-2.6/arch/mips/boot/compressed/decompress.c @@ -111,8 +111,8 @@ void decompress_kernel(unsigned long boo puts(\n); /* Decompress the kernel with according algorithm */ - decompress((char *)zimage_start, zimage_size, 0, 0, - (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error); +