aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2011-01-12 20:01:21 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 11:03:24 -0500
commitfb7fa589fd3ecc212fabd7867a4ecc3b175260c1 (patch)
tree785e193aaaf9537136140084f8cf2f5ea0d1fb9f /lib
parent5a3f81a7029daff5f08aad146f4c4510e790da49 (diff)
Decompressors: fix callback-to-callback mode in decompress_unlzo.c
Callback-to-callback decompression mode is used for initrd (not initramfs). The LZO wrapper is broken for this use case for two reasons: - The argument validation is needlessly too strict by requiring that "posp" is non-NULL when "fill" is non-NULL. - The buffer handling code didn't work at all for this use case. I tested with LZO-compressed kernel, initramfs, initrd, and corrupt (truncated) initramfs and initrd images. Signed-off-by: Lasse Collin <lasse.collin@tukaani.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Alain Knaff <alain@knaff.lu> Cc: Albin Tonnerre <albin.tonnerre@free-electrons.com> Cc: Phillip Lougher <phillip@lougher.demon.co.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/decompress_unlzo.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c
index 7eb3b80bf022..5a7a2adf4c4c 100644
--- a/lib/decompress_unlzo.c
+++ b/lib/decompress_unlzo.c
@@ -139,8 +139,8 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
139 goto exit_1; 139 goto exit_1;
140 } else if (input) { 140 } else if (input) {
141 in_buf = input; 141 in_buf = input;
142 } else if (!fill || !posp) { 142 } else if (!fill) {
143 error("NULL input pointer and missing position pointer or fill function"); 143 error("NULL input pointer and missing fill function");
144 goto exit_1; 144 goto exit_1;
145 } else { 145 } else {
146 in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE)); 146 in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
@@ -154,21 +154,40 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
154 if (posp) 154 if (posp)
155 *posp = 0; 155 *posp = 0;
156 156
157 if (fill) 157 if (fill) {
158 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE)); 158 /*
159 * Start from in_buf + HEADER_SIZE_MAX to make it possible
160 * to use memcpy() to copy the unused data to the beginning
161 * of the buffer. This way memmove() isn't needed which
162 * is missing from pre-boot environments of most archs.
163 */
164 in_buf += HEADER_SIZE_MAX;
165 in_len = fill(in_buf, HEADER_SIZE_MAX);
166 }
159 167
160 if (!parse_header(input, &skip, in_len)) { 168 if (!parse_header(in_buf, &skip, in_len)) {
161 error("invalid header"); 169 error("invalid header");
162 goto exit_2; 170 goto exit_2;
163 } 171 }
164 in_buf += skip; 172 in_buf += skip;
165 in_len -= skip; 173 in_len -= skip;
166 174
175 if (fill) {
176 /* Move the unused data to the beginning of the buffer. */
177 memcpy(in_buf_save, in_buf, in_len);
178 in_buf = in_buf_save;
179 }
180
167 if (posp) 181 if (posp)
168 *posp = skip; 182 *posp = skip;
169 183
170 for (;;) { 184 for (;;) {
171 /* read uncompressed block size */ 185 /* read uncompressed block size */
186 if (fill && in_len < 4) {
187 skip = fill(in_buf + in_len, 4 - in_len);
188 if (skip > 0)
189 in_len += skip;
190 }
172 if (in_len < 4) { 191 if (in_len < 4) {
173 error("file corrupted"); 192 error("file corrupted");
174 goto exit_2; 193 goto exit_2;
@@ -190,6 +209,11 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
190 } 209 }
191 210
192 /* read compressed block size, and skip block checksum info */ 211 /* read compressed block size, and skip block checksum info */
212 if (fill && in_len < 8) {
213 skip = fill(in_buf + in_len, 8 - in_len);
214 if (skip > 0)
215 in_len += skip;
216 }
193 if (in_len < 8) { 217 if (in_len < 8) {
194 error("file corrupted"); 218 error("file corrupted");
195 goto exit_2; 219 goto exit_2;
@@ -198,12 +222,21 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
198 in_buf += 8; 222 in_buf += 8;
199 in_len -= 8; 223 in_len -= 8;
200 224
201 if (src_len <= 0 || src_len > dst_len || src_len > in_len) { 225 if (src_len <= 0 || src_len > dst_len) {
202 error("file corrupted"); 226 error("file corrupted");
203 goto exit_2; 227 goto exit_2;
204 } 228 }
205 229
206 /* decompress */ 230 /* decompress */
231 if (fill && in_len < src_len) {
232 skip = fill(in_buf + in_len, src_len - in_len);
233 if (skip > 0)
234 in_len += skip;
235 }
236 if (in_len < src_len) {
237 error("file corrupted");
238 goto exit_2;
239 }
207 tmp = dst_len; 240 tmp = dst_len;
208 241
209 /* When the input data is not compressed at all, 242 /* When the input data is not compressed at all,
@@ -227,12 +260,19 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
227 out_buf += dst_len; 260 out_buf += dst_len;
228 if (posp) 261 if (posp)
229 *posp += src_len + 12; 262 *posp += src_len + 12;
263
264 in_buf += src_len;
265 in_len -= src_len;
230 if (fill) { 266 if (fill) {
267 /*
268 * If there happens to still be unused data left in
269 * in_buf, move it to the beginning of the buffer.
270 * Use a loop to avoid memmove() dependency.
271 */
272 if (in_len > 0)
273 for (skip = 0; skip < in_len; ++skip)
274 in_buf_save[skip] = in_buf[skip];
231 in_buf = in_buf_save; 275 in_buf = in_buf_save;
232 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
233 } else {
234 in_buf += src_len;
235 in_len -= src_len;
236 } 276 }
237 } 277 }
238 278