[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Decompressors: check input size in unlzo.c



# HG changeset patch
# User Lasse Collin <lasse.collin@xxxxxxxxxxx>
# Date 1321018551 -3600
# Node ID 44d925615ac6dc5667cfae5e287dbbd720d89fc7
# Parent  276db7ceeb5d5f4ac47a1ed83c3574cb46d7aa84
Decompressors: check input size in unlzo.c

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>
Acked-by: Keir Fraser <keir@xxxxxxx>
Committed-by: Jan Beulich <jbeulich@xxxxxxxx>
---


diff -r 276db7ceeb5d -r 44d925615ac6 xen/common/unlzo.c
--- a/xen/common/unlzo.c        Fri Nov 11 14:35:05 2011 +0100
+++ b/xen/common/unlzo.c        Fri Nov 11 14:35:51 2011 +0100
@@ -63,14 +63,25 @@
 
 #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 @@
        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 @@
 
        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 @@
                      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 @@
        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 @@
                }
 
                /* 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 @@
                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;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.