diff options
author | Lasse Collin <lasse.collin@tukaani.org> | 2011-01-12 20:01:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:24 -0500 |
commit | 528941ca05734f24a7568c1c082125f2b635c4eb (patch) | |
tree | 1fb14770f7605c09863175787671217408203c26 /lib | |
parent | 278208d9d631524d04152574f87b9b88919ce663 (diff) |
Decompressors: check for write errors in decompress_unlzma.c
The return value of wr->flush() is not checked in write_byte(). This
means that the decompressor won't stop even if the caller doesn't want
more data. This can happen e.g. with corrupt LZMA-compressed initramfs.
Returning the error quickly allows the user to see the error message
quicker.
There is a similar missing check for wr.flush() near the end of unlzma().
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_unlzma.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index 4281aa9cb76c..f30c899241ef 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c | |||
@@ -313,32 +313,38 @@ static inline uint8_t INIT peek_old_byte(struct writer *wr, | |||
313 | 313 | ||
314 | } | 314 | } |
315 | 315 | ||
316 | static inline void INIT write_byte(struct writer *wr, uint8_t byte) | 316 | static inline int INIT write_byte(struct writer *wr, uint8_t byte) |
317 | { | 317 | { |
318 | wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte; | 318 | wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte; |
319 | if (wr->flush && wr->buffer_pos == wr->header->dict_size) { | 319 | if (wr->flush && wr->buffer_pos == wr->header->dict_size) { |
320 | wr->buffer_pos = 0; | 320 | wr->buffer_pos = 0; |
321 | wr->global_pos += wr->header->dict_size; | 321 | wr->global_pos += wr->header->dict_size; |
322 | wr->flush((char *)wr->buffer, wr->header->dict_size); | 322 | if (wr->flush((char *)wr->buffer, wr->header->dict_size) |
323 | != wr->header->dict_size) | ||
324 | return -1; | ||
323 | } | 325 | } |
326 | return 0; | ||
324 | } | 327 | } |
325 | 328 | ||
326 | 329 | ||
327 | static inline void INIT copy_byte(struct writer *wr, uint32_t offs) | 330 | static inline int INIT copy_byte(struct writer *wr, uint32_t offs) |
328 | { | 331 | { |
329 | write_byte(wr, peek_old_byte(wr, offs)); | 332 | return write_byte(wr, peek_old_byte(wr, offs)); |
330 | } | 333 | } |
331 | 334 | ||
332 | static inline void INIT copy_bytes(struct writer *wr, | 335 | static inline int INIT copy_bytes(struct writer *wr, |
333 | uint32_t rep0, int len) | 336 | uint32_t rep0, int len) |
334 | { | 337 | { |
335 | do { | 338 | do { |
336 | copy_byte(wr, rep0); | 339 | if (copy_byte(wr, rep0)) |
340 | return -1; | ||
337 | len--; | 341 | len--; |
338 | } while (len != 0 && wr->buffer_pos < wr->header->dst_size); | 342 | } while (len != 0 && wr->buffer_pos < wr->header->dst_size); |
343 | |||
344 | return len; | ||
339 | } | 345 | } |
340 | 346 | ||
341 | static inline void INIT process_bit0(struct writer *wr, struct rc *rc, | 347 | static inline int INIT process_bit0(struct writer *wr, struct rc *rc, |
342 | struct cstate *cst, uint16_t *p, | 348 | struct cstate *cst, uint16_t *p, |
343 | int pos_state, uint16_t *prob, | 349 | int pos_state, uint16_t *prob, |
344 | int lc, uint32_t literal_pos_mask) { | 350 | int lc, uint32_t literal_pos_mask) { |
@@ -372,16 +378,17 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc, | |||
372 | uint16_t *prob_lit = prob + mi; | 378 | uint16_t *prob_lit = prob + mi; |
373 | rc_get_bit(rc, prob_lit, &mi); | 379 | rc_get_bit(rc, prob_lit, &mi); |
374 | } | 380 | } |
375 | write_byte(wr, mi); | ||
376 | if (cst->state < 4) | 381 | if (cst->state < 4) |
377 | cst->state = 0; | 382 | cst->state = 0; |
378 | else if (cst->state < 10) | 383 | else if (cst->state < 10) |
379 | cst->state -= 3; | 384 | cst->state -= 3; |
380 | else | 385 | else |
381 | cst->state -= 6; | 386 | cst->state -= 6; |
387 | |||
388 | return write_byte(wr, mi); | ||
382 | } | 389 | } |
383 | 390 | ||
384 | static inline void INIT process_bit1(struct writer *wr, struct rc *rc, | 391 | static inline int INIT process_bit1(struct writer *wr, struct rc *rc, |
385 | struct cstate *cst, uint16_t *p, | 392 | struct cstate *cst, uint16_t *p, |
386 | int pos_state, uint16_t *prob) { | 393 | int pos_state, uint16_t *prob) { |
387 | int offset; | 394 | int offset; |
@@ -412,8 +419,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc, | |||
412 | 419 | ||
413 | cst->state = cst->state < LZMA_NUM_LIT_STATES ? | 420 | cst->state = cst->state < LZMA_NUM_LIT_STATES ? |
414 | 9 : 11; | 421 | 9 : 11; |
415 | copy_byte(wr, cst->rep0); | 422 | return copy_byte(wr, cst->rep0); |
416 | return; | ||
417 | } else { | 423 | } else { |
418 | rc_update_bit_1(rc, prob); | 424 | rc_update_bit_1(rc, prob); |
419 | } | 425 | } |
@@ -515,12 +521,12 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc, | |||
515 | } else | 521 | } else |
516 | cst->rep0 = pos_slot; | 522 | cst->rep0 = pos_slot; |
517 | if (++(cst->rep0) == 0) | 523 | if (++(cst->rep0) == 0) |
518 | return; | 524 | return 0; |
519 | } | 525 | } |
520 | 526 | ||
521 | len += LZMA_MATCH_MIN_LEN; | 527 | len += LZMA_MATCH_MIN_LEN; |
522 | 528 | ||
523 | copy_bytes(wr, cst->rep0, len); | 529 | return copy_bytes(wr, cst->rep0, len); |
524 | } | 530 | } |
525 | 531 | ||
526 | 532 | ||
@@ -623,11 +629,17 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, | |||
623 | int pos_state = get_pos(&wr) & pos_state_mask; | 629 | int pos_state = get_pos(&wr) & pos_state_mask; |
624 | uint16_t *prob = p + LZMA_IS_MATCH + | 630 | uint16_t *prob = p + LZMA_IS_MATCH + |
625 | (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state; | 631 | (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state; |
626 | if (rc_is_bit_0(&rc, prob)) | 632 | if (rc_is_bit_0(&rc, prob)) { |
627 | process_bit0(&wr, &rc, &cst, p, pos_state, prob, | 633 | if (process_bit0(&wr, &rc, &cst, p, pos_state, prob, |
628 | lc, literal_pos_mask); | 634 | lc, literal_pos_mask)) { |
629 | else { | 635 | error("LZMA data is corrupt"); |
630 | process_bit1(&wr, &rc, &cst, p, pos_state, prob); | 636 | goto exit_3; |
637 | } | ||
638 | } else { | ||
639 | if (process_bit1(&wr, &rc, &cst, p, pos_state, prob)) { | ||
640 | error("LZMA data is corrupt"); | ||
641 | goto exit_3; | ||
642 | } | ||
631 | if (cst.rep0 == 0) | 643 | if (cst.rep0 == 0) |
632 | break; | 644 | break; |
633 | } | 645 | } |
@@ -637,9 +649,8 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, | |||
637 | 649 | ||
638 | if (posp) | 650 | if (posp) |
639 | *posp = rc.ptr-rc.buffer; | 651 | *posp = rc.ptr-rc.buffer; |
640 | if (wr.flush) | 652 | if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos) |
641 | wr.flush(wr.buffer, wr.buffer_pos); | 653 | ret = 0; |
642 | ret = 0; | ||
643 | exit_3: | 654 | exit_3: |
644 | large_free(p); | 655 | large_free(p); |
645 | exit_2: | 656 | exit_2: |