[xen] Two security fixes CVE-2013-0215 CVE-2013-0153

myoung myoung at fedoraproject.org
Tue Feb 5 19:37:42 UTC 2013


commit 958b17f2d0528f5818395f18ab1d5ad8f6461340
Author: Michael Young <m.a.young at durham.ac.uk>
Date:   Tue Feb 5 19:36:05 2013 +0000

    Two security fixes CVE-2013-0215 CVE-2013-0153

 xen.spec        |   12 ++-
 xsa36-4.2.patch |  323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 xsa38.patch     |   73 +++++++++++++
 3 files changed, 407 insertions(+), 1 deletions(-)
---
diff --git a/xen.spec b/xen.spec
index 7d24e07..973d19e 100644
--- a/xen.spec
+++ b/xen.spec
@@ -27,7 +27,7 @@
 Summary: Xen is a virtual machine monitor
 Name:    xen
 Version: 4.2.1
-Release: 5%{?dist}
+Release: 6%{?dist}
 Group:   Development/Libraries
 License: GPLv2+ and LGPLv2+ and BSD
 URL:     http://xen.org/
@@ -78,9 +78,11 @@ Patch56: xen.fedora19.buildfix.patch
 Patch57: xsa33-4.2-unstable.patch
 Patch58: xsa34-4.2.patch
 Patch59: xsa35-4.2-with-xsa34.patch
+Patch60: xsa36-4.2.patch
 Patch61: xsa37-4.2.patch
 Patch62: man.formatting.patch
 Patch63: xsa41.patch
+Patch64: xsa38.patch
 
 Patch100: xen-configure-xend.patch
 
@@ -249,9 +251,11 @@ manage Xen virtual machines.
 %patch57 -p1
 %patch58 -p1
 %patch59 -p1
+%patch60 -p1
 %patch61 -p1
 %patch62 -p1
 %patch63 -p1
+%patch64 -p1
 
 %patch100 -p1
 
@@ -741,6 +745,12 @@ rm -rf %{buildroot}
 %endif
 
 %changelog
+* Tue Feb 05 2013 Michael Young <m.a.young at durham.ac.uk> - 4.2.1-6
+- guest using oxenstored can crash host or exhaust memory [XSA-38,
+  CVE-2013-0215] (#907888)
+- guest using AMD-Vi for PCI passthrough can cause denial of service
+  [XSA-36, CVE-2013-0153]
+
 * Wed Jan 23 2013 Michael Young <m.a.young at durham.ac.uk>
 - correct disabling of xendomains.service on uninstall
 
diff --git a/xsa36-4.2.patch b/xsa36-4.2.patch
new file mode 100644
index 0000000..8477701
--- /dev/null
+++ b/xsa36-4.2.patch
@@ -0,0 +1,323 @@
+ACPI: acpi_table_parse() should return handler's error code
+
+Currently, the error code returned by acpi_table_parse()'s handler
+is ignored. This patch will propagate handler's return value to
+acpi_table_parse()'s caller.
+
+AMD,IOMMU: Clean up old entries in remapping tables when creating new
+interrupt mapping.
+
+When changing the affinity of an IRQ associated with a passed
+through PCI device, clear previous mapping.
+
+In addition, because some BIOSes may incorrectly program IVRS
+entries for IOAPIC try to check for entry's consistency. Specifically,
+if conflicting entries are found disable IOMMU if per-device
+remapping table is used. If entries refer to bogus IOAPIC IDs
+disable IOMMU unconditionally
+
+AMD,IOMMU: Disable IOMMU if SATA Combined mode is on
+
+AMD's SP5100 chipset can be placed into SATA Combined mode
+that may cause prevent dom0 from booting when IOMMU is
+enabled and per-device interrupt remapping table is used.
+While SP5100 erratum 28 requires BIOSes to disable this mode,
+some may still use it.
+
+This patch checks whether this mode is on and, if per-device
+table is in use, disables IOMMU.
+
+AMD,IOMMU: Make per-device interrupt remapping table default
+
+Using global interrupt remapping table may be insecure, as
+described by XSA-36. This patch makes per-device mode default.
+
+This is XSA-36 / CVE-2013-0153.
+
+Signed-off-by: Jan Beulich <jbeulich at suse.com>
+Signed-off-by: Boris Ostrovsky <boris.ostrovsky at amd.com>
+
+--- a/xen/arch/x86/irq.c
++++ b/xen/arch/x86/irq.c
+@@ -1942,9 +1942,6 @@ int map_domain_pirq(
+         spin_lock_irqsave(&desc->lock, flags);
+         set_domain_irq_pirq(d, irq, info);
+         spin_unlock_irqrestore(&desc->lock, flags);
+-
+-        if ( opt_irq_vector_map == OPT_IRQ_VECTOR_MAP_PERDEV )
+-            printk(XENLOG_INFO "Per-device vector maps for GSIs not implemented yet.\n");
+     }
+ 
+ done:
+--- a/xen/drivers/acpi/tables.c
++++ b/xen/drivers/acpi/tables.c
+@@ -267,7 +267,7 @@ acpi_table_parse_madt(enum acpi_madt_typ
+  * @handler: handler to run
+  *
+  * Scan the ACPI System Descriptor Table (STD) for a table matching @id,
+- * run @handler on it.  Return 0 if table found, return on if not.
++ * run @handler on it.
+  */
+ int __init acpi_table_parse(char *id, acpi_table_handler handler)
+ {
+@@ -282,8 +282,7 @@ int __init acpi_table_parse(char *id, ac
+ 		acpi_get_table(id, 0, &table);
+ 
+ 	if (table) {
+-		handler(table);
+-		return 0;
++		return handler(table);
+ 	} else
+ 		return 1;
+ }
+--- a/xen/drivers/passthrough/amd/iommu_acpi.c
++++ b/xen/drivers/passthrough/amd/iommu_acpi.c
+@@ -22,6 +22,7 @@
+ #include <xen/errno.h>
+ #include <xen/acpi.h>
+ #include <asm/apicdef.h>
++#include <asm/io_apic.h>
+ #include <asm/amd-iommu.h>
+ #include <asm/hvm/svm/amd-iommu-proto.h>
+ 
+@@ -635,6 +636,7 @@ static u16 __init parse_ivhd_device_spec
+     u16 header_length, u16 block_length, struct amd_iommu *iommu)
+ {
+     u16 dev_length, bdf;
++    int apic;
+ 
+     dev_length = sizeof(*special);
+     if ( header_length < (block_length + dev_length) )
+@@ -651,10 +653,59 @@ static u16 __init parse_ivhd_device_spec
+     }
+ 
+     add_ivrs_mapping_entry(bdf, bdf, special->header.data_setting, iommu);
+-    /* set device id of ioapic */
+-    ioapic_sbdf[special->handle].bdf = bdf;
+-    ioapic_sbdf[special->handle].seg = seg;
+-    return dev_length;
++
++    if ( special->variety != ACPI_IVHD_IOAPIC )
++    {
++        if ( special->variety != ACPI_IVHD_HPET )
++            printk(XENLOG_ERR "Unrecognized IVHD special variety %#x\n",
++                   special->variety);
++        return dev_length;
++    }
++
++    /*
++     * Some BIOSes have IOAPIC broken entries so we check for IVRS
++     * consistency here --- whether entry's IOAPIC ID is valid and
++     * whether there are conflicting/duplicated entries.
++     */
++    for ( apic = 0; apic < nr_ioapics; apic++ )
++    {
++        if ( IO_APIC_ID(apic) != special->handle )
++            continue;
++
++        if ( ioapic_sbdf[special->handle].pin_setup )
++        {
++            if ( ioapic_sbdf[special->handle].bdf == bdf &&
++                 ioapic_sbdf[special->handle].seg == seg )
++                AMD_IOMMU_DEBUG("IVHD Warning: Duplicate IO-APIC %#x entries\n",
++                                special->handle);
++            else
++            {
++                printk(XENLOG_ERR "IVHD Error: Conflicting IO-APIC %#x entries\n",
++                       special->handle);
++                if ( amd_iommu_perdev_intremap )
++                    return 0;
++            }
++        }
++        else
++        {
++            /* set device id of ioapic */
++            ioapic_sbdf[special->handle].bdf = bdf;
++            ioapic_sbdf[special->handle].seg = seg;
++
++            ioapic_sbdf[special->handle].pin_setup = xzalloc_array(
++                unsigned long, BITS_TO_LONGS(nr_ioapic_entries[apic]));
++            if ( nr_ioapic_entries[apic] &&
++                 !ioapic_sbdf[IO_APIC_ID(apic)].pin_setup )
++            {
++                printk(XENLOG_ERR "IVHD Error: Out of memory\n");
++                return 0;
++            }
++        }
++        return dev_length;
++    }
++
++    printk(XENLOG_ERR "IVHD Error: Invalid IO-APIC %#x\n", special->handle);
++    return 0;
+ }
+ 
+ static int __init parse_ivhd_block(const struct acpi_ivrs_hardware *ivhd_block)
+--- a/xen/drivers/passthrough/amd/iommu_init.c
++++ b/xen/drivers/passthrough/amd/iommu_init.c
+@@ -1126,12 +1126,45 @@ static int __init amd_iommu_setup_device
+     return 0;
+ }
+ 
++/* Check whether SP5100 SATA Combined mode is on */
++static bool_t __init amd_sp5100_erratum28(void)
++{
++    u32 bus, id;
++    u16 vendor_id, dev_id;
++    u8 byte;
++
++    for (bus = 0; bus < 256; bus++)
++    {
++        id = pci_conf_read32(0, bus, 0x14, 0, PCI_VENDOR_ID);
++
++        vendor_id = id & 0xffff;
++        dev_id = (id >> 16) & 0xffff;
++
++        /* SP5100 SMBus module sets Combined mode on */
++        if (vendor_id != 0x1002 || dev_id != 0x4385)
++            continue;
++
++        byte = pci_conf_read8(0, bus, 0x14, 0, 0xad);
++        if ( (byte >> 3) & 1 )
++        {
++            printk(XENLOG_WARNING "AMD-Vi: SP5100 erratum 28 detected, disabling IOMMU.\n"
++                   "If possible, disable SATA Combined mode in BIOS or contact your vendor for BIOS update.\n");
++            return 1;
++        }
++    }
++
++    return 0;
++}
++
+ int __init amd_iommu_init(void)
+ {
+     struct amd_iommu *iommu;
+ 
+     BUG_ON( !iommu_found() );
+ 
++    if ( amd_iommu_perdev_intremap && amd_sp5100_erratum28() )
++        goto error_out;
++
+     ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
+ 
+     if ( !ivrs_bdf_entries )
+--- a/xen/drivers/passthrough/amd/iommu_intr.c
++++ b/xen/drivers/passthrough/amd/iommu_intr.c
+@@ -99,12 +99,12 @@ static void update_intremap_entry(u32* e
+ static void update_intremap_entry_from_ioapic(
+     int bdf,
+     struct amd_iommu *iommu,
+-    struct IO_APIC_route_entry *ioapic_rte)
++    const struct IO_APIC_route_entry *rte,
++    const struct IO_APIC_route_entry *old_rte)
+ {
+     unsigned long flags;
+     u32* entry;
+     u8 delivery_mode, dest, vector, dest_mode;
+-    struct IO_APIC_route_entry *rte = ioapic_rte;
+     int req_id;
+     spinlock_t *lock;
+     int offset;
+@@ -120,6 +120,14 @@ static void update_intremap_entry_from_i
+     spin_lock_irqsave(lock, flags);
+ 
+     offset = get_intremap_offset(vector, delivery_mode);
++    if ( old_rte )
++    {
++        int old_offset = get_intremap_offset(old_rte->vector,
++                                             old_rte->delivery_mode);
++
++        if ( offset != old_offset )
++            free_intremap_entry(iommu->seg, bdf, old_offset);
++    }
+     entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
+     update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
+ 
+@@ -188,6 +196,7 @@ int __init amd_iommu_setup_ioapic_remapp
+                 amd_iommu_flush_intremap(iommu, req_id);
+                 spin_unlock_irqrestore(&iommu->lock, flags);
+             }
++            set_bit(pin, ioapic_sbdf[IO_APIC_ID(apic)].pin_setup);
+         }
+     }
+     return 0;
+@@ -199,6 +208,7 @@ void amd_iommu_ioapic_update_ire(
+     struct IO_APIC_route_entry old_rte = { 0 };
+     struct IO_APIC_route_entry new_rte = { 0 };
+     unsigned int rte_lo = (reg & 1) ? reg - 1 : reg;
++    unsigned int pin = (reg - 0x10) / 2;
+     int saved_mask, seg, bdf;
+     struct amd_iommu *iommu;
+ 
+@@ -236,6 +246,14 @@ void amd_iommu_ioapic_update_ire(
+         *(((u32 *)&new_rte) + 1) = value;
+     }
+ 
++    if ( new_rte.mask &&
++         !test_bit(pin, ioapic_sbdf[IO_APIC_ID(apic)].pin_setup) )
++    {
++        ASSERT(saved_mask);
++        __io_apic_write(apic, reg, value);
++        return;
++    }
++
+     /* mask the interrupt while we change the intremap table */
+     if ( !saved_mask )
+     {
+@@ -244,7 +262,11 @@ void amd_iommu_ioapic_update_ire(
+     }
+ 
+     /* Update interrupt remapping entry */
+-    update_intremap_entry_from_ioapic(bdf, iommu, &new_rte);
++    update_intremap_entry_from_ioapic(
++        bdf, iommu, &new_rte,
++        test_and_set_bit(pin,
++                         ioapic_sbdf[IO_APIC_ID(apic)].pin_setup) ? &old_rte
++                                                                  : NULL);
+ 
+     /* Forward write access to IO-APIC RTE */
+     __io_apic_write(apic, reg, value);
+@@ -354,6 +376,12 @@ void amd_iommu_msi_msg_update_ire(
+         return;
+     }
+ 
++    if ( msi_desc->remap_index >= 0 )
++        update_intremap_entry_from_msi_msg(iommu, pdev, msi_desc, NULL);
++
++    if ( !msg )
++        return;
++
+     update_intremap_entry_from_msi_msg(iommu, pdev, msi_desc, msg);
+ }
+ 
+--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
++++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
+@@ -205,6 +205,8 @@ int __init amd_iov_detect(void)
+     {
+         printk("AMD-Vi: Not overriding irq_vector_map setting\n");
+     }
++    if ( !amd_iommu_perdev_intremap )
++        printk(XENLOG_WARNING "AMD-Vi: Using global interrupt remap table is not recommended (see XSA-36)!\n");
+     return scan_pci_devices();
+ }
+ 
+--- a/xen/drivers/passthrough/iommu.c
++++ b/xen/drivers/passthrough/iommu.c
+@@ -52,7 +52,7 @@ bool_t __read_mostly iommu_qinval = 1;
+ bool_t __read_mostly iommu_intremap = 1;
+ bool_t __read_mostly iommu_hap_pt_share = 1;
+ bool_t __read_mostly iommu_debug;
+-bool_t __read_mostly amd_iommu_perdev_intremap;
++bool_t __read_mostly amd_iommu_perdev_intremap = 1;
+ 
+ DEFINE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
+ 
+--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
++++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+@@ -100,6 +100,7 @@ void amd_iommu_read_msi_from_ire(
+ 
+ extern struct ioapic_sbdf {
+     u16 bdf, seg;
++    unsigned long *pin_setup;
+ } ioapic_sbdf[MAX_IO_APICS];
+ extern void *shared_intremap_table;
+ 
diff --git a/xsa38.patch b/xsa38.patch
new file mode 100644
index 0000000..f4a5dc0
--- /dev/null
+++ b/xsa38.patch
@@ -0,0 +1,73 @@
+diff --git a/tools/ocaml/libs/xb/partial.ml b/tools/ocaml/libs/xb/partial.ml
+index 3558889..d4d1c7b 100644
+--- a/tools/ocaml/libs/xb/partial.ml
++++ b/tools/ocaml/libs/xb/partial.ml
+@@ -27,8 +27,15 @@ external header_size: unit -> int = "stub_header_size"
+ external header_of_string_internal: string -> int * int * int * int
+          = "stub_header_of_string"
+ 
++let xenstore_payload_max = 4096 (* xen/include/public/io/xs_wire.h *)
++
+ let of_string s =
+ 	let tid, rid, opint, dlen = header_of_string_internal s in
++	(* A packet which is bigger than xenstore_payload_max is illegal.
++	   This will leave the guest connection is a bad state and will
++	   be hard to recover from without restarting the connection
++	   (ie rebooting the guest) *)
++	let dlen = min xenstore_payload_max dlen in
+ 	{
+ 		tid = tid;
+ 		rid = rid;
+@@ -38,6 +45,7 @@ let of_string s =
+ 	}
+ 
+ let append pkt s sz =
++	if pkt.len > 4096 then failwith "Buffer.add: cannot grow buffer";
+ 	Buffer.add_string pkt.buf (String.sub s 0 sz)
+ 
+ let to_complete pkt =
+diff --git a/tools/ocaml/libs/xb/xs_ring_stubs.c b/tools/ocaml/libs/xb/xs_ring_stubs.c
+index 00414c5..4888ac5 100644
+--- a/tools/ocaml/libs/xb/xs_ring_stubs.c
++++ b/tools/ocaml/libs/xb/xs_ring_stubs.c
+@@ -39,21 +39,23 @@ static int xs_ring_read(struct mmap_interface *interface,
+                              char *buffer, int len)
+ {
+ 	struct xenstore_domain_interface *intf = interface->addr;
+-	XENSTORE_RING_IDX cons, prod;
++	XENSTORE_RING_IDX cons, prod; /* offsets only */
+ 	int to_read;
+ 
+-	cons = intf->req_cons;
+-	prod = intf->req_prod;
++	cons = *(volatile uint32*)&intf->req_cons;
++	prod = *(volatile uint32*)&intf->req_prod;
+ 	xen_mb();
++	cons = MASK_XENSTORE_IDX(cons);
++	prod = MASK_XENSTORE_IDX(prod);
+ 	if (prod == cons)
+ 		return 0;
+-	if (MASK_XENSTORE_IDX(prod) > MASK_XENSTORE_IDX(cons)) 
++	if (prod > cons)
+ 		to_read = prod - cons;
+ 	else
+-		to_read = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
++		to_read = XENSTORE_RING_SIZE - cons;
+ 	if (to_read < len)
+ 		len = to_read;
+-	memcpy(buffer, intf->req + MASK_XENSTORE_IDX(cons), len);
++	memcpy(buffer, intf->req + cons, len);
+ 	xen_mb();
+ 	intf->req_cons += len;
+ 	return len;
+@@ -66,8 +68,8 @@ static int xs_ring_write(struct mmap_interface *interface,
+ 	XENSTORE_RING_IDX cons, prod;
+ 	int can_write;
+ 
+-	cons = intf->rsp_cons;
+-	prod = intf->rsp_prod;
++	cons = *(volatile uint32*)&intf->rsp_cons;
++	prod = *(volatile uint32*)&intf->rsp_prod;
+ 	xen_mb();
+ 	if ( (prod - cons) >= XENSTORE_RING_SIZE )
+ 		return 0;


More information about the scm-commits mailing list