aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/unlzma.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2011-11-11 14:33:30 +0100
committerLasse Collin <lasse.collin@tukaani.org>2011-11-11 14:33:30 +0100
commit8e8ca04c7bbee50d35582d4f2748d644ebc47086 (patch)
tree2c2dd0cc72248dde79f4eef986ca210bda3dadee /xen/common/unlzma.c
parentf4b38c6cd882bbc88c6a39a4f5d0fb81818fe107 (diff)
downloadxen-8e8ca04c7bbee50d35582d4f2748d644ebc47086.tar.gz
xen-8e8ca04c7bbee50d35582d4f2748d644ebc47086.tar.bz2
xen-8e8ca04c7bbee50d35582d4f2748d644ebc47086.zip
Decompressors: check for write errors in unlzma.c
From: Lasse Collin <lasse.collin@tukaani.org> 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> Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Keir Fraser <keir@xen.org> Committed-by: Jan Beulich <jbeulich@suse.com>
Diffstat (limited to 'xen/common/unlzma.c')
-rw-r--r--xen/common/unlzma.c53
1 files changed, 32 insertions, 21 deletions
diff --git a/xen/common/unlzma.c b/xen/common/unlzma.c
index 781982b524..6dcd7ba20b 100644
--- a/xen/common/unlzma.c
+++ b/xen/common/unlzma.c
@@ -307,32 +307,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) {
@@ -366,16 +372,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;
@@ -406,8 +413,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);
}
@@ -509,12 +515,12 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
} else
cst->rep0 = pos_slot;
if (++(cst->rep0) == 0)
- return;
+ return 0;
}
len += LZMA_MATCH_MIN_LEN;
- copy_bytes(wr, cst->rep0, len);
+ return copy_bytes(wr, cst->rep0, len);
}
@@ -617,11 +623,17 @@ STATIC int INIT unlzma(unsigned char *buf, unsigned 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;
}
@@ -631,9 +643,8 @@ STATIC int INIT unlzma(unsigned char *buf, unsigned int in_len,
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: