~alpine/devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[alpine-devel] [PATCH] xen: add fixes for XSA-47, XSA-48, XSA-44 and XSA-46

Roger Pau Monne <roger.pau@citrix.com>
Details
Message ID
<1366295186-41139-1-git-send-email-roger.pau@citrix.com>
Sender timestamp
1366295186
DKIM signature
missing
Download raw message
Patch: +519 -0
---
Please run abuild checksum before committing.
---
 main/xen/APKBUILD                 |    4 +
 main/xen/xsa44-4.2.patch          |   77 ++++++++++
 main/xen/xsa46-4.2.patch          |  293 +++++++++++++++++++++++++++++++++++++
 main/xen/xsa47-4.2-unstable.patch |   31 ++++
 main/xen/xsa48-4.2.patch          |  114 ++++++++++++++
 5 files changed, 519 insertions(+), 0 deletions(-)
 create mode 100644 main/xen/xsa44-4.2.patch
 create mode 100644 main/xen/xsa46-4.2.patch
 create mode 100644 main/xen/xsa47-4.2-unstable.patch
 create mode 100644 main/xen/xsa48-4.2.patch

diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD
index 51ff406..122ac1a 100644
--- a/main/xen/APKBUILD
+++ b/main/xen/APKBUILD
@@ -26,6 +26,10 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g
	xsa35-4.2-with-xsa34.patch
	xsa36-4.2.patch
	xsa38.patch
	xsa47-4.2-unstable.patch
	xsa48-4.2.patch
	xsa44-4.2.patch
	xsa46-4.2.patch

	xenstored.initd
	xenstored.confd
diff --git a/main/xen/xsa44-4.2.patch b/main/xen/xsa44-4.2.patch
new file mode 100644
index 0000000..07ed938
--- /dev/null
+++ b/main/xen/xsa44-4.2.patch
@@ -0,0 +1,77 @@
x86: clear EFLAGS.NT in SYSENTER entry path

... as it causes problems if we happen to exit back via IRET: In the
course of trying to handle the fault, the hypervisor creates a stack
frame by hand, and uses PUSHFQ to set the respective EFLAGS field, but
expects to be able to IRET through that stack frame to the second
portion of the fixup code (which causes a #GP due to the stored EFLAGS
having NT set).

And even if this worked (e.g if we cleared NT in that path), it would
then (through the fail safe callback) cause a #GP in the guest with the
SYSENTER handler's first instruction as the source, which in turn would
allow guest user mode code to crash the guest kernel.

Inject a #GP on the fake (NULL) address of the SYSENTER instruction
instead, just like in the case where the guest kernel didn't register
a corresponding entry point.

On 32-bit we also need to make sure we clear SYSENTER_CS for all CPUs
(neither #RESET nor #INIT guarantee this).

This is CVE-2013-1917 / XSA-44.

Reported-by: Andrew Cooper <andrew.cooper3@citirx.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/acpi/suspend.c
+++ b/xen/arch/x86/acpi/suspend.c
@@ -81,8 +81,12 @@ void restore_rest_processor_state(void)
     }
 
 #else /* !defined(CONFIG_X86_64) */
-    if ( supervisor_mode_kernel && cpu_has_sep )
-        wrmsr(MSR_IA32_SYSENTER_ESP, &this_cpu(init_tss).esp1, 0);
+    if ( cpu_has_sep )
+    {
+        wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+        if ( supervisor_mode_kernel )
+            wrmsr(MSR_IA32_SYSENTER_ESP, &this_cpu(init_tss).esp1, 0);
+    }
 #endif
 
     /* Maybe load the debug registers. */
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -655,8 +655,11 @@ void __cpuinit cpu_init(void)
 #if defined(CONFIG_X86_32)
 	t->ss0  = __HYPERVISOR_DS;
 	t->esp0 = get_stack_bottom();
-	if ( supervisor_mode_kernel && cpu_has_sep )
+	if ( cpu_has_sep ) {
+	    wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+	    if ( supervisor_mode_kernel )
 		wrmsr(MSR_IA32_SYSENTER_ESP, &t->esp1, 0);
+	}
 #elif defined(CONFIG_X86_64)
 	/* Bottom-of-stack must be 16-byte aligned! */
 	BUG_ON((get_stack_bottom() & 15) != 0);
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -284,7 +284,14 @@ sysenter_eflags_saved:
         cmpb  $0,VCPU_sysenter_disables_events(%rbx)
         movq  VCPU_sysenter_addr(%rbx),%rax
         setne %cl
+        testl $X86_EFLAGS_NT,UREGS_eflags(%rsp)
         leaq  VCPU_trap_bounce(%rbx),%rdx
+UNLIKELY_START(nz, sysenter_nt_set)
+        pushfq
+        andl  $~X86_EFLAGS_NT,(%rsp)
+        popfq
+        xorl  %eax,%eax
+UNLIKELY_END(sysenter_nt_set)
         testq %rax,%rax
         leal  (,%rcx,TBF_INTERRUPT),%ecx
 UNLIKELY_START(z, sysenter_gpf)
diff --git a/main/xen/xsa46-4.2.patch b/main/xen/xsa46-4.2.patch
new file mode 100644
index 0000000..9448ea9
--- /dev/null
+++ b/main/xen/xsa46-4.2.patch
@@ -0,0 +1,293 @@
x86: fix various issues with handling guest IRQs

- properly revoke IRQ access in map_domain_pirq() error path
- don't permit replacing an in use IRQ
- don't accept inputs in the GSI range for MAP_PIRQ_TYPE_MSI
- track IRQ access permission in host IRQ terms, not guest IRQ ones
  (and with that, also disallow Dom0 access to IRQ0)

This is CVE-2013-1919 / XSA-46.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -968,14 +968,16 @@ static void domcreate_launch_dm(libxl__e
     }
 
     for (i = 0; i < d_config->b_info.num_irqs; i++) {
-        uint32_t irq = d_config->b_info.irqs[i];
+        int irq = d_config->b_info.irqs[i];
 
-        LOG(DEBUG, "dom%d irq %"PRIx32, domid, irq);
+        LOG(DEBUG, "dom%d irq %d", domid, irq);
 
-        ret = xc_domain_irq_permission(CTX->xch, domid, irq, 1);
+        ret = irq >= 0 ? xc_physdev_map_pirq(CTX->xch, domid, irq, &irq)
+                       : -EOVERFLOW;
+        if (!ret)
+            ret = xc_domain_irq_permission(CTX->xch, domid, irq, 1);
         if ( ret<0 ){
-            LOGE(ERROR,
-                 "failed give dom%d access to irq %"PRId32, domid, irq);
+            LOGE(ERROR, "failed give dom%d access to irq %d", domid, irq);
             ret = ERROR_FAIL;
         }
     }
--- a/tools/python/xen/xend/server/irqif.py
+++ b/tools/python/xen/xend/server/irqif.py
@@ -73,6 +73,12 @@ class IRQController(DevController):
        
         pirq = get_param('irq')
 
+        rc = xc.physdev_map_pirq(domid = self.getDomid(),
+                                 index = pirq,
+                                 pirq  = pirq)
+        if rc < 0:
+            raise VmError('irq: Failed to map irq %x' % (pirq))
+
         rc = xc.domain_irq_permission(domid        = self.getDomid(),
                                       pirq         = pirq,
                                       allow_access = True)
@@ -81,12 +87,6 @@ class IRQController(DevController):
             #todo non-fatal
             raise VmError(
                 'irq: Failed to configure irq: %d' % (pirq))
-        rc = xc.physdev_map_pirq(domid = self.getDomid(),
-                                index = pirq,
-                                pirq  = pirq)
-        if rc < 0:
-            raise VmError(
-                'irq: Failed to map irq %x' % (pirq))
         back = dict([(k, config[k]) for k in self.valid_cfg if k in config])
         return (self.allocateDeviceID(), back, {})
 
--- a/xen/arch/x86/domain_build.c
+++ b/xen/arch/x86/domain_build.c
@@ -1219,7 +1219,7 @@ int __init construct_dom0(
     /* DOM0 is permitted full I/O capabilities. */
     rc |= ioports_permit_access(dom0, 0, 0xFFFF);
     rc |= iomem_permit_access(dom0, 0UL, ~0UL);
-    rc |= irqs_permit_access(dom0, 0, d->nr_pirqs - 1);
+    rc |= irqs_permit_access(dom0, 1, nr_irqs_gsi - 1);
 
     /*
      * Modify I/O port access permissions.
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -772,9 +772,13 @@ long arch_do_domctl(
             goto bind_out;
 
         ret = -EPERM;
-        if ( !IS_PRIV(current->domain) &&
-             !irq_access_permitted(current->domain, bind->machine_irq) )
-            goto bind_out;
+        if ( !IS_PRIV(current->domain) )
+        {
+            int irq = domain_pirq_to_irq(d, bind->machine_irq);
+
+            if ( irq <= 0 || !irq_access_permitted(current->domain, irq) )
+                goto bind_out;
+        }
 
         ret = -ESRCH;
         if ( iommu_enabled )
@@ -803,9 +807,13 @@ long arch_do_domctl(
         bind = &(domctl->u.bind_pt_irq);
 
         ret = -EPERM;
-        if ( !IS_PRIV(current->domain) &&
-             !irq_access_permitted(current->domain, bind->machine_irq) )
-            goto unbind_out;
+        if ( !IS_PRIV(current->domain) )
+        {
+            int irq = domain_pirq_to_irq(d, bind->machine_irq);
+
+            if ( irq <= 0 || !irq_access_permitted(current->domain, irq) )
+                goto unbind_out;
+        }
 
         if ( iommu_enabled )
         {
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -184,6 +184,14 @@ int create_irq(int node)
         desc->arch.used = IRQ_UNUSED;
         irq = ret;
     }
+    else if ( dom0 )
+    {
+        ret = irq_permit_access(dom0, irq);
+        if ( ret )
+            printk(XENLOG_G_ERR
+                   "Could not grant Dom0 access to IRQ%d (error %d)\n",
+                   irq, ret);
+    }
 
     return irq;
 }
@@ -280,6 +288,17 @@ void clear_irq_vector(int irq)
 void destroy_irq(unsigned int irq)
 {
     BUG_ON(!MSI_IRQ(irq));
+
+    if ( dom0 )
+    {
+        int err = irq_deny_access(dom0, irq);
+
+        if ( err )
+            printk(XENLOG_G_ERR
+                   "Could not revoke Dom0 access to IRQ%u (error %d)\n",
+                   irq, err);
+    }
+
     dynamic_irq_cleanup(irq);
     clear_irq_vector(irq);
 }
@@ -1858,7 +1877,7 @@ int map_domain_pirq(
 
     if ( !IS_PRIV(current->domain) &&
          !(IS_PRIV_FOR(current->domain, d) &&
-           irq_access_permitted(current->domain, pirq)))
+           irq_access_permitted(current->domain, irq)))
         return -EPERM;
 
     if ( pirq < 0 || pirq >= d->nr_pirqs || irq < 0 || irq >= nr_irqs )
@@ -1887,17 +1906,18 @@ int map_domain_pirq(
         return ret;
     }
 
-    ret = irq_permit_access(d, pirq);
+    ret = irq_permit_access(d, irq);
     if ( ret )
     {
-        dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d\n",
-                d->domain_id, pirq);
+        printk(XENLOG_G_ERR
+               "dom%d: could not permit access to IRQ%d (pirq %d)\n",
+               d->domain_id, irq, pirq);
         return ret;
     }
 
     ret = prepare_domain_irq_pirq(d, irq, pirq, &info);
     if ( ret )
-        return ret;
+        goto revoke;
 
     desc = irq_to_desc(irq);
 
@@ -1921,8 +1941,14 @@ int map_domain_pirq(
         spin_lock_irqsave(&desc->lock, flags);
 
         if ( desc->handler != &no_irq_type )
+        {
+            spin_unlock_irqrestore(&desc->lock, flags);
             dprintk(XENLOG_G_ERR, "dom%d: irq %d in use\n",
                     d->domain_id, irq);
+            pci_disable_msi(msi_desc);
+            ret = -EBUSY;
+            goto done;
+        }
         setup_msi_handler(desc, msi_desc);
 
         if ( opt_irq_vector_map == OPT_IRQ_VECTOR_MAP_PERDEV
@@ -1951,7 +1977,14 @@ int map_domain_pirq(
 
 done:
     if ( ret )
+    {
         cleanup_domain_irq_pirq(d, irq, info);
+ revoke:
+        if ( irq_deny_access(d, irq) )
+            printk(XENLOG_G_ERR
+                   "dom%d: could not revoke access to IRQ%d (pirq %d)\n",
+                   d->domain_id, irq, pirq);
+    }
     return ret;
 }
 
@@ -2017,10 +2050,11 @@ int unmap_domain_pirq(struct domain *d, 
     if ( !forced_unbind )
         cleanup_domain_irq_pirq(d, irq, info);
 
-    ret = irq_deny_access(d, pirq);
+    ret = irq_deny_access(d, irq);
     if ( ret )
-        dprintk(XENLOG_G_ERR, "dom%d: could not deny access to irq %d\n",
-                d->domain_id, pirq);
+        printk(XENLOG_G_ERR
+               "dom%d: could not deny access to IRQ%d (pirq %d)\n",
+               d->domain_id, irq, pirq);
 
  done:
     return ret;
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -147,7 +147,7 @@ int physdev_map_pirq(domid_t domid, int 
         if ( irq == -1 )
             irq = create_irq(NUMA_NO_NODE);
 
-        if ( irq < 0 || irq >= nr_irqs )
+        if ( irq < nr_irqs_gsi || irq >= nr_irqs )
         {
             dprintk(XENLOG_G_ERR, "dom%d: can't create irq for msi!\n",
                     d->domain_id);
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -25,6 +25,7 @@
 #include <xen/paging.h>
 #include <xen/hypercall.h>
 #include <asm/current.h>
+#include <asm/irq.h>
 #include <asm/page.h>
 #include <public/domctl.h>
 #include <xsm/xsm.h>
@@ -897,9 +898,9 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
         else if ( xsm_irq_permission(d, pirq, allow) )
             ret = -EPERM;
         else if ( allow )
-            ret = irq_permit_access(d, pirq);
+            ret = pirq_permit_access(d, pirq);
         else
-            ret = irq_deny_access(d, pirq);
+            ret = pirq_deny_access(d, pirq);
 
         rcu_unlock_domain(d);
     }
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -369,7 +369,7 @@ static long evtchn_bind_pirq(evtchn_bind
     if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
         return -EINVAL;
 
-    if ( !is_hvm_domain(d) && !irq_access_permitted(d, pirq) )
+    if ( !is_hvm_domain(d) && !pirq_access_permitted(d, pirq) )
         return -EPERM;
 
     spin_lock(&d->event_lock);
--- a/xen/include/xen/iocap.h
+++ b/xen/include/xen/iocap.h
@@ -28,4 +28,22 @@
 #define irq_access_permitted(d, i)                      \
     rangeset_contains_singleton((d)->irq_caps, i)
 
+#define pirq_permit_access(d, i) ({                     \
+    struct domain *d__ = (d);                           \
+    int i__ = domain_pirq_to_irq(d__, i);               \
+    i__ > 0 ? rangeset_add_singleton(d__->irq_caps, i__)\
+            : -EINVAL;                                  \
+})
+#define pirq_deny_access(d, i) ({                       \
+    struct domain *d__ = (d);                           \
+    int i__ = domain_pirq_to_irq(d__, i);               \
+    i__ > 0 ? rangeset_remove_singleton(d__->irq_caps, i__)\
+            : -EINVAL;                                  \
+})
+#define pirq_access_permitted(d, i) ({                  \
+    struct domain *d__ = (d);                           \
+    rangeset_contains_singleton(d__->irq_caps,          \
+                                domain_pirq_to_irq(d__, i));\
+})
+
 #endif /* __XEN_IOCAP_H__ */
diff --git a/main/xen/xsa47-4.2-unstable.patch b/main/xen/xsa47-4.2-unstable.patch
new file mode 100644
index 0000000..7ebb8c8
--- /dev/null
+++ b/main/xen/xsa47-4.2-unstable.patch
@@ -0,0 +1,31 @@
defer event channel bucket pointer store until after XSM checks

Otherwise a dangling pointer can be left, which would cause subsequent
memory corruption as soon as the space got re-allocated for some other
purpose.

This is CVE-2013-1920 / XSA-47.

Reported-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Tim Deegan <tim@xen.org>

--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -140,7 +140,6 @@ static int get_free_port(struct domain *
     chn = xzalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
     if ( unlikely(chn == NULL) )
         return -ENOMEM;
-    bucket_from_port(d, port) = chn;
 
     for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ )
     {
@@ -153,6 +152,8 @@ static int get_free_port(struct domain *
         }
     }
 
+    bucket_from_port(d, port) = chn;
+
     return port;
 }
 
diff --git a/main/xen/xsa48-4.2.patch b/main/xen/xsa48-4.2.patch
new file mode 100644
index 0000000..c44806e
--- /dev/null
+++ b/main/xen/xsa48-4.2.patch
@@ -0,0 +1,114 @@
Add -f FMT  / --format FMT arg to qemu-nbd

From: "Daniel P. Berrange" <berrange@redhat.com>

Currently the qemu-nbd program will auto-detect the format of
any disk it is given. This behaviour is known to be insecure.
For example, if qemu-nbd initially exposes a 'raw' file to an
unprivileged app, and that app runs

   'qemu-img create -f qcow2 -o backing_file=/etc/shadow /dev/nbd0'

then the next time the app is started, the qemu-nbd will now
detect it as a 'qcow2' file and expose /etc/shadow to the
unprivileged app.

The only way to avoid this is to explicitly tell qemu-nbd what
disk format to use on the command line, completely disabling
auto-detection. This patch adds a '-f' / '--format' arg for
this purpose, mirroring what is already available via qemu-img
and qemu commands.

  qemu-nbd --format raw -p 9000 evil.img

will now always use raw, regardless of what format 'evil.img'
looks like it contains

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
[Use errx, not err. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

[ This is a security issue, CVE-2013-1922 / XSA-48. ]

diff --git a/qemu-nbd.c b/qemu-nbd.c
index 291cba2..8fbe2cf 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -247,6 +247,7 @@ out:
 int main(int argc, char **argv)
 {
     BlockDriverState *bs;
+    BlockDriver *drv;
     off_t dev_offset = 0;
     off_t offset = 0;
     uint32_t nbdflags = 0;
@@ -256,7 +257,7 @@ int main(int argc, char **argv)
     struct sockaddr_in addr;
     socklen_t addr_len = sizeof(addr);
     off_t fd_size;
-    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
+    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t";
     struct option lopt[] = {
         { "help", 0, NULL, 'h' },
         { "version", 0, NULL, 'V' },
@@ -271,6 +272,7 @@ int main(int argc, char **argv)
         { "snapshot", 0, NULL, 's' },
         { "nocache", 0, NULL, 'n' },
         { "shared", 1, NULL, 'e' },
+        { "format", 1, NULL, 'f' },
         { "persistent", 0, NULL, 't' },
         { "verbose", 0, NULL, 'v' },
         { NULL, 0, NULL, 0 }
@@ -292,6 +294,7 @@ int main(int argc, char **argv)
     int max_fd;
     int persistent = 0;
     pthread_t client_thread;
+    const char *fmt = NULL;
 
     /* The client thread uses SIGTERM to interrupt the server.  A signal
      * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -368,6 +371,9 @@ int main(int argc, char **argv)
                 errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
             }
             break;
+        case 'f':
+            fmt = optarg;
+            break;
 	case 't':
 	    persistent = 1;
 	    break;
@@ -478,9 +484,19 @@ int main(int argc, char **argv)
     bdrv_init();
     atexit(bdrv_close_all);
 
+    if (fmt) {
+        drv = bdrv_find_format(fmt);
+        if (!drv) {
+            errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
+        }
+    } else {
+        drv = NULL;
+    }
+
     bs = bdrv_new("hda");
     srcpath = argv[optind];
-    if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
+    ret = bdrv_open(bs, srcpath, flags, drv);
+    if (ret < 0) {
         errno = -ret;
         err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
     }
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 44996cc..f56c68e 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -36,6 +36,8 @@ Export Qemu disk image using NBD protocol.
   disconnect the specified device
 @item -e, --shared=@var{num}
   device can be shared by @var{num} clients (default @samp{1})
+@item -f, --format=@var{fmt}
+  force block driver for format @var{fmt} instead of auto-detecting
 @item -t, --persistent
   don't exit on the last connection
 @item -v, --verbose
-- 
1.7.7.5 (Apple Git-26)



---
Unsubscribe:  alpine-devel+unsubscribe@lists.alpinelinux.org
Help:         alpine-devel+help@lists.alpinelinux.org
---
Reply to thread Export thread (mbox)