aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2011-01-12 20:01:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 11:03:24 -0500
commit528941ca05734f24a7568c1c082125f2b635c4eb (patch)
tree1fb14770f7605c09863175787671217408203c26 /lib
parent278208d9d631524d04152574f87b9b88919ce663 (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.c53
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
316static inline void INIT write_byte(struct writer *wr, uint8_t byte) 316static 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
327static inline void INIT copy_byte(struct writer *wr, uint32_t offs) 330static 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
332static inline void INIT copy_bytes(struct writer *wr, 335static 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
341static inline void INIT process_bit0(struct writer *wr, struct rc *rc, 347static 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
384static inline void INIT process_bit1(struct writer *wr, struct rc *rc, 391static 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;
643exit_3: 654exit_3:
644 large_free(p); 655 large_free(p);
645exit_2: 656exit_2: