[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] blkback/blktap/netback: Fix CVE-2010-3699



# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1290520718 0
# Node ID 59f097ef181b2d131fdc72a56071b964d771bcaa
# Parent  26562626c866026c62c4be83b4c4c87b4cdc31a4
blkback/blktap/netback: Fix CVE-2010-3699

A guest can cause the backend driver to leak a kernel
thread. Such leaked threads hold references to the device, whichmakes
the device impossible to tear down. If shut down, the guest remains a
zombie domain, the xenwatch process hangs, and most xm commands will
stop working.

This patch tries to do the following, for all of netback, blkback,
blktap:
    - identify/extract idempotent teardown operations,
    - add/move the invocation of said teardown operation
      right before we're about to allocate new resources in the
      Connected states.

Signed-off-by: Laszlo Ersek <lersek@xxxxxxxxxx>
---
 drivers/xen/blkback/xenbus.c |    6 ++++++
 drivers/xen/blktap/xenbus.c  |   26 +++++++++++++++++++++-----
 drivers/xen/netback/xenbus.c |   32 +++++++++++++++++++++-----------
 3 files changed, 48 insertions(+), 16 deletions(-)

diff -r 26562626c866 -r 59f097ef181b drivers/xen/blkback/xenbus.c
--- a/drivers/xen/blkback/xenbus.c      Fri Nov 19 13:22:43 2010 +0000
+++ b/drivers/xen/blkback/xenbus.c      Tue Nov 23 13:58:38 2010 +0000
@@ -380,6 +380,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;
@@ -397,6 +402,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 -r 26562626c866 -r 59f097ef181b drivers/xen/blktap/xenbus.c
--- a/drivers/xen/blktap/xenbus.c       Fri Nov 19 13:22:43 2010 +0000
+++ b/drivers/xen/blktap/xenbus.c       Tue Nov 23 13:58:38 2010 +0000
@@ -339,6 +339,18 @@ static void tap_backend_changed(struct x
        tap_update_blkif_status(be->blkif);
 }
 
+
+static void 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.
  */
@@ -367,6 +379,11 @@ static void tap_frontend_changed(struct 
                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;
@@ -374,11 +391,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_free(be->blkif);
+               blkif_disconnect(be->blkif);
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
 
@@ -388,6 +401,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 -r 26562626c866 -r 59f097ef181b drivers/xen/netback/xenbus.c
--- a/drivers/xen/netback/xenbus.c      Fri Nov 19 13:22:43 2010 +0000
+++ b/drivers/xen/netback/xenbus.c      Tue Nov 23 13:58:38 2010 +0000
@@ -32,6 +32,7 @@ static int connect_rings(struct backend_
 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,16 +40,22 @@ static int netback_remove(struct xenbus_
 
        netback_remove_accelerators(be, dev);
 
+       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(&dev->dev.kobj, KOBJ_OFFLINE);
+               kobject_uevent(&xbdev_dev->kobj, KOBJ_OFFLINE);
                netif_disconnect(be->netif);
                be->netif = NULL;
        }
-       kfree(be);
-       dev->dev.driver_data = NULL;
-       return 0;
-}
-
+}
 
 /**
  * Entry point to this code when a new device is created.  Allocate the basic
@@ -234,17 +241,19 @@ static void frontend_changed(struct xenb
        case XenbusStateConnected:
                if (dev->state == XenbusStateConnected)
                        break;
+
+               /* Enforce precondition before potential leak point.
+                * netback_disconnect() is idempotent.
+                */
+               netback_disconnect(&dev->dev);
+
                backend_create_netif(be);
                if (be->netif)
                        connect(be);
                break;
 
        case XenbusStateClosing:
-               if (be->netif) {
-                       kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-                       netif_disconnect(be->netif);
-                       be->netif = NULL;
-               }
+               netback_disconnect(&dev->dev);
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
 
@@ -254,6 +263,7 @@ static void frontend_changed(struct xenb
                        break;
                /* fall through if not online */
        case XenbusStateUnknown:
+               /* implies netback_disconnect() via netback_remove() */
                device_unregister(&dev->dev);
                break;
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.