Bastian Blank
2011-Jun-09 18:35 UTC
[Pkg-xen-changes] r896 - in branches/squeeze-security/xen/debian: . patches
Author: waldi Date: Thu Jun 9 18:35:07 2011 New Revision: 896 Log: * debian/changelog: Prepare to release (4.0.1-4). * debian/patches/series: Update. * debian/patches/upstream-21485:b85a9e58ec3a-CVE-2011-1898, debian/patches/upstream-21482:c2adc059e931-CVE-2011-1583: New security patches. Added: branches/squeeze-security/xen/debian/patches/upstream-21482:c2adc059e931-CVE-2011-1583 branches/squeeze-security/xen/debian/patches/upstream-21485:b85a9e58ec3a-CVE-2011-1898 Modified: branches/squeeze-security/xen/debian/changelog branches/squeeze-security/xen/debian/patches/series Modified: branches/squeeze-security/xen/debian/changelog =============================================================================--- branches/squeeze-security/xen/debian/changelog Sat Apr 30 13:39:55 2011 (r895) +++ branches/squeeze-security/xen/debian/changelog Thu Jun 9 18:35:07 2011 (r896) @@ -1,3 +1,12 @@ +xen (4.0.1-4) stable-security; urgency=low + + * Fix overflows and missing error checks in PV kernel loader. + CVE-2011-1583 + * Protect against malicious MSIs from untrusted devices. + CVE-2011-1898 + + -- Bastian Blank <waldi at debian.org> Thu, 09 Jun 2011 20:33:46 +0200 + xen (4.0.1-3) stable-security; urgency=low * Fix check for existance of user-mode page tables. Modified: branches/squeeze-security/xen/debian/patches/series =============================================================================--- branches/squeeze-security/xen/debian/patches/series Sat Apr 30 13:39:55 2011 (r895) +++ branches/squeeze-security/xen/debian/patches/series Thu Jun 9 18:35:07 2011 (r896) @@ -69,3 +69,5 @@ upstream-21409:a45388506790 upstream-21413:b05fa0652463 upstream-21461:ee088a0b5cb8-CVE-2011-1166 +upstream-21482:c2adc059e931-CVE-2011-1583 +upstream-21485:b85a9e58ec3a-CVE-2011-1898 Added: branches/squeeze-security/xen/debian/patches/upstream-21482:c2adc059e931-CVE-2011-1583 =============================================================================--- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/squeeze-security/xen/debian/patches/upstream-21482:c2adc059e931-CVE-2011-1583 Thu Jun 9 18:35:07 2011 (r896) @@ -0,0 +1,235 @@ +# HG changeset patch +# User Ian Jackson <ian.jackson at eu.citrix.com> +# Date 1304949977 -3600 +# Node ID c2adc059e9311cc88778fd6020818344902ecdc6 +# Parent e91977e7ab3ab097a49c6a4780b330a4f48dac81 +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 at eu.citrix.com> +Signed-off-by: Ian Jackson <ian.jackson at eu.citrix.com> +Committed-by: Ian Jackson <ian.jackson at eu.citrix.com> + +diff -r e91977e7ab3a -r c2adc059e931 tools/libxc/xc_dom_bzimageloader.c +--- a/tools/libxc/xc_dom_bzimageloader.c Mon May 09 12:20:24 2011 +0100 ++++ b/tools/libxc/xc_dom_bzimageloader.c Mon May 09 15:06:17 2011 +0100 +@@ -68,8 +68,29 @@ + 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 @@ + 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 @@ + 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 @@ + } + 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 @@ + + 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 @@ + 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 @@ + 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 @@ + 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 ) Added: branches/squeeze-security/xen/debian/patches/upstream-21485:b85a9e58ec3a-CVE-2011-1898 =============================================================================--- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ branches/squeeze-security/xen/debian/patches/upstream-21485:b85a9e58ec3a-CVE-2011-1898 Thu Jun 9 18:35:07 2011 (r896) @@ -0,0 +1,121 @@ +# HG changeset patch +# User Keir Fraser <keir at xen.org> +# Date 1305220065 -3600 +# Node ID b85a9e58ec3aa46be0e4148737fefdddd59fdddf +# Parent f47c6786ea6d8f14ce0a6770e9be51ca2b9d6888 +x86, vtd: [CVE-2011-1898] Protect against malicious MSIs from untrusted devices. + +In the absence of VT-d interrupt remapping support, a device can send +arbitrary APIC messages to host CPUs. One class of attack that results +is to confuse the hypervisor by delivering asynchronous interrupts to +vectors that are expected to handle only synchronous +traps/exceptions. + +We block this class of attack by: +(1) setting APIC.TPR=0x10, to block all interrupts below vector +0x20. This blocks delivery to all architectural exception vectors. +(2) checking APIC.ISR[vec] for vectors 0x80 (fast syscall) and 0x82 +(hypercall). In these cases we BUG if we detect we are handling a +hardware interrupt -- turning a potentially more severe infiltration +into a straightforward system crash (i.e, DoS). + +Thanks to Invisible Things Lab <http://www.invisiblethingslab.com> +for discovery and detailed investigation of this attack. + +Signed-off-by: Keir Fraser <keir at xen.org> +xen-unstable changeset: 23337:cc91832a02c7 +xen-unstable date: Thu May 12 16:39:31 2011 +0100 + +diff -r f47c6786ea6d -r b85a9e58ec3a xen/arch/x86/apic.c +--- a/xen/arch/x86/apic.c Thu May 12 09:23:21 2011 +0100 ++++ b/xen/arch/x86/apic.c Thu May 12 18:07:45 2011 +0100 +@@ -572,12 +572,9 @@ + init_apic_ldr(); + + /* +- * Set Task Priority to ''accept all''. We never change this +- * later on. ++ * Set Task Priority to reject any interrupts below FIRST_DYNAMIC_VECTOR. + */ +- value = apic_read(APIC_TASKPRI); +- value &= ~APIC_TPRI_MASK; +- apic_write_around(APIC_TASKPRI, value); ++ apic_write_around(APIC_TASKPRI, (FIRST_DYNAMIC_VECTOR & 0xF0) - 0x10); + + /* + * After a crash, we no longer service the interrupts and a pending +@@ -1498,3 +1495,9 @@ + + return 0; + } ++ ++void check_for_unexpected_msi(unsigned int vector) ++{ ++ unsigned long v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1)); ++ BUG_ON(v & (1 << (vector & 0x1f))); ++} +diff -r f47c6786ea6d -r b85a9e58ec3a xen/arch/x86/x86_64/compat/entry.S +--- a/xen/arch/x86/x86_64/compat/entry.S Thu May 12 09:23:21 2011 +0100 ++++ b/xen/arch/x86/x86_64/compat/entry.S Thu May 12 18:07:45 2011 +0100 +@@ -27,6 +27,15 @@ + pushq $0 + movl $TRAP_syscall,4(%rsp) + SAVE_ALL ++ ++ cmpb $0,untrusted_msi(%rip) ++ je 1f ++ movl $0x82,%edi ++ call check_for_unexpected_msi ++ RESTORE_ALL ++ SAVE_ALL ++1: ++ + GET_CURRENT(%rbx) + + cmpl $NR_hypercalls,%eax +diff -r f47c6786ea6d -r b85a9e58ec3a xen/arch/x86/x86_64/entry.S +--- a/xen/arch/x86/x86_64/entry.S Thu May 12 09:23:21 2011 +0100 ++++ b/xen/arch/x86/x86_64/entry.S Thu May 12 18:07:45 2011 +0100 +@@ -310,6 +310,14 @@ + pushq $0 + SAVE_ALL + ++ cmpb $0,untrusted_msi(%rip) ++ je 1f ++ movl $0x80,%edi ++ call check_for_unexpected_msi ++ RESTORE_ALL ++ SAVE_ALL ++1: ++ + GET_CURRENT(%rbx) + + /* Check that the callback is non-null. */ +diff -r f47c6786ea6d -r b85a9e58ec3a xen/drivers/passthrough/vtd/iommu.c +--- a/xen/drivers/passthrough/vtd/iommu.c Thu May 12 09:23:21 2011 +0100 ++++ b/xen/drivers/passthrough/vtd/iommu.c Thu May 12 18:07:45 2011 +0100 +@@ -42,6 +42,9 @@ + #define nr_ioapics iosapic_get_nr_iosapics() + #endif + ++/* Possible unfiltered LAPIC/MSI messages from untrusted sources? */ ++bool_t __read_mostly untrusted_msi; ++ + int nr_iommus; + static bool_t rwbf_quirk; + +@@ -1566,6 +1569,14 @@ + if (!pdev) + return -ENODEV; + ++ /* ++ * Devices assigned to untrusted domains (here assumed to be any domU) ++ * can attempt to send arbitrary LAPIC/MSI messages. We are unprotected ++ * by the root complex unless interrupt remapping is enabled. ++ */ ++ if ( (target != dom0) && !iommu_intremap ) ++ untrusted_msi = 1; ++ + ret = domain_context_unmap(source, bus, devfn); + if ( ret ) + return ret;