diff options
Diffstat (limited to 'lib/decompress_unlzma.c')
-rw-r--r-- | lib/decompress_unlzma.c | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index ca82fde81c8f..476c65af9709 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -33,7 +33,6 @@ #define PREBOOT #else #include <linux/decompress/unlzma.h> -#include <linux/slab.h> #endif /* STATIC */ #include <linux/decompress/mm.h> @@ -74,6 +73,7 @@ struct rc { uint32_t code; uint32_t range; uint32_t bound; + void (*error)(char *); }; @@ -82,7 +82,7 @@ struct rc { #define RC_MODEL_TOTAL_BITS 11 -static int nofill(void *buffer, unsigned int len) +static int INIT nofill(void *buffer, unsigned int len) { return -1; } @@ -92,7 +92,7 @@ static void INIT rc_read(struct rc *rc) { rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE); if (rc->buffer_size <= 0) - error("unexpected EOF"); + rc->error("unexpected EOF"); rc->ptr = rc->buffer; rc->buffer_end = rc->buffer + rc->buffer_size; } @@ -127,12 +127,6 @@ static inline void INIT rc_init_code(struct rc *rc) } -/* Called once. TODO: bb_maybe_free() */ -static inline void INIT rc_free(struct rc *rc) -{ - free(rc->buffer); -} - /* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */ static void INIT rc_do_normalize(struct rc *rc) { @@ -169,7 +163,7 @@ static inline void INIT rc_update_bit_0(struct rc *rc, uint16_t *p) rc->range = rc->bound; *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; } -static inline void rc_update_bit_1(struct rc *rc, uint16_t *p) +static inline void INIT rc_update_bit_1(struct rc *rc, uint16_t *p) { rc->range -= rc->bound; rc->code -= rc->bound; @@ -319,32 +313,38 @@ static inline uint8_t INIT peek_old_byte(struct writer *wr, } -static inline void INIT write_byte(struct writer *wr, uint8_t byte) +static inline int INIT write_byte(struct writer *wr, uint8_t byte) { wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte; if (wr->flush && wr->buffer_pos == wr->header->dict_size) { wr->buffer_pos = 0; wr->global_pos += wr->header->dict_size; - wr->flush((char *)wr->buffer, wr->header->dict_size); + if (wr->flush((char *)wr->buffer, wr->header->dict_size) + != wr->header->dict_size) + return -1; } + return 0; } -static inline void INIT copy_byte(struct writer *wr, uint32_t offs) +static inline int INIT copy_byte(struct writer *wr, uint32_t offs) { - write_byte(wr, peek_old_byte(wr, offs)); + return write_byte(wr, peek_old_byte(wr, offs)); } -static inline void INIT copy_bytes(struct writer *wr, +static inline int INIT copy_bytes(struct writer *wr, uint32_t rep0, int len) { do { - copy_byte(wr, rep0); + if (copy_byte(wr, rep0)) + return -1; len--; } while (len != 0 && wr->buffer_pos < wr->header->dst_size); + + return len; } -static inline void INIT process_bit0(struct writer *wr, struct rc *rc, +static inline int INIT process_bit0(struct writer *wr, struct rc *rc, struct cstate *cst, uint16_t *p, int pos_state, uint16_t *prob, int lc, uint32_t literal_pos_mask) { @@ -378,16 +378,17 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc, uint16_t *prob_lit = prob + mi; rc_get_bit(rc, prob_lit, &mi); } - write_byte(wr, mi); if (cst->state < 4) cst->state = 0; else if (cst->state < 10) cst->state -= 3; else cst->state -= 6; + + return write_byte(wr, mi); } -static inline void INIT process_bit1(struct writer *wr, struct rc *rc, +static inline int INIT process_bit1(struct writer *wr, struct rc *rc, struct cstate *cst, uint16_t *p, int pos_state, uint16_t *prob) { int offset; @@ -418,8 +419,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc, cst->state = cst->state < LZMA_NUM_LIT_STATES ? 9 : 11; - copy_byte(wr, cst->rep0); - return; + return copy_byte(wr, cst->rep0); } else { rc_update_bit_1(rc, prob); } @@ -521,12 +521,15 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc, } else cst->rep0 = pos_slot; if (++(cst->rep0) == 0) - return; + return 0; + if (cst->rep0 > wr->header->dict_size + || cst->rep0 > get_pos(wr)) + return -1; } len += LZMA_MATCH_MIN_LEN; - copy_bytes(wr, cst->rep0, len); + return copy_bytes(wr, cst->rep0, len); } @@ -536,7 +539,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, int(*flush)(void*, unsigned int), unsigned char *output, int *posp, - void(*error_fn)(char *x) + void(*error)(char *x) ) { struct lzma_header header; @@ -552,7 +555,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, unsigned char *inbuf; int ret = -1; - set_error_fn(error_fn); + rc.error = error; if (buf) inbuf = buf; @@ -580,8 +583,10 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, ((unsigned char *)&header)[i] = *rc.ptr++; } - if (header.pos >= (9 * 5 * 5)) + if (header.pos >= (9 * 5 * 5)) { error("bad header"); + goto exit_1; + } mi = 0; lc = header.pos; @@ -627,21 +632,29 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len, int pos_state = get_pos(&wr) & pos_state_mask; uint16_t *prob = p + LZMA_IS_MATCH + (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state; - if (rc_is_bit_0(&rc, prob)) - process_bit0(&wr, &rc, &cst, p, pos_state, prob, - lc, literal_pos_mask); - else { - process_bit1(&wr, &rc, &cst, p, pos_state, prob); + if (rc_is_bit_0(&rc, prob)) { + if (process_bit0(&wr, &rc, &cst, p, pos_state, prob, + lc, literal_pos_mask)) { + error("LZMA data is corrupt"); + goto exit_3; + } + } else { + if (process_bit1(&wr, &rc, &cst, p, pos_state, prob)) { + error("LZMA data is corrupt"); + goto exit_3; + } if (cst.rep0 == 0) break; } + if (rc.buffer_size <= 0) + goto exit_3; } if (posp) *posp = rc.ptr-rc.buffer; - if (wr.flush) - wr.flush(wr.buffer, wr.buffer_pos); - ret = 0; + if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos) + ret = 0; +exit_3: large_free(p); exit_2: if (!output) @@ -659,9 +672,9 @@ STATIC int INIT decompress(unsigned char *buf, int in_len, int(*flush)(void*, unsigned int), unsigned char *output, int *posp, - void(*error_fn)(char *x) + void(*error)(char *x) ) { - return unlzma(buf, in_len - 4, fill, flush, output, posp, error_fn); + return unlzma(buf, in_len - 4, fill, flush, output, posp, error); } #endif |