From 9ed49310c49191170b5761ca9959414e91e6f5c9 Mon Sep 17 00:00:00 2001 From: Jacek Konieczny Date: Wed, 18 Jun 2014 10:23:42 +0200 Subject: [PATCH] security fixes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - XSA-92 – CVE-2014-3124 - XSA-96 – CVE-2014-3967, CVE-2014-3968 - XSA-99 – none (yet) assigned --- xen.spec | 7 ++ xsa92.patch | 36 ++++++++ xsa96.patch | 38 ++++++++ xsa99.patch | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 xsa92.patch create mode 100644 xsa96.patch create mode 100644 xsa99.patch diff --git a/xen.spec b/xen.spec index 9f8155b..2ffa5ed 100644 --- a/xen.spec +++ b/xen.spec @@ -111,6 +111,10 @@ Patch14: %{name}-no_fetcher.patch Patch15: odd-glib2-fix.patch Patch16: CVE-2014-2599.patch Patch17: %{name}-pvh_fixes.patch +Patch18: http://xenbits.xen.org/xsa/xsa92.patch +Patch19: http://xenbits.xen.org/xsa/xsa96.patch +# based on: http://xenbits.xen.org/xsa/xsa99.patch +Patch20: xsa99.patch URL: http://www.xen.org/products/xenhyp.html %if %{with qemu_traditional} %{?with_opengl:BuildRequires: OpenGL-devel} @@ -417,6 +421,9 @@ Nadzorca Xen w postaci, która może być uruchomiona wprost z firmware %patch15 -p1 %patch16 -p1 %patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 # stubdom sources ln -s %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} stubdom diff --git a/xsa92.patch b/xsa92.patch new file mode 100644 index 0000000..60ef934 --- /dev/null +++ b/xsa92.patch @@ -0,0 +1,36 @@ +x86/HVM: restrict HVMOP_set_mem_type + +Permitting arbitrary type changes here has the potential of creating +present P2M (and hence EPT/NPT/IOMMU) entries pointing to an invalid +MFN (INVALID_MFN truncated to the respective hardware structure field's +width). This would become a problem the latest when something real sat +at the end of the physical address space; I'm suspecting though that +other things might break with such bogus entries. + +Along with that drop a bogus (and otherwise becoming stale) log +message. + +Afaict the similar operation in p2m_set_mem_access() is safe. + +This is XSA-92. + +Signed-off-by: Jan Beulich +Reviewed-by: Tim Deegan + +--- a/xen/arch/x86/hvm/hvm.c ++++ b/xen/arch/x86/hvm/hvm.c +@@ -4541,12 +4541,10 @@ long do_hvm_op(unsigned long op, XEN_GUE + rc = -EINVAL; + goto param_fail4; + } +- if ( p2m_is_grant(t) ) ++ if ( !p2m_is_ram(t) && ++ (!p2m_is_hole(t) || a.hvmmem_type != HVMMEM_mmio_dm) ) + { + put_gfn(d, pfn); +- gdprintk(XENLOG_WARNING, +- "type for pfn %#lx changed to grant while " +- "we were working?\n", pfn); + goto param_fail4; + } + else diff --git a/xsa96.patch b/xsa96.patch new file mode 100644 index 0000000..ef6443f --- /dev/null +++ b/xsa96.patch @@ -0,0 +1,38 @@ +x86/HVM: eliminate vulnerabilities from hvm_inject_msi() + +- pirq_info() returns NULL for a non-allocated pIRQ, and hence we + mustn't unconditionally de-reference it, and we need to invoke it + another time after having called map_domain_emuirq_pirq() +- don't use printk(), namely without XENLOG_GUEST, for error reporting + +This is XSA-96. + +Signed-off-by: Jan Beulich + +--- a/xen/arch/x86/hvm/irq.c ++++ b/xen/arch/x86/hvm/irq.c +@@ -289,20 +289,18 @@ void hvm_inject_msi(struct domain *d, ui + struct pirq *info = pirq_info(d, pirq); + + /* if it is the first time, allocate the pirq */ +- if (info->arch.hvm.emuirq == IRQ_UNBOUND) ++ if ( !info || info->arch.hvm.emuirq == IRQ_UNBOUND ) + { + spin_lock(&d->event_lock); + map_domain_emuirq_pirq(d, pirq, IRQ_MSI_EMU); + spin_unlock(&d->event_lock); ++ info = pirq_info(d, pirq); ++ if ( !info ) ++ return; + } else if (info->arch.hvm.emuirq != IRQ_MSI_EMU) +- { +- printk("%s: pirq %d does not correspond to an emulated MSI\n", __func__, pirq); + return; +- } + send_guest_pirq(d, info); + return; +- } else { +- printk("%s: error getting pirq from MSI: pirq = %d\n", __func__, pirq); + } + } + diff --git a/xsa99.patch b/xsa99.patch new file mode 100644 index 0000000..14e58f4 --- /dev/null +++ b/xsa99.patch @@ -0,0 +1,257 @@ +diff -durN -x '*~' -x '*.orig' -x '*.rej' xen-4.4.0.orig/tools/libxc/xc_mem_access.c xen-4.4.0/tools/libxc/xc_mem_access.c +--- xen-4.4.0.orig/tools/libxc/xc_mem_access.c 2014-03-10 11:43:57.000000000 +0100 ++++ xen-4.4.0/tools/libxc/xc_mem_access.c 2014-06-18 10:19:54.000000000 +0200 +@@ -24,19 +24,9 @@ + #include "xc_private.h" + + +-int xc_mem_access_enable(xc_interface *xch, domid_t domain_id, +- uint32_t *port) ++void *xc_mem_access_enable(xc_interface *xch, domid_t domain_id, uint32_t *port) + { +- if ( !port ) +- { +- errno = EINVAL; +- return -1; +- } +- +- return xc_mem_event_control(xch, domain_id, +- XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE, +- XEN_DOMCTL_MEM_EVENT_OP_ACCESS, +- port); ++ return xc_mem_event_enable(xch, domain_id, HVM_PARAM_ACCESS_RING_PFN, port); + } + + int xc_mem_access_disable(xc_interface *xch, domid_t domain_id) +diff -durN -x '*~' -x '*.orig' -x '*.rej' xen-4.4.0.orig/tools/libxc/xc_mem_event.c xen-4.4.0/tools/libxc/xc_mem_event.c +--- xen-4.4.0.orig/tools/libxc/xc_mem_event.c 2014-03-10 11:43:57.000000000 +0100 ++++ xen-4.4.0/tools/libxc/xc_mem_event.c 2014-06-18 10:19:54.000000000 +0200 +@@ -56,3 +56,118 @@ + return do_memory_op(xch, mode, &meo, sizeof(meo)); + } + ++void *xc_mem_event_enable(xc_interface *xch, domid_t domain_id, int param, ++ uint32_t *port) ++{ ++ void *ring_page = NULL; ++ unsigned long ring_pfn, mmap_pfn; ++ unsigned int op, mode; ++ int rc1, rc2, saved_errno; ++ ++ if ( !port ) ++ { ++ errno = EINVAL; ++ return NULL; ++ } ++ ++ /* Pause the domain for ring page setup */ ++ rc1 = xc_domain_pause(xch, domain_id); ++ if ( rc1 != 0 ) ++ { ++ PERROR("Unable to pause domain\n"); ++ return NULL; ++ } ++ ++ /* Get the pfn of the ring page */ ++ rc1 = xc_get_hvm_param(xch, domain_id, param, &ring_pfn); ++ if ( rc1 != 0 ) ++ { ++ PERROR("Failed to get pfn of ring page\n"); ++ goto out; ++ } ++ ++ mmap_pfn = ring_pfn; ++ ring_page = xc_map_foreign_batch(xch, domain_id, PROT_READ | PROT_WRITE, ++ &mmap_pfn, 1); ++ if ( mmap_pfn & XEN_DOMCTL_PFINFO_XTAB ) ++ { ++ /* Map failed, populate ring page */ ++ rc1 = xc_domain_populate_physmap_exact(xch, domain_id, 1, 0, 0, ++ &ring_pfn); ++ if ( rc1 != 0 ) ++ { ++ PERROR("Failed to populate ring pfn\n"); ++ goto out; ++ } ++ ++ mmap_pfn = ring_pfn; ++ ring_page = xc_map_foreign_batch(xch, domain_id, PROT_READ | PROT_WRITE, ++ &mmap_pfn, 1); ++ if ( mmap_pfn & XEN_DOMCTL_PFINFO_XTAB ) ++ { ++ PERROR("Could not map the ring page\n"); ++ goto out; ++ } ++ } ++ ++ switch ( param ) ++ { ++ case HVM_PARAM_PAGING_RING_PFN: ++ op = XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE; ++ mode = XEN_DOMCTL_MEM_EVENT_OP_PAGING; ++ break; ++ ++ case HVM_PARAM_ACCESS_RING_PFN: ++ op = XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE; ++ mode = XEN_DOMCTL_MEM_EVENT_OP_ACCESS; ++ break; ++ ++ case HVM_PARAM_SHARING_RING_PFN: ++ op = XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE; ++ mode = XEN_DOMCTL_MEM_EVENT_OP_SHARING; ++ break; ++ ++ /* ++ * This is for the outside chance that the HVM_PARAM is valid but is invalid ++ * as far as mem_event goes. ++ */ ++ default: ++ errno = EINVAL; ++ rc1 = -1; ++ goto out; ++ } ++ ++ rc1 = xc_mem_event_control(xch, domain_id, op, mode, port); ++ if ( rc1 != 0 ) ++ { ++ PERROR("Failed to enable mem_event\n"); ++ goto out; ++ } ++ ++ /* Remove the ring_pfn from the guest's physmap */ ++ rc1 = xc_domain_decrease_reservation_exact(xch, domain_id, 1, 0, &ring_pfn); ++ if ( rc1 != 0 ) ++ PERROR("Failed to remove ring page from guest physmap"); ++ ++ out: ++ saved_errno = errno; ++ ++ rc2 = xc_domain_unpause(xch, domain_id); ++ if ( rc1 != 0 || rc2 != 0 ) ++ { ++ if ( rc2 != 0 ) ++ { ++ if ( rc1 == 0 ) ++ saved_errno = errno; ++ PERROR("Unable to unpause domain"); ++ } ++ ++ if ( ring_page ) ++ munmap(ring_page, XC_PAGE_SIZE); ++ ring_page = NULL; ++ ++ errno = saved_errno; ++ } ++ ++ return ring_page; ++} +diff -durN -x '*~' -x '*.orig' -x '*.rej' xen-4.4.0.orig/tools/libxc/xenctrl.h xen-4.4.0/tools/libxc/xenctrl.h +--- xen-4.4.0.orig/tools/libxc/xenctrl.h 2014-03-10 11:43:57.000000000 +0100 ++++ xen-4.4.0/tools/libxc/xenctrl.h 2014-06-18 10:19:54.000000000 +0200 +@@ -2040,6 +2040,12 @@ + int xc_mem_event_memop(xc_interface *xch, domid_t domain_id, + unsigned int op, unsigned int mode, + uint64_t gfn, void *buffer); ++/* ++ * Enables mem_event and returns the mapped ring page indicated by param. ++ * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN ++ */ ++void *xc_mem_event_enable(xc_interface *xch, domid_t domain_id, int param, ++ uint32_t *port); + + /** + * Mem paging operations. +@@ -2060,7 +2066,13 @@ + * Access tracking operations. + * Supported only on Intel EPT 64 bit processors. + */ +-int xc_mem_access_enable(xc_interface *xch, domid_t domain_id, uint32_t *port); ++ ++/* ++ * Enables mem_access and returns the mapped ring page. ++ * Will return NULL on error. ++ * Caller has to unmap this page when done. ++ */ ++void *xc_mem_access_enable(xc_interface *xch, domid_t domain_id, uint32_t *port); + int xc_mem_access_disable(xc_interface *xch, domid_t domain_id); + int xc_mem_access_resume(xc_interface *xch, domid_t domain_id, + unsigned long gfn); +diff -durN -x '*~' -x '*.orig' -x '*.rej' xen-4.4.0.orig/tools/tests/xen-access/xen-access.c xen-4.4.0/tools/tests/xen-access/xen-access.c +--- xen-4.4.0.orig/tools/tests/xen-access/xen-access.c 2014-03-10 11:43:57.000000000 +0100 ++++ xen-4.4.0/tools/tests/xen-access/xen-access.c 2014-06-18 10:20:55.000000000 +0200 +@@ -231,7 +231,6 @@ + xenaccess_t *xenaccess = 0; + xc_interface *xch; + int rc; +- unsigned long ring_pfn, mmap_pfn; + + xch = xc_interface_open(NULL, NULL, 0); + if ( !xch ) +@@ -253,40 +252,12 @@ + /* Initialise lock */ + mem_event_ring_lock_init(&xenaccess->mem_event); + +- /* Map the ring page */ +- xc_get_hvm_param(xch, xenaccess->mem_event.domain_id, +- HVM_PARAM_ACCESS_RING_PFN, &ring_pfn); +- mmap_pfn = ring_pfn; +- xenaccess->mem_event.ring_page = +- xc_map_foreign_batch(xch, xenaccess->mem_event.domain_id, +- PROT_READ | PROT_WRITE, &mmap_pfn, 1); +- if ( mmap_pfn & XEN_DOMCTL_PFINFO_XTAB ) +- { +- /* Map failed, populate ring page */ +- rc = xc_domain_populate_physmap_exact(xenaccess->xc_handle, +- xenaccess->mem_event.domain_id, +- 1, 0, 0, &ring_pfn); +- if ( rc != 0 ) +- { +- PERROR("Failed to populate ring gfn\n"); +- goto err; +- } +- +- mmap_pfn = ring_pfn; +- xenaccess->mem_event.ring_page = +- xc_map_foreign_batch(xch, xenaccess->mem_event.domain_id, +- PROT_READ | PROT_WRITE, &mmap_pfn, 1); +- if ( mmap_pfn & XEN_DOMCTL_PFINFO_XTAB ) +- { +- PERROR("Could not map the ring page\n"); +- goto err; +- } +- } +- +- /* Initialise Xen */ +- rc = xc_mem_access_enable(xenaccess->xc_handle, xenaccess->mem_event.domain_id, +- &xenaccess->mem_event.evtchn_port); +- if ( rc != 0 ) ++ /* Enable mem_access */ ++ xenaccess->mem_event.ring_page = ++ xc_mem_access_enable(xenaccess->xc_handle, ++ xenaccess->mem_event.domain_id, ++ &xenaccess->mem_event.evtchn_port); ++ if ( xenaccess->mem_event.ring_page == NULL ) + { + switch ( errno ) { + case EBUSY: +@@ -296,7 +267,7 @@ + ERROR("EPT not supported for this guest"); + break; + default: +- perror("Error initialising shared page"); ++ perror("Error enabling mem_access"); + break; + } + goto err; +@@ -330,11 +301,6 @@ + (mem_event_sring_t *)xenaccess->mem_event.ring_page, + PAGE_SIZE); + +- /* Now that the ring is set, remove it from the guest's physmap */ +- if ( xc_domain_decrease_reservation_exact(xch, +- xenaccess->mem_event.domain_id, 1, 0, &ring_pfn) ) +- PERROR("Failed to remove ring from guest physmap"); +- + /* Get platform info */ + xenaccess->platform_info = malloc(sizeof(xc_platform_info_t)); + if ( xenaccess->platform_info == NULL ) -- 2.44.0