diff options
| author | Lasse Collin <lasse.collin@tukaani.org> | 2011-01-12 20:01:21 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:24 -0500 |
| commit | fb7fa589fd3ecc212fabd7867a4ecc3b175260c1 (patch) | |
| tree | 785e193aaaf9537136140084f8cf2f5ea0d1fb9f | |
| parent | 5a3f81a7029daff5f08aad146f4c4510e790da49 (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>
| -rw-r--r-- | lib/decompress_unlzo.c | 60 |
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 | ||
