X-Original-To: alpine-devel@lists.alpinelinux.org Delivered-To: alpine-devel@mail.alpinelinux.org Received: from SMTP.EU.CITRIX.COM (smtp.eu.citrix.com [46.33.159.39]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client certificate requested) by mail.alpinelinux.org (Postfix) with ESMTPS id 2FF28DC00BC for ; Thu, 18 Apr 2013 14:27:41 +0000 (UTC) X-IronPort-AV: E=Sophos;i="4.87,502,1363132800"; d="scan'208";a="3698954" Received: from lonpmailmx01.citrite.net ([10.30.203.162]) by LONPIPO01.EU.CITRIX.COM with ESMTP/TLS/RC4-MD5; 18 Apr 2013 14:27:40 +0000 Received: from localhost.localdomain (10.30.249.38) by LONPMAILMX01.citrite.net (10.30.203.162) with Microsoft SMTP Server id 8.3.298.1; Thu, 18 Apr 2013 15:27:38 +0100 From: Roger Pau Monne To: CC: Roger Pau Monne Subject: [alpine-devel] [PATCH] xen: add fixes for XSA-47, XSA-48, XSA-44 and XSA-46 Date: Thu, 18 Apr 2013 16:26:26 +0200 Message-ID: <1366295186-41139-1-git-send-email-roger.pau@citrix.com> X-Mailer: git-send-email 1.7.7.5 (Apple Git-26) X-Mailinglist: alpine-devel Precedence: list List-Id: Alpine Development List-Unsubscribe: List-Post: List-Help: List-Subscribe: MIME-Version: 1.0 Content-Type: text/plain --- 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 +Signed-off-by: Jan Beulich +Tested-by: Andrew Cooper +Acked-by: Andrew Cooper + +--- 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 +Acked-by: Stefano Stabellini + +--- 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 + #include + #include ++#include + #include + #include + #include +@@ -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 +Signed-off-by: Jan Beulich +Reviewed-by: Tim Deegan + +--- 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" + +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 +[Use errx, not err. - Paolo] +Signed-off-by: Paolo Bonzini +Signed-off-by: Stefano Stabellini + +[ 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 ---