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-changelog

[Xen-changelog] [xen-4.1-testing] libxc: [CVE-2011-1583] pv kernel image

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-4.1-testing] libxc: [CVE-2011-1583] pv kernel image validation
From: Xen patchbot-4.1-testing <patchbot@xxxxxxx>
Date: Tue, 10 May 2011 19:30:11 +0100
Delivery-date: Tue, 10 May 2011 11:30:47 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
# Date 1304949841 -3600
# Node ID e2e575f8b5d961db23ea8bb7b3820be8621789b3
# Parent  bdc6dd89d83c2fcd87b069557b6f8867ab95dda1
libxc: [CVE-2011-1583] pv kernel image validation

The functions which interpret the kernel image supplied for a
paravirtualised guest, and decompress it into memory when booting the
domain, are incautious.  Specifically:

 (i) Integer overflow in the decompression loop memory allocator might
    result in overrunning the buffer used for the decompressed image;
 (ii) Integer overflows and lack of checking of certain length fields
    can result in the loader reading its own address space beyond the
    size of the supplied kernel image file.
 (iii) Lack of error checking in the decompression loop can lead to an
    infinite loop.

This patch fixes these problems.

CVE-2011-1583.

Signed-off-by: Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx>
Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Committed-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---


diff -r bdc6dd89d83c -r e2e575f8b5d9 tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c        Mon May 09 12:18:50 2011 +0100
+++ b/tools/libxc/xc_dom_bzimageloader.c        Mon May 09 15:04:01 2011 +0100
@@ -82,8 +82,29 @@
     for ( ; ; )
     {
         ret = BZ2_bzDecompress(&stream);
-        if ( (stream.avail_out == 0) || (ret != BZ_OK) )
+        if ( ret == BZ_STREAM_END )
         {
+            DOMPRINTF("BZIP2: Saw data stream end");
+            retval = 0;
+            break;
+        }
+        if ( ret != BZ_OK )
+        {
+            DOMPRINTF("BZIP2: error %d", ret);
+            free(out_buf);
+            goto bzip2_cleanup;
+        }
+
+        if ( stream.avail_out == 0 )
+        {
+            /* Protect against output buffer overflow */
+            if ( outsize > INT_MAX / 2 )
+            {
+                DOMPRINTF("BZIP2: output buffer overflow");
+                free(out_buf);
+                goto bzip2_cleanup;
+            }
+
             tmp_buf = realloc(out_buf, outsize * 2);
             if ( tmp_buf == NULL )
             {
@@ -97,16 +118,18 @@
             stream.avail_out = (outsize * 2) - outsize;
             outsize *= 2;
         }
-
-        if ( ret != BZ_OK )
+        else if ( stream.avail_in == 0 )
         {
-            if ( ret == BZ_STREAM_END )
-            {
-                DOMPRINTF("BZIP2: Saw data stream end");
-                retval = 0;
-                break;
-            }
-            DOMPRINTF("BZIP2: error");
+            /*
+             * If there is output buffer available then this indicates
+             * that BZ2_bzDecompress would like more input data to be
+             * provided.  However our complete input buffer is in
+             * memory and provided upfront so if avail_in is zero this
+             * actually indicates a truncated input.
+             */
+            DOMPRINTF("BZIP2: not enough input");
+            free(out_buf);
+            goto bzip2_cleanup;
         }
     }
 
@@ -180,31 +203,14 @@
     for ( ; ; )
     {
         ret = lzma_code(&stream, action);
-        if ( (stream.avail_out == 0) || (ret != LZMA_OK) )
+        if ( ret == LZMA_STREAM_END )
         {
-            tmp_buf = realloc(out_buf, outsize * 2);
-            if ( tmp_buf == NULL )
-            {
-                DOMPRINTF("LZMA: Failed to realloc memory");
-                free(out_buf);
-                goto lzma_cleanup;
-            }
-            out_buf = tmp_buf;
-
-            stream.next_out = out_buf + outsize;
-            stream.avail_out = (outsize * 2) - outsize;
-            outsize *= 2;
+            DOMPRINTF("LZMA: Saw data stream end");
+            retval = 0;
+            break;
         }
-
         if ( ret != LZMA_OK )
         {
-            if ( ret == LZMA_STREAM_END )
-            {
-                DOMPRINTF("LZMA: Saw data stream end");
-                retval = 0;
-                break;
-            }
-
             switch ( ret )
             {
             case LZMA_MEM_ERROR:
@@ -238,7 +244,32 @@
             }
             DOMPRINTF("%s: LZMA decompression error %s",
                       __FUNCTION__, msg);
-            break;
+            free(out_buf);
+            goto lzma_cleanup;
+        }
+
+        if ( stream.avail_out == 0 )
+        {
+            /* Protect against output buffer overflow */
+            if ( outsize > INT_MAX / 2 )
+            {
+                DOMPRINTF("LZMA: output buffer overflow");
+                free(out_buf);
+                goto lzma_cleanup;
+            }
+
+            tmp_buf = realloc(out_buf, outsize * 2);
+            if ( tmp_buf == NULL )
+            {
+                DOMPRINTF("LZMA: Failed to realloc memory");
+                free(out_buf);
+                goto lzma_cleanup;
+            }
+            out_buf = tmp_buf;
+
+            stream.next_out = out_buf + outsize;
+            stream.avail_out = (outsize * 2) - outsize;
+            outsize *= 2;
         }
     }
 
@@ -489,18 +520,18 @@
 
 extern struct xc_dom_loader elf_loader;
 
-static unsigned int payload_offset(struct setup_header *hdr)
+static int check_magic(struct xc_dom_image *dom, const void *magic, size_t len)
 {
-    unsigned int off;
+    if (len > dom->kernel_size)
+        return 0;
 
-    off = (hdr->setup_sects + 1) * 512;
-    off += hdr->payload_offset;
-    return off;
+    return (memcmp(dom->kernel_blob, magic, len) == 0);
 }
 
 static int xc_dom_probe_bzimage_kernel(struct xc_dom_image *dom)
 {
     struct setup_header *hdr;
+    uint64_t payload_offset, payload_length;
     int ret;
 
     if ( dom->kernel_blob == NULL )
@@ -533,10 +564,30 @@
         return -EINVAL;
     }
 
-    dom->kernel_blob = dom->kernel_blob + payload_offset(hdr);
-    dom->kernel_size = hdr->payload_length;
 
-    if ( memcmp(dom->kernel_blob, "\037\213", 2) == 0 )
+    /* upcast to 64 bits to avoid overflow */
+    /* setup_sects is u8 and so cannot overflow */
+    payload_offset = (hdr->setup_sects + 1) * 512;
+    payload_offset += hdr->payload_offset;
+    payload_length = hdr->payload_length;
+
+    if ( payload_offset >= dom->kernel_size )
+    {
+        xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: payload offset 
overflow",
+                     __FUNCTION__);
+        return -EINVAL;
+    }
+    if ( (payload_offset + payload_length) > dom->kernel_size )
+    {
+        xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: payload length 
overflow",
+                     __FUNCTION__);
+        return -EINVAL;
+    }
+
+    dom->kernel_blob = dom->kernel_blob + payload_offset;
+    dom->kernel_size = payload_length;
+
+    if ( check_magic(dom, "\037\213", 2) )
     {
         ret = xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size);
         if ( ret == -1 )
@@ -546,7 +597,7 @@
             return -EINVAL;
         }
     }
-    else if ( memcmp(dom->kernel_blob, "\102\132\150", 3) == 0 )
+    else if ( check_magic(dom, "\102\132\150", 3) )
     {
         ret = xc_try_bzip2_decode(dom, &dom->kernel_blob, &dom->kernel_size);
         if ( ret < 0 )
@@ -557,7 +608,7 @@
             return -EINVAL;
         }
     }
-    else if ( memcmp(dom->kernel_blob, "\135\000", 2) == 0 )
+    else if ( check_magic(dom, "\135\000", 2) )
     {
         ret = xc_try_lzma_decode(dom, &dom->kernel_blob, &dom->kernel_size);
         if ( ret < 0 )
@@ -568,7 +619,7 @@
             return -EINVAL;
         }
     }
-    else if ( memcmp(dom->kernel_blob, "\x89LZO", 5) == 0 )
+    else if ( check_magic(dom, "\x89LZO", 5) )
     {
         ret = xc_try_lzo1x_decode(dom, &dom->kernel_blob, &dom->kernel_size);
         if ( ret < 0 )

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-4.1-testing] libxc: [CVE-2011-1583] pv kernel image validation, Xen patchbot-4 . 1-testing <=