* Xen security advisory CVE-2011-1583 - pv kernel image validation
@ 2011-05-09 14:08 Ian Jackson
2011-05-09 15:05 ` Simon Rowe
0 siblings, 1 reply; 2+ messages in thread
From: Ian Jackson @ 2011-05-09 14:08 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: message body text --]
[-- Type: text/plain, Size: 4704 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Xen security advisory CVE-2011-1583
paravirtualised kernel image validation
SUMMARY
=======
Xen.org paravirtualised guest image loading functionality has multiple
errors in the validation and decompression of guest kernels.
Vendors and users are urged to apply the attached patch. Some
defensive workarounds are available.
ISSUE DESCRIPTION
=================
1. Problems
-----------
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.
2. Impact
---------
An attacker who can supply a kernel image to be booted as a
paravirtualised guest might be able to:
(i) Escalate privilege, taking control of the management domain and
hence the entire machine.
(ii) Gain knowledge the contents of memory in the management tools.
Depending on the toolstack in use this might contain sensitive
information such as domain management or VNC passwords.
(iii) Cause an infinite loop in the management software, resulting in
denial of service (and excessive resource consumption by the
management domain).
3. Who is affected, and workarounds
-----------------------------------
Systems where the guest kernel is provided by untrusted guest
administrators ARE vulnerable; this is the case whether the guest
kernel is provided by ad-hoc or out-of-band means, or via the "pygrub"
tool which automatically finds the kernel in the guest filesystem.
Systems which permit only blessed or approved paravirtualised kernel
images to be used are NOT vulnerable; preventing attackers from
providing hostile kernel images will completely prevent the attacks.
Systems which only run fully virtualised ("HVM") guests are NOT
vulnerable.
With respect to each of the three specific issues:
(i) Only management domains with 32-bit userland are vulnerable.
The attack can be defeated by running the management tools with a
virtual address space ulimit of less than 2Gby, for example by
putting "ulimit -v 1000000" in an appropriate point in the
system startup files.
(ii) In the xen.org "xend" management toolstack this exposure is
indeed limited to VNC passwords (and general information about the
number of running domains); in such systems this attack will be
complicated to carry out and not likely to be rewarding.
In the systems using the xen.org "xl" management tool this exposure
is limited to information about the specific guest in question and
is therefore very low impact.
(iii) This attack is very easy to carry out but the impact is low.
Running VMs are not adversely affected. There is no known
workaround.
In theory it might be possible to pre-validate kernel images. Images
which are accepted and booted by a fixed version of xen are safe to
pass to unfixed versions.
4. Patch information
--------------------
The proposed patch is attached. There are three separate versions:
cve-2011-1583-4.1.patch for Xen 4.1
cve-2011-1583-4.0.patch for Xen 3.4 and 4.0
cve-2011-1583-unstable.patch for the xen-unstable development tree
$ sha256sum cve-2011-1583-*.patch
f51b774eec945c48a0e91ed17df3cee07027d64c7e7c5783f7446507dbcc201b cve-2011-1583-4.0.patch
2a54dbb1984a966e8d90da9f4fb10c30ff197d13603943c38488122044bb977d cve-2011-1583-4.1.patch
0299618a56c9ad86d41a1d9879cb373bdef5105592f9a1f2390af3bf94c404be cve-2011-1583-unstable.patch
$ sha1sum cve-2011-1583-*.patch
41e2a653313d13a036e30c1c160e402e380bc377 cve-2011-1583-4.0.patch
d2bad52b255d7475709b49420db4ce41b2a108f3 cve-2011-1583-4.1.patch
0b25612d708c71143498d52af276721a4bf1c3fa cve-2011-1583-unstable.patch
$
These have been applied and pushed to xen-unstable.hg (23322:d9982136d8fa),
xen-4.1-testing (23042:e2e575f8b5d9) and xen-4.0-testing (21482:c2adc059e931).
It will appear in xen-3.4-testing shortly.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
iJwEAQECAAYFAk3H9S4ACgkQQz2i6ICVfYNB1wP/WtYetJRpVe+pWr9Ys7j51cGS
D8tPY4GUaVMEzJ8G0In4ic9cmo/T7CvLuZgXlngzHnPj+BmXzwlY511qSmLFAguM
PhuC1Hx49sBiIh0ZPymv1O8DIgesrUdWVjEmfAhXkwqP2jo7H7SUSAYRyRgoJOQe
vxHz7uopMFjg+yLx3o4=
=4vr6
-----END PGP SIGNATURE-----
[-- Attachment #2: patch for Xen 4.1 --]
[-- Type: application/octet-stream, Size: 6983 bytes --]
diff -r dbf2ddf652dc tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c Thu Apr 07 15:26:58 2011 +0100
+++ b/tools/libxc/xc_dom_bzimageloader.c Thu Apr 21 12:05:57 2011 +0100
@@ -82,8 +82,29 @@ static int xc_try_bzip2_decode(
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 @@ static int xc_try_bzip2_decode(
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 @@ static int xc_try_lzma_decode(
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 @@ static int xc_try_lzma_decode(
}
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 @@ struct setup_header {
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 @@ static int xc_dom_probe_bzimage_kernel(s
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 @@ static int xc_dom_probe_bzimage_kernel(s
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 @@ static int xc_dom_probe_bzimage_kernel(s
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 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
[-- Attachment #3: patch for Xen 3.4 and 4.0 --]
[-- Type: application/octet-stream, Size: 6708 bytes --]
diff -r dbbc61c48da4 tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c Wed Apr 13 09:48:17 2011 +0100
+++ b/tools/libxc/xc_dom_bzimageloader.c Thu Apr 21 11:57:06 2011 +0100
@@ -68,8 +68,29 @@ static int xc_try_bzip2_decode(
for ( ; ; )
{
ret = BZ2_bzDecompress(&stream);
- if ( (stream.avail_out == 0) || (ret != BZ_OK) )
+ if ( ret == BZ_STREAM_END )
{
+ xc_dom_printf("BZIP2: Saw data stream end\n");
+ retval = 0;
+ break;
+ }
+ if ( ret != BZ_OK )
+ {
+ xc_dom_printf("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 )
+ {
+ xc_dom_printf("BZIP2: output buffer overflow\n");
+ free(out_buf);
+ goto bzip2_cleanup;
+ }
+
tmp_buf = realloc(out_buf, outsize * 2);
if ( tmp_buf == NULL )
{
@@ -83,16 +104,18 @@ static int xc_try_bzip2_decode(
stream.avail_out = (outsize * 2) - outsize;
outsize *= 2;
}
-
- if ( ret != BZ_OK )
+ else if ( stream.avail_in == 0 )
{
- if ( ret == BZ_STREAM_END )
- {
- xc_dom_printf("BZIP2: Saw data stream end\n");
- retval = 0;
- break;
- }
- xc_dom_printf("BZIP2: error\n");
+ /*
+ * 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.
+ */
+ xc_dom_printf("BZIP2: not enough input\n");
+ free(out_buf);
+ goto bzip2_cleanup;
}
}
@@ -187,31 +210,14 @@ static int xc_try_lzma_decode(
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 )
- {
- xc_dom_printf("LZMA: Failed to realloc memory\n");
- free(out_buf);
- goto lzma_cleanup;
- }
- out_buf = tmp_buf;
-
- stream.next_out = out_buf + outsize;
- stream.avail_out = (outsize * 2) - outsize;
- outsize *= 2;
+ xc_dom_printf("LZMA: Saw data stream end\n");
+ retval = 0;
+ break;
}
-
if ( ret != LZMA_OK )
{
- if ( ret == LZMA_STREAM_END )
- {
- xc_dom_printf("LZMA: Saw data stream end\n");
- retval = 0;
- break;
- }
-
switch ( ret )
{
case LZMA_MEM_ERROR:
@@ -245,7 +251,32 @@ static int xc_try_lzma_decode(
}
xc_dom_printf("%s: LZMA decompression error %s\n",
__FUNCTION__, msg);
- break;
+ free(out_buf);
+ goto lzma_cleanup;
+ }
+
+ if ( stream.avail_out == 0 )
+ {
+ /* Protect against output buffer overflow */
+ if ( outsize > INT_MAX / 2 )
+ {
+ xc_dom_printf("LZMA: output buffer overflow\n");
+ free(out_buf);
+ goto lzma_cleanup;
+ }
+
+ tmp_buf = realloc(out_buf, outsize * 2);
+ if ( tmp_buf == NULL )
+ {
+ xc_dom_printf("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;
}
}
@@ -314,18 +345,18 @@ struct setup_header {
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 )
@@ -358,10 +389,30 @@ static int xc_dom_probe_bzimage_kernel(s
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(XC_INVALID_KERNEL, "%s: payload offset overflow",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ if ( (payload_offset + payload_length) > dom->kernel_size )
+ {
+ xc_dom_panic(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 )
@@ -372,7 +423,7 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
@@ -383,7 +434,7 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
[-- Attachment #4: Patch for xen-unstable --]
[-- Type: application/octet-stream, Size: 7341 bytes --]
diff -r b1e0da092e92 tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c Thu Apr 21 11:36:43 2011 +0100
+++ b/tools/libxc/xc_dom_bzimageloader.c Thu Apr 21 11:37:04 2011 +0100
@@ -82,8 +82,29 @@ static int xc_try_bzip2_decode(
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 @@ static int xc_try_bzip2_decode(
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;
}
}
@@ -173,31 +196,14 @@ static int _xc_try_lzma_decode(
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("%s: Failed to realloc memory", what);
- 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("%s: Saw data stream end", what);
+ retval = 0;
+ break;
}
-
if ( ret != LZMA_OK )
{
- if ( ret == LZMA_STREAM_END )
- {
- DOMPRINTF("%s: Saw data stream end", what);
- retval = 0;
- break;
- }
-
switch ( ret )
{
case LZMA_MEM_ERROR:
@@ -231,7 +237,32 @@ static int _xc_try_lzma_decode(
}
DOMPRINTF("%s: %s decompression error: %s",
__FUNCTION__, what, msg);
- break;
+ free(out_buf);
+ goto lzma_cleanup;
+ }
+
+ if ( stream->avail_out == 0 )
+ {
+ /* Protect against output buffer overflow */
+ if ( outsize > INT_MAX / 2 )
+ {
+ DOMPRINTF("%s: output buffer overflow", what);
+ free(out_buf);
+ goto lzma_cleanup;
+ }
+
+ tmp_buf = realloc(out_buf, outsize * 2);
+ if ( tmp_buf == NULL )
+ {
+ DOMPRINTF("%s: Failed to realloc memory", what);
+ free(out_buf);
+ goto lzma_cleanup;
+ }
+ out_buf = tmp_buf;
+
+ stream->next_out = out_buf + outsize;
+ stream->avail_out = (outsize * 2) - outsize;
+ outsize *= 2;
}
}
@@ -521,18 +552,18 @@ struct setup_header {
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 )
@@ -565,10 +596,30 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
@@ -578,7 +629,7 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
@@ -589,7 +640,7 @@ static int xc_dom_probe_bzimage_kernel(s
return -EINVAL;
}
}
- else if ( memcmp(dom->kernel_blob, "\3757zXZ", 6) == 0 )
+ else if ( check_magic(dom, "\3757zXZ", 6) )
{
ret = xc_try_xz_decode(dom, &dom->kernel_blob, &dom->kernel_size);
if ( ret < 0 )
@@ -600,7 +651,7 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
@@ -611,7 +662,7 @@ static int xc_dom_probe_bzimage_kernel(s
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 )
[-- Attachment #5: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: Xen security advisory CVE-2011-1583 - pv kernel image validation
2011-05-09 14:08 Xen security advisory CVE-2011-1583 - pv kernel image validation Ian Jackson
@ 2011-05-09 15:05 ` Simon Rowe
0 siblings, 0 replies; 2+ messages in thread
From: Simon Rowe @ 2011-05-09 15:05 UTC (permalink / raw)
To: xen-devel
[-- Attachment #1: Type: text/plain, Size: 84 bytes --]
Attached are patches for Xen 3.2 & 3.3 as shipped with XenServer 5.0 & 5.5,
Simon
[-- Attachment #2: cve-2011-1583-3.2.patch --]
[-- Type: text/x-patch, Size: 2571 bytes --]
# HG changeset patch
# Parent 11931301845c3b4b6a358f2d7246874b1d10c05f
diff -r 11931301845c tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c Mon Mar 14 16:59:49 2011 +0000
+++ b/tools/libxc/xc_dom_bzimageloader.c Tue May 03 10:09:28 2011 +0100
@@ -61,18 +61,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 check_bzimage_kernel(struct xc_dom_image *dom, int verbose)
{
struct setup_header *hdr;
+ uint64_t payload_offset, payload_length;
if ( dom->kernel_blob == NULL )
{
@@ -107,14 +107,43 @@
return -EINVAL;
}
- dom->kernel_blob = dom->kernel_blob + payload_offset(hdr);
- dom->kernel_size = hdr->payload_length;
- if ( xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size) == -1 )
+ /* 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 )
{
- if ( verbose )
- xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to decompress kernel\n",
- __FUNCTION__);
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: payload offset overflow",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ if ( (payload_offset + payload_length) > dom->kernel_size )
+ {
+ xc_dom_panic(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) )
+ {
+ if ( xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size) == -1 )
+ {
+ if ( verbose )
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to decompress kernel\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: unknown compression format\n",
+ __FUNCTION__);
return -EINVAL;
}
[-- Attachment #3: cve-2011-1583-3.3.patch --]
[-- Type: text/x-patch, Size: 2571 bytes --]
# HG changeset patch
# Parent 11931301845c3b4b6a358f2d7246874b1d10c05f
diff -r 11931301845c tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c Mon Mar 14 16:59:49 2011 +0000
+++ b/tools/libxc/xc_dom_bzimageloader.c Tue May 03 10:09:28 2011 +0100
@@ -61,18 +61,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 check_bzimage_kernel(struct xc_dom_image *dom, int verbose)
{
struct setup_header *hdr;
+ uint64_t payload_offset, payload_length;
if ( dom->kernel_blob == NULL )
{
@@ -107,14 +107,43 @@
return -EINVAL;
}
- dom->kernel_blob = dom->kernel_blob + payload_offset(hdr);
- dom->kernel_size = hdr->payload_length;
- if ( xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size) == -1 )
+ /* 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 )
{
- if ( verbose )
- xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to decompress kernel\n",
- __FUNCTION__);
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: payload offset overflow",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ if ( (payload_offset + payload_length) > dom->kernel_size )
+ {
+ xc_dom_panic(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) )
+ {
+ if ( xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size) == -1 )
+ {
+ if ( verbose )
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to decompress kernel\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ xc_dom_panic(XC_INVALID_KERNEL, "%s: unknown compression format\n",
+ __FUNCTION__);
return -EINVAL;
}
[-- Attachment #4: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-05-09 15:05 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-09 14:08 Xen security advisory CVE-2011-1583 - pv kernel image validation Ian Jackson
2011-05-09 15:05 ` Simon Rowe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).