[PATCH v2] lib/decompressors: Use real out buf size for gunzip with kernel

2015-08-13 Thread Yinghai Lu
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

2015-08-13 Thread Yinghai Lu
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);
+