aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2015-09-09 18:39:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-10 16:29:01 -0400
commit2d3862d26e67a59340ba1cf1748196c76c5787de (patch)
treee3b1dd9157a0c745bcd8147cad82bf021a1cec72
parente852d82a5b55b44ce8be89078d0dfbddbeae3211 (diff)
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: [0x807cc00000-0x807f3ea29b] 0x027ea29c: output_len | boot via startup_64 | KASLR using RDTSC... | new output: [0x46fe000000-0x470138cfff] 0x0338d000: output_run_size | decompress: [0x46fe000000-0x47007ea29b] <=== [0x807f2143b4-0x807ff61aee] | | Decompressing Linux... gz... | | uncompression error | | -- System halted the new buffer is at 0x46fe000000ULL, decompressor_gzip is using 0xffffffb901ffffff as out_len. gunzip in lib/zlib_inflate/inflate.c cap that len to 0x01ffffff 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. Fixes: 1431574a1c4 (lib/decompressors: fix "no limit" output buffer length) Signed-off-by: Yinghai Lu <yinghai@kernel.org> Cc: Alexandre Courbot <acourbot@nvidia.com> Cc: Jon Medhurst <tixy@linaro.org> Cc: Stephen Warren <swarren@wwwdotorg.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/arm/boot/compressed/decompress.c2
-rw-r--r--arch/h8300/boot/compressed/misc.c2
-rw-r--r--arch/m32r/boot/compressed/misc.c3
-rw-r--r--arch/mips/boot/compressed/decompress.c4
-rw-r--r--arch/s390/boot/compressed/misc.c2
-rw-r--r--arch/sh/boot/compressed/misc.c2
-rw-r--r--arch/unicore32/boot/compressed/misc.c4
-rw-r--r--arch/x86/boot/compressed/misc.c3
-rw-r--r--lib/decompress_bunzip2.c6
-rw-r--r--lib/decompress_inflate.c31
-rw-r--r--lib/decompress_unlz4.c6
-rw-r--r--lib/decompress_unlzma.c7
-rw-r--r--lib/decompress_unlzo.c13
-rw-r--r--lib/decompress_unxz.c12
14 files changed, 70 insertions, 27 deletions
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
index bd245d34952d..a0765e7ed6c7 100644
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -57,5 +57,5 @@ extern char * strstr(const char * s1, const char *s2);
57 57
58int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) 58int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
59{ 59{
60 return decompress(input, len, NULL, NULL, output, NULL, error); 60 return __decompress(input, len, NULL, NULL, output, 0, NULL, error);
61} 61}
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
index 704274127c07..c4f2cfcb117b 100644
--- a/arch/h8300/boot/compressed/misc.c
+++ b/arch/h8300/boot/compressed/misc.c
@@ -70,5 +70,5 @@ void decompress_kernel(void)
70 free_mem_ptr = (unsigned long)&_end; 70 free_mem_ptr = (unsigned long)&_end;
71 free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; 71 free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
72 72
73 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 73 __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
74} 74}
diff --git a/arch/m32r/boot/compressed/misc.c b/arch/m32r/boot/compressed/misc.c
index 28a09529f206..3a7692745868 100644
--- a/arch/m32r/boot/compressed/misc.c
+++ b/arch/m32r/boot/compressed/misc.c
@@ -86,6 +86,7 @@ decompress_kernel(int mmu_on, unsigned char *zimage_data,
86 free_mem_end_ptr = free_mem_ptr + BOOT_HEAP_SIZE; 86 free_mem_end_ptr = free_mem_ptr + BOOT_HEAP_SIZE;
87 87
88 puts("\nDecompressing Linux... "); 88 puts("\nDecompressing Linux... ");
89 decompress(input_data, input_len, NULL, NULL, output_data, NULL, error); 89 __decompress(input_data, input_len, NULL, NULL, output_data, 0,
90 NULL, error);
90 puts("done.\nBooting the kernel.\n"); 91 puts("done.\nBooting the kernel.\n");
91} 92}
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
index 54831069a206..080cd53bac36 100644
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -111,8 +111,8 @@ void decompress_kernel(unsigned long boot_heap_start)
111 puts("\n"); 111 puts("\n");
112 112
113 /* Decompress the kernel with according algorithm */ 113 /* Decompress the kernel with according algorithm */
114 decompress((char *)zimage_start, zimage_size, 0, 0, 114 __decompress((char *)zimage_start, zimage_size, 0, 0,
115 (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error); 115 (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, 0, error);
116 116
117 /* FIXME: should we flush cache here? */ 117 /* FIXME: should we flush cache here? */
118 puts("Now, booting the kernel...\n"); 118 puts("Now, booting the kernel...\n");
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c
index 42506b371b74..4da604ebf6fd 100644
--- a/arch/s390/boot/compressed/misc.c
+++ b/arch/s390/boot/compressed/misc.c
@@ -167,7 +167,7 @@ unsigned long decompress_kernel(void)
167#endif 167#endif
168 168
169 puts("Uncompressing Linux... "); 169 puts("Uncompressing Linux... ");
170 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 170 __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
171 puts("Ok, booting the kernel.\n"); 171 puts("Ok, booting the kernel.\n");
172 return (unsigned long) output; 172 return (unsigned long) output;
173} 173}
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index 95470a472d2c..208a9753ab38 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -132,7 +132,7 @@ void decompress_kernel(void)
132 132
133 puts("Uncompressing Linux... "); 133 puts("Uncompressing Linux... ");
134 cache_control(CACHE_ENABLE); 134 cache_control(CACHE_ENABLE);
135 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 135 __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
136 cache_control(CACHE_DISABLE); 136 cache_control(CACHE_DISABLE);
137 puts("Ok, booting the kernel.\n"); 137 puts("Ok, booting the kernel.\n");
138} 138}
diff --git a/arch/unicore32/boot/compressed/misc.c b/arch/unicore32/boot/compressed/misc.c
index 176d5bda3559..5c65dfee278c 100644
--- a/arch/unicore32/boot/compressed/misc.c
+++ b/arch/unicore32/boot/compressed/misc.c
@@ -119,8 +119,8 @@ unsigned long decompress_kernel(unsigned long output_start,
119 output_ptr = get_unaligned_le32(tmp); 119 output_ptr = get_unaligned_le32(tmp);
120 120
121 arch_decomp_puts("Uncompressing Linux..."); 121 arch_decomp_puts("Uncompressing Linux...");
122 decompress(input_data, input_data_end - input_data, NULL, NULL, 122 __decompress(input_data, input_data_end - input_data, NULL, NULL,
123 output_data, NULL, error); 123 output_data, 0, NULL, error);
124 arch_decomp_puts(" done, booting the kernel.\n"); 124 arch_decomp_puts(" done, booting the kernel.\n");
125 return output_ptr; 125 return output_ptr;
126} 126}
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index f63797942bb5..79dac1758e7c 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -448,7 +448,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
448#endif 448#endif
449 449
450 debug_putstr("\nDecompressing Linux... "); 450 debug_putstr("\nDecompressing Linux... ");
451 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 451 __decompress(input_data, input_len, NULL, NULL, output, output_len,
452 NULL, error);
452 parse_elf(output); 453 parse_elf(output);
453 /* 454 /*
454 * 32-bit always performs relocations. 64-bit relocations are only 455 * 32-bit always performs relocations. 64-bit relocations are only
diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c
index 6dd0335ea61b..0234361b24b8 100644
--- a/lib/decompress_bunzip2.c
+++ b/lib/decompress_bunzip2.c
@@ -743,12 +743,12 @@ exit_0:
743} 743}
744 744
745#ifdef PREBOOT 745#ifdef PREBOOT
746STATIC int INIT decompress(unsigned char *buf, long len, 746STATIC int INIT __decompress(unsigned char *buf, long len,
747 long (*fill)(void*, unsigned long), 747 long (*fill)(void*, unsigned long),
748 long (*flush)(void*, unsigned long), 748 long (*flush)(void*, unsigned long),
749 unsigned char *outbuf, 749 unsigned char *outbuf, long olen,
750 long *pos, 750 long *pos,
751 void(*error)(char *x)) 751 void (*error)(char *x))
752{ 752{
753 return bunzip2(buf, len - 4, fill, flush, outbuf, pos, error); 753 return bunzip2(buf, len - 4, fill, flush, outbuf, pos, error);
754} 754}
diff --git a/lib/decompress_inflate.c b/lib/decompress_inflate.c
index d4c7891635ec..555c06bf20da 100644
--- a/lib/decompress_inflate.c
+++ b/lib/decompress_inflate.c
@@ -1,4 +1,5 @@
1#ifdef STATIC 1#ifdef STATIC
2#define PREBOOT
2/* Pre-boot environment: included */ 3/* Pre-boot environment: included */
3 4
4/* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots 5/* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
@@ -33,23 +34,23 @@ static long INIT nofill(void *buffer, unsigned long len)
33} 34}
34 35
35/* Included from initramfs et al code */ 36/* Included from initramfs et al code */
36STATIC int INIT gunzip(unsigned char *buf, long len, 37STATIC int INIT __gunzip(unsigned char *buf, long len,
37 long (*fill)(void*, unsigned long), 38 long (*fill)(void*, unsigned long),
38 long (*flush)(void*, unsigned long), 39 long (*flush)(void*, unsigned long),
39 unsigned char *out_buf, 40 unsigned char *out_buf, long out_len,
40 long *pos, 41 long *pos,
41 void(*error)(char *x)) { 42 void(*error)(char *x)) {
42 u8 *zbuf; 43 u8 *zbuf;
43 struct z_stream_s *strm; 44 struct z_stream_s *strm;
44 int rc; 45 int rc;
45 size_t out_len;
46 46
47 rc = -1; 47 rc = -1;
48 if (flush) { 48 if (flush) {
49 out_len = 0x8000; /* 32 K */ 49 out_len = 0x8000; /* 32 K */
50 out_buf = malloc(out_len); 50 out_buf = malloc(out_len);
51 } else { 51 } else {
52 out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */ 52 if (!out_len)
53 out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */
53 } 54 }
54 if (!out_buf) { 55 if (!out_buf) {
55 error("Out of memory while allocating output buffer"); 56 error("Out of memory while allocating output buffer");
@@ -181,4 +182,24 @@ gunzip_nomem1:
181 return rc; /* returns Z_OK (0) if successful */ 182 return rc; /* returns Z_OK (0) if successful */
182} 183}
183 184
184#define decompress gunzip 185#ifndef PREBOOT
186STATIC int INIT gunzip(unsigned char *buf, long len,
187 long (*fill)(void*, unsigned long),
188 long (*flush)(void*, unsigned long),
189 unsigned char *out_buf,
190 long *pos,
191 void (*error)(char *x))
192{
193 return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error);
194}
195#else
196STATIC int INIT __decompress(unsigned char *buf, long len,
197 long (*fill)(void*, unsigned long),
198 long (*flush)(void*, unsigned long),
199 unsigned char *out_buf, long out_len,
200 long *pos,
201 void (*error)(char *x))
202{
203 return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error);
204}
205#endif
diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c
index 40f66ebe57b7..036fc882cd72 100644
--- a/lib/decompress_unlz4.c
+++ b/lib/decompress_unlz4.c
@@ -196,12 +196,12 @@ exit_0:
196} 196}
197 197
198#ifdef PREBOOT 198#ifdef PREBOOT
199STATIC int INIT decompress(unsigned char *buf, long in_len, 199STATIC int INIT __decompress(unsigned char *buf, long in_len,
200 long (*fill)(void*, unsigned long), 200 long (*fill)(void*, unsigned long),
201 long (*flush)(void*, unsigned long), 201 long (*flush)(void*, unsigned long),
202 unsigned char *output, 202 unsigned char *output, long out_len,
203 long *posp, 203 long *posp,
204 void(*error)(char *x) 204 void (*error)(char *x)
205 ) 205 )
206{ 206{
207 return unlz4(buf, in_len - 4, fill, flush, output, posp, error); 207 return unlz4(buf, in_len - 4, fill, flush, output, posp, error);
diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c
index 0be83af62b88..decb64629c14 100644
--- a/lib/decompress_unlzma.c
+++ b/lib/decompress_unlzma.c
@@ -667,13 +667,12 @@ exit_0:
667} 667}
668 668
669#ifdef PREBOOT 669#ifdef PREBOOT
670STATIC int INIT decompress(unsigned char *buf, long in_len, 670STATIC int INIT __decompress(unsigned char *buf, long in_len,
671 long (*fill)(void*, unsigned long), 671 long (*fill)(void*, unsigned long),
672 long (*flush)(void*, unsigned long), 672 long (*flush)(void*, unsigned long),
673 unsigned char *output, 673 unsigned char *output, long out_len,
674 long *posp, 674 long *posp,
675 void(*error)(char *x) 675 void (*error)(char *x))
676 )
677{ 676{
678 return unlzma(buf, in_len - 4, fill, flush, output, posp, error); 677 return unlzma(buf, in_len - 4, fill, flush, output, posp, error);
679} 678}
diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c
index b94a31bdd87d..f4c158e3a022 100644
--- a/lib/decompress_unlzo.c
+++ b/lib/decompress_unlzo.c
@@ -31,6 +31,7 @@
31 */ 31 */
32 32
33#ifdef STATIC 33#ifdef STATIC
34#define PREBOOT
34#include "lzo/lzo1x_decompress_safe.c" 35#include "lzo/lzo1x_decompress_safe.c"
35#else 36#else
36#include <linux/decompress/unlzo.h> 37#include <linux/decompress/unlzo.h>
@@ -287,4 +288,14 @@ exit:
287 return ret; 288 return ret;
288} 289}
289 290
290#define decompress unlzo 291#ifdef PREBOOT
292STATIC int INIT __decompress(unsigned char *buf, long len,
293 long (*fill)(void*, unsigned long),
294 long (*flush)(void*, unsigned long),
295 unsigned char *out_buf, long olen,
296 long *pos,
297 void (*error)(char *x))
298{
299 return unlzo(buf, len, fill, flush, out_buf, pos, error);
300}
301#endif
diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c
index b07a78340e9d..25d59a95bd66 100644
--- a/lib/decompress_unxz.c
+++ b/lib/decompress_unxz.c
@@ -394,4 +394,14 @@ error_alloc_state:
394 * This macro is used by architecture-specific files to decompress 394 * This macro is used by architecture-specific files to decompress
395 * the kernel image. 395 * the kernel image.
396 */ 396 */
397#define decompress unxz 397#ifdef XZ_PREBOOT
398STATIC int INIT __decompress(unsigned char *buf, long len,
399 long (*fill)(void*, unsigned long),
400 long (*flush)(void*, unsigned long),
401 unsigned char *out_buf, long olen,
402 long *pos,
403 void (*error)(char *x))
404{
405 return unxz(buf, len, fill, flush, out_buf, pos, error);
406}
407#endif