WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 6/9] Decompressors: check for write errors in unlzma.

To: "xen-devel@xxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 6/9] Decompressors: check for write errors in unlzma.c
From: "Jan Beulich" <JBeulich@xxxxxxxx>
Date: Fri, 11 Nov 2011 11:30:16 +0000
Cc: lasse.collin@xxxxxxxxxxx
Delivery-date: Fri, 11 Nov 2011 03:32:41 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
From: Lasse Collin <lasse.collin@xxxxxxxxxxx>

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@xxxxxxxxxxx>
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

--- a/xen/common/unlzma.c
+++ b/xen/common/unlzma.c
@@ -307,32 +307,38 @@ static inline uint8_t INIT peek_old_byte
 
 }
 
-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(str
                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(str
 
                                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(str
                } 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 *bu
                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 *bu
 
        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:


Attachment: unlzma-check-write-errors.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 6/9] Decompressors: check for write errors in unlzma.c, Jan Beulich <=