From 25a05d703385a09feb95cce60c63b7078b013892 Mon Sep 17 00:00:00 2001
From: Tim Gardner <tim.gardner@canonical.com>
Date: Tue, 25 Jan 2011 14:54:33 -0700
Subject: [PATCH] UBUNTU: xen unified block-device I/O interface back end can orphan devices, CVE-2010-3699
CVE-2010-3699
BugLink: http://bugs.launchpad.net/bugs/???
Excerpted from http://rhn.redhat.com/errata/RHSA-2011-0004.html:
"A flaw was found in the Xenbus code for the unified block-device I/O
interface back end. A privileged guest user could use this flaw to cause a
denial of service on the host system running the Xen hypervisor."
Most of this patch was developed from http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/59f097ef181b.
A careful comparision of the patch and the actual contents of http://xenbits.xensource.com/linux-2.6.18-xen.hg
showed that part of the original patch introduced a regression as can be seen from the Mercurial log.
I've not implemented that piece of the patch.
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
.../xen/patchset/020-xen-CVE-2010-3699.patch | 187 ++++++++++++++++++++
1 files changed, 187 insertions(+), 0 deletions(-)
create mode 100644 debian/binary-custom.d/xen/patchset/020-xen-CVE-2010-3699.patch
new file mode 100644
@@ -0,0 +1,187 @@
+diff -Nurp custom-source-xen.orig/drivers/xen/blkback/xenbus.c custom-source-xen/drivers/xen/blkback/xenbus.c
+--- custom-source-xen.orig/drivers/xen/blkback/xenbus.c 2011-01-26 18:31:29.866234416 +0100
++++ custom-source-xen/drivers/xen/blkback/xenbus.c 2011-01-26 18:29:26.690234371 +0100
+@@ -362,6 +362,11 @@ static void frontend_changed(struct xenb
+ if (dev->state == XenbusStateConnected)
+ break;
+
++ /* Enforce precondition before potential leak point.
++ * blkif_disconnect() is idempotent.
++ */
++ blkif_disconnect(be->blkif);
++
+ err = connect_ring(be);
+ if (err)
+ break;
+@@ -379,6 +384,7 @@ static void frontend_changed(struct xenb
+ break;
+ /* fall through if not online */
+ case XenbusStateUnknown:
++ /* implies blkif_disconnect() via blkback_remove() */
+ device_unregister(&dev->dev);
+ break;
+
+diff -Nurp custom-source-xen.orig/drivers/xen/blktap/common.h custom-source-xen/drivers/xen/blktap/common.h
+--- custom-source-xen.orig/drivers/xen/blktap/common.h 2011-01-26 18:29:25.974232874 +0100
++++ custom-source-xen/drivers/xen/blktap/common.h 2011-01-26 18:32:10.622236863 +0100
+@@ -89,6 +89,7 @@ typedef struct blkif_st {
+
+ blkif_t *tap_alloc_blkif(domid_t domid);
+ void tap_blkif_free(blkif_t *blkif);
++void tap_blkif_kmem_cache_free(blkif_t *blkif);
+ int tap_blkif_map(blkif_t *blkif, unsigned long shared_page,
+ unsigned int evtchn);
+ void tap_blkif_unmap(blkif_t *blkif);
+diff -Nurp custom-source-xen.orig/drivers/xen/blktap/interface.c custom-source-xen/drivers/xen/blktap/interface.c
+--- custom-source-xen.orig/drivers/xen/blktap/interface.c 2011-01-26 18:31:29.882243505 +0100
++++ custom-source-xen/drivers/xen/blktap/interface.c 2011-01-26 18:29:26.690234371 +0100
+@@ -162,8 +162,15 @@ void tap_blkif_free(blkif_t *blkif)
+ {
+ atomic_dec(&blkif->refcnt);
+ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++ atomic_inc(&blkif->refcnt);
+
+ tap_blkif_unmap(blkif);
++}
++
++void tap_blkif_kmem_cache_free(blkif_t *blkif)
++{
++ if (!atomic_dec_and_test(&blkif->refcnt))
++ BUG();
+ kmem_cache_free(blkif_cachep, blkif);
+ }
+
+diff -Nurp custom-source-xen.orig/drivers/xen/blktap/xenbus.c custom-source-xen/drivers/xen/blktap/xenbus.c
+--- custom-source-xen.orig/drivers/xen/blktap/xenbus.c 2011-01-26 18:31:29.882243505 +0100
++++ custom-source-xen/drivers/xen/blktap/xenbus.c 2011-01-26 18:29:26.690234371 +0100
+@@ -183,6 +183,7 @@ static int blktap_remove(struct xenbus_d
+ kthread_stop(be->blkif->xenblkd);
+ signal_tapdisk(be->blkif->dev_num);
+ tap_blkif_free(be->blkif);
++ tap_blkif_kmem_cache_free(be->blkif);
+ be->blkif = NULL;
+ }
+ kfree(be);
+@@ -326,6 +327,18 @@ static void tap_backend_changed(struct x
+ tap_update_blkif_status(be->blkif);
+ }
+
++
++static void tap_blkif_disconnect(blkif_t *blkif)
++{
++ if (blkif->xenblkd) {
++ kthread_stop(blkif->xenblkd);
++ blkif->xenblkd = NULL;
++ }
++
++ /* idempotent */
++ tap_blkif_free(blkif);
++}
++
+ /**
+ * Callback received when the frontend's state changes.
+ */
+@@ -354,6 +367,11 @@ static void tap_frontend_changed(struct
+ if (dev->state == XenbusStateConnected)
+ break;
+
++ /* Enforce precondition before potential leak point.
++ * tap_blkif_disconnect() is idempotent.
++ */
++ tap_blkif_disconnect(be->blkif);
++
+ err = connect_ring(be);
+ if (err)
+ break;
+@@ -361,10 +379,7 @@ static void tap_frontend_changed(struct
+ break;
+
+ case XenbusStateClosing:
+- if (be->blkif->xenblkd) {
+- kthread_stop(be->blkif->xenblkd);
+- be->blkif->xenblkd = NULL;
+- }
++ tap_blkif_disconnect(be->blkif);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+@@ -374,6 +389,9 @@ static void tap_frontend_changed(struct
+ break;
+ /* fall through if not online */
+ case XenbusStateUnknown:
++ /* Implies the effects of blkif_disconnect() via
++ * blktap_remove().
++ */
+ device_unregister(&dev->dev);
+ break;
+
+diff -Nurp custom-source-xen.orig/drivers/xen/netback/xenbus.c custom-source-xen/drivers/xen/netback/xenbus.c
+--- custom-source-xen.orig/drivers/xen/netback/xenbus.c 2011-01-26 18:31:29.882243505 +0100
++++ custom-source-xen/drivers/xen/netback/xenbus.c 2011-01-26 18:29:26.690234371 +0100
+@@ -32,6 +32,7 @@
+ static int connect_rings(struct backend_info *);
+ static void connect(struct backend_info *);
+ static void backend_create_netif(struct backend_info *be);
++static void netback_disconnect(struct device *);
+
+ static int netback_remove(struct xenbus_device *dev)
+ {
+@@ -39,15 +40,22 @@ static int netback_remove(struct xenbus_
+
+ netback_remove_accelerators(be, dev);
+
+- if (be->netif) {
+- netif_disconnect(be->netif);
+- be->netif = NULL;
+- }
++ netback_disconnect(&dev->dev);
+ kfree(be);
+ dev->dev.driver_data = NULL;
+ return 0;
+ }
+
++static void netback_disconnect(struct device *xbdev_dev)
++{
++ struct backend_info *be = xbdev_dev->driver_data;
++
++ if (be->netif) {
++ kobject_uevent(&xbdev_dev->kobj, KOBJ_OFFLINE);
++ netif_disconnect(be->netif);
++ be->netif = NULL;
++ }
++}
+
+ /**
+ * Entry point to this code when a new device is created. Allocate the basic
+@@ -225,16 +233,17 @@ static void frontend_changed(struct xenb
+ break;
+
+ case XenbusStateConnected:
++ if (dev->state == XenbusStateConnected)
++ break;
++
++ /* backend_create_netif() is idempotent */
+ backend_create_netif(be);
+ if (be->netif)
+ connect(be);
+ break;
+
+ case XenbusStateClosing:
+- if (be->netif) {
+- netif_disconnect(be->netif);
+- be->netif = NULL;
+- }
++ netback_disconnect(&dev->dev);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+@@ -244,8 +253,7 @@ static void frontend_changed(struct xenb
+ break;
+ /* fall through if not online */
+ case XenbusStateUnknown:
+- if (be->netif != NULL)
+- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ /* implies netback_disconnect() via netback_remove() */
+ device_unregister(&dev->dev);
+ break;
+
--
1.7.0.4