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 9/9] Decompressors: check input size in unlzo.c

To: "xen-devel@xxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 9/9] Decompressors: check input size in unlzo.c
From: "Jan Beulich" <JBeulich@xxxxxxxx>
Date: Fri, 11 Nov 2011 11:32:18 +0000
Cc: lasse.collin@xxxxxxxxxxx
Delivery-date: Fri, 11 Nov 2011 03:36:04 -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 code assumes that the input is valid and not truncated.  Add checks to
avoid reading past the end of the input buffer.  Change the type of "skip"
from u8 to int to fix a possible integer overflow.

Signed-off-by: Lasse Collin <lasse.collin@xxxxxxxxxxx>
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

--- a/xen/common/unlzo.c
+++ b/xen/common/unlzo.c
@@ -63,14 +63,25 @@ static const unsigned char lzop_magic[] 
 
 #define LZO_BLOCK_SIZE        (256*1024l)
 #define HEADER_HAS_FILTER      0x00000800L
+#define HEADER_SIZE_MIN       (9 + 7     + 4 + 8     + 1       + 4)
+#define HEADER_SIZE_MAX       (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4)
 
-static int INIT parse_header(u8 *input, u8 *skip)
+static int INIT parse_header(u8 *input, int *skip, int in_len)
 {
        int l;
        u8 *parse = input;
+       u8 *end = input + in_len;
        u8 level = 0;
        u16 version;
 
+       /*
+        * Check that there's enough input to possibly have a valid header.
+        * Then it is possible to parse several fields until the minimum
+        * size may have been used.
+        */
+       if (in_len < HEADER_SIZE_MIN)
+               return 0;
+
        /* read magic: 9 first bits */
        for (l = 0; l < 9; l++) {
                if (*parse++ != lzop_magic[l])
@@ -88,6 +99,15 @@ static int INIT parse_header(u8 *input, 
        else
                parse += 4; /* flags */
 
+       /*
+        * At least mode, mtime_low, filename length, and checksum must
+        * be left to be parsed. If also mtime_high is present, it's OK
+        * because the next input buffer check is after reading the
+        * filename length.
+        */
+       if (end - parse < 8 + 1 + 4)
+               return 0;
+
        /* skip mode and mtime_low */
        parse += 8;
        if (version >= 0x0940)
@@ -95,6 +115,8 @@ static int INIT parse_header(u8 *input, 
 
        l = *parse++;
        /* don't care about the file name, and skip checksum */
+       if (end - parse < l + 4)
+               return 0;
        parse += l + 4;
 
        *skip = parse - input;
@@ -107,7 +129,8 @@ STATIC int INIT unlzo(u8 *input, unsigne
                      u8 *output, unsigned int *posp,
                      void (*error) (const char *x))
 {
-       u8 skip = 0, r = 0;
+       u8 r = 0;
+       int skip = 0;
        u32 src_len, dst_len;
        size_t tmp;
        u8 *in_buf, *in_buf_save, *out_buf;
@@ -149,19 +172,25 @@ STATIC int INIT unlzo(u8 *input, unsigne
        if (fill)
                fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
 
-       if (!parse_header(input, &skip)) {
+       if (!parse_header(input, &skip, in_len)) {
                error("invalid header");
                goto exit_2;
        }
        in_buf += skip;
+       in_len -= skip;
 
        if (posp)
                *posp = skip;
 
        for (;;) {
                /* read uncompressed block size */
+               if (in_len < 4) {
+                       error("file corrupted");
+                       goto exit_2;
+               }
                dst_len = get_unaligned_be32(in_buf);
                in_buf += 4;
+               in_len -= 4;
 
                /* exit if last block */
                if (dst_len == 0) {
@@ -176,10 +205,15 @@ STATIC int INIT unlzo(u8 *input, unsigne
                }
 
                /* read compressed block size, and skip block checksum info */
+               if (in_len < 8) {
+                       error("file corrupted");
+                       goto exit_2;
+               }
                src_len = get_unaligned_be32(in_buf);
                in_buf += 8;
+               in_len -= 8;
 
-               if (src_len <= 0 || src_len > dst_len) {
+               if (src_len <= 0 || src_len > dst_len || src_len > in_len) {
                        error("file corrupted");
                        goto exit_2;
                }
@@ -211,8 +245,10 @@ STATIC int INIT unlzo(u8 *input, unsigne
                if (fill) {
                        in_buf = in_buf_save;
                        fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
-               } else
+               } else {
                        in_buf += src_len;
+                       in_len -= src_len;
+               }
        }
 
        ret = 0;



Attachment: unlzo-check-input-size.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 9/9] Decompressors: check input size in unlzo.c, Jan Beulich <=