gnu: qemu: Fix CVE-2017-9524.
* gnu/packages/patches/qemu-CVE-2017-9524.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/qemu.scm (qemu)[source]: Use it.
This commit is contained in:
		
							parent
							
								
									ab126c170a
								
							
						
					
					
						commit
						c57b56722f
					
				
					 3 changed files with 290 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -966,6 +966,7 @@ dist_patch_DATA =						\
 | 
			
		|||
  %D%/packages/patches/qemu-CVE-2017-8309.patch			\
 | 
			
		||||
  %D%/packages/patches/qemu-CVE-2017-8379.patch			\
 | 
			
		||||
  %D%/packages/patches/qemu-CVE-2017-8380.patch			\
 | 
			
		||||
  %D%/packages/patches/qemu-CVE-2017-9524.patch			\
 | 
			
		||||
  %D%/packages/patches/qt4-ldflags.patch			\
 | 
			
		||||
  %D%/packages/patches/qtscript-disable-tests.patch		\
 | 
			
		||||
  %D%/packages/patches/quickswitch-fix-dmenu-check.patch	\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										287
									
								
								gnu/packages/patches/qemu-CVE-2017-9524.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								gnu/packages/patches/qemu-CVE-2017-9524.patch
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,287 @@
 | 
			
		|||
Fix CVE-2017-9524:
 | 
			
		||||
 | 
			
		||||
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9524
 | 
			
		||||
http://seclists.org/oss-sec/2017/q2/454
 | 
			
		||||
 | 
			
		||||
Patches copied from upstream source repository:
 | 
			
		||||
 | 
			
		||||
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=df8ad9f128c15aa0a0ebc7b24e9a22c9775b67af
 | 
			
		||||
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=0c9390d978cbf61e8f16c9f580fa96b305c43568
 | 
			
		||||
 | 
			
		||||
From df8ad9f128c15aa0a0ebc7b24e9a22c9775b67af Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Date: Fri, 26 May 2017 22:04:21 -0500
 | 
			
		||||
Subject: [PATCH] nbd: Fully initialize client in case of failed negotiation
 | 
			
		||||
 | 
			
		||||
If a non-NBD client connects to qemu-nbd, we would end up with
 | 
			
		||||
a SIGSEGV in nbd_client_put() because we were trying to
 | 
			
		||||
unregister the client's association to the export, even though
 | 
			
		||||
we skipped inserting the client into that list.  Easy trigger
 | 
			
		||||
in two terminals:
 | 
			
		||||
 | 
			
		||||
$ qemu-nbd -p 30001 --format=raw file
 | 
			
		||||
$ nmap 127.0.0.1 -p 30001
 | 
			
		||||
 | 
			
		||||
nmap claims that it thinks it connected to a pago-services1
 | 
			
		||||
server (which probably means nmap could be updated to learn the
 | 
			
		||||
NBD protocol and give a more accurate diagnosis of the open
 | 
			
		||||
port - but that's not our problem), then terminates immediately,
 | 
			
		||||
so our call to nbd_negotiate() fails.  The fix is to reorder
 | 
			
		||||
nbd_co_client_start() to ensure that all initialization occurs
 | 
			
		||||
before we ever try talking to a client in nbd_negotiate(), so
 | 
			
		||||
that the teardown sequence on negotiation failure doesn't fault
 | 
			
		||||
while dereferencing a half-initialized object.
 | 
			
		||||
 | 
			
		||||
While debugging this, I also noticed that nbd_update_server_watch()
 | 
			
		||||
called by nbd_client_closed() was still adding a channel to accept
 | 
			
		||||
the next client, even when the state was no longer RUNNING.  That
 | 
			
		||||
is fixed by making nbd_can_accept() pay attention to the current
 | 
			
		||||
state.
 | 
			
		||||
 | 
			
		||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Message-Id: <20170527030421.28366-1-eblake@redhat.com>
 | 
			
		||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
 | 
			
		||||
---
 | 
			
		||||
 nbd/server.c | 8 +++-----
 | 
			
		||||
 qemu-nbd.c   | 2 +-
 | 
			
		||||
 2 files changed, 4 insertions(+), 6 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/nbd/server.c b/nbd/server.c
 | 
			
		||||
index ee59e5d234..49b55f6ede 100644
 | 
			
		||||
--- a/nbd/server.c
 | 
			
		||||
+++ b/nbd/server.c
 | 
			
		||||
@@ -1358,16 +1358,14 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
 | 
			
		||||
 
 | 
			
		||||
     if (exp) {
 | 
			
		||||
         nbd_export_get(exp);
 | 
			
		||||
+        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
 | 
			
		||||
     }
 | 
			
		||||
+    qemu_co_mutex_init(&client->send_lock);
 | 
			
		||||
+
 | 
			
		||||
     if (nbd_negotiate(data)) {
 | 
			
		||||
         client_close(client);
 | 
			
		||||
         goto out;
 | 
			
		||||
     }
 | 
			
		||||
-    qemu_co_mutex_init(&client->send_lock);
 | 
			
		||||
-
 | 
			
		||||
-    if (exp) {
 | 
			
		||||
-        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
 | 
			
		||||
-    }
 | 
			
		||||
 
 | 
			
		||||
     nbd_client_receive_next_request(client);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qemu-nbd.c b/qemu-nbd.c
 | 
			
		||||
index f60842fd86..651f85ecc1 100644
 | 
			
		||||
--- a/qemu-nbd.c
 | 
			
		||||
+++ b/qemu-nbd.c
 | 
			
		||||
@@ -325,7 +325,7 @@ out:
 | 
			
		||||
 
 | 
			
		||||
 static int nbd_can_accept(void)
 | 
			
		||||
 {
 | 
			
		||||
-    return nb_fds < shared;
 | 
			
		||||
+    return state == RUNNING && nb_fds < shared;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static void nbd_export_closed(NBDExport *exp)
 | 
			
		||||
-- 
 | 
			
		||||
2.13.1
 | 
			
		||||
 | 
			
		||||
From 0c9390d978cbf61e8f16c9f580fa96b305c43568 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Date: Thu, 8 Jun 2017 17:26:17 -0500
 | 
			
		||||
Subject: [PATCH] nbd: Fix regression on resiliency to port scan
 | 
			
		||||
 | 
			
		||||
Back in qemu 2.5, qemu-nbd was immune to port probes (a transient
 | 
			
		||||
server would not quit, regardless of how many probe connections
 | 
			
		||||
came and went, until a connection actually negotiated).  But we
 | 
			
		||||
broke that in commit ee7d7aa when removing the return value to
 | 
			
		||||
nbd_client_new(), although that patch also introduced a bug causing
 | 
			
		||||
an assertion failure on a client that fails negotiation.  We then
 | 
			
		||||
made it worse during refactoring in commit 1a6245a (a segfault
 | 
			
		||||
before we could even assert); the (masked) assertion was cleaned
 | 
			
		||||
up in d3780c2 (still in 2.6), and just recently we finally fixed
 | 
			
		||||
the segfault ("nbd: Fully intialize client in case of failed
 | 
			
		||||
negotiation").  But that still means that ever since we added
 | 
			
		||||
TLS support to qemu-nbd, we have been vulnerable to an ill-timed
 | 
			
		||||
port-scan being able to cause a denial of service by taking down
 | 
			
		||||
qemu-nbd before a real client has a chance to connect.
 | 
			
		||||
 | 
			
		||||
Since negotiation is now handled asynchronously via coroutines,
 | 
			
		||||
we no longer have a synchronous point of return by re-adding a
 | 
			
		||||
return value to nbd_client_new().  So this patch instead wires
 | 
			
		||||
things up to pass the negotiation status through the close_fn
 | 
			
		||||
callback function.
 | 
			
		||||
 | 
			
		||||
Simple test across two terminals:
 | 
			
		||||
$ qemu-nbd -f raw -p 30001 file
 | 
			
		||||
$ nmap 127.0.0.1 -p 30001 && \
 | 
			
		||||
  qemu-io -c 'r 0 512' -f raw nbd://localhost:30001
 | 
			
		||||
 | 
			
		||||
Note that this patch does not change what constitutes successful
 | 
			
		||||
negotiation (thus, a client must enter transmission phase before
 | 
			
		||||
that client can be considered as a reason to terminate the server
 | 
			
		||||
when the connection ends).  Perhaps we may want to tweak things
 | 
			
		||||
in a later patch to also treat a client that uses NBD_OPT_ABORT
 | 
			
		||||
as being a 'successful' negotiation (the client correctly talked
 | 
			
		||||
the NBD protocol, and informed us it was not going to use our
 | 
			
		||||
export after all), but that's a discussion for another day.
 | 
			
		||||
 | 
			
		||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Eric Blake <eblake@redhat.com>
 | 
			
		||||
Message-Id: <20170608222617.20376-1-eblake@redhat.com>
 | 
			
		||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
 | 
			
		||||
---
 | 
			
		||||
 blockdev-nbd.c      |  6 +++++-
 | 
			
		||||
 include/block/nbd.h |  2 +-
 | 
			
		||||
 nbd/server.c        | 24 +++++++++++++++---------
 | 
			
		||||
 qemu-nbd.c          |  4 ++--
 | 
			
		||||
 4 files changed, 23 insertions(+), 13 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
 | 
			
		||||
index dd0860f4a6..28f551a7b0 100644
 | 
			
		||||
--- a/blockdev-nbd.c
 | 
			
		||||
+++ b/blockdev-nbd.c
 | 
			
		||||
@@ -27,6 +27,10 @@ typedef struct NBDServerData {
 | 
			
		||||
 
 | 
			
		||||
 static NBDServerData *nbd_server;
 | 
			
		||||
 
 | 
			
		||||
+static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
 | 
			
		||||
+{
 | 
			
		||||
+    nbd_client_put(client);
 | 
			
		||||
+}
 | 
			
		||||
 
 | 
			
		||||
 static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
 | 
			
		||||
                            gpointer opaque)
 | 
			
		||||
@@ -46,7 +50,7 @@ static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
 | 
			
		||||
     qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
 | 
			
		||||
     nbd_client_new(NULL, cioc,
 | 
			
		||||
                    nbd_server->tlscreds, NULL,
 | 
			
		||||
-                   nbd_client_put);
 | 
			
		||||
+                   nbd_blockdev_client_closed);
 | 
			
		||||
     object_unref(OBJECT(cioc));
 | 
			
		||||
     return TRUE;
 | 
			
		||||
 }
 | 
			
		||||
diff --git a/include/block/nbd.h b/include/block/nbd.h
 | 
			
		||||
index 416257abca..8fa5ce51f3 100644
 | 
			
		||||
--- a/include/block/nbd.h
 | 
			
		||||
+++ b/include/block/nbd.h
 | 
			
		||||
@@ -162,7 +162,7 @@ void nbd_client_new(NBDExport *exp,
 | 
			
		||||
                     QIOChannelSocket *sioc,
 | 
			
		||||
                     QCryptoTLSCreds *tlscreds,
 | 
			
		||||
                     const char *tlsaclname,
 | 
			
		||||
-                    void (*close)(NBDClient *));
 | 
			
		||||
+                    void (*close_fn)(NBDClient *, bool));
 | 
			
		||||
 void nbd_client_get(NBDClient *client);
 | 
			
		||||
 void nbd_client_put(NBDClient *client);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/nbd/server.c b/nbd/server.c
 | 
			
		||||
index 49b55f6ede..f2b1aa47ce 100644
 | 
			
		||||
--- a/nbd/server.c
 | 
			
		||||
+++ b/nbd/server.c
 | 
			
		||||
@@ -81,7 +81,7 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
 | 
			
		||||
 
 | 
			
		||||
 struct NBDClient {
 | 
			
		||||
     int refcount;
 | 
			
		||||
-    void (*close)(NBDClient *client);
 | 
			
		||||
+    void (*close_fn)(NBDClient *client, bool negotiated);
 | 
			
		||||
 
 | 
			
		||||
     bool no_zeroes;
 | 
			
		||||
     NBDExport *exp;
 | 
			
		||||
@@ -778,7 +778,7 @@ void nbd_client_put(NBDClient *client)
 | 
			
		||||
     }
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static void client_close(NBDClient *client)
 | 
			
		||||
+static void client_close(NBDClient *client, bool negotiated)
 | 
			
		||||
 {
 | 
			
		||||
     if (client->closing) {
 | 
			
		||||
         return;
 | 
			
		||||
@@ -793,8 +793,8 @@ static void client_close(NBDClient *client)
 | 
			
		||||
                          NULL);
 | 
			
		||||
 
 | 
			
		||||
     /* Also tell the client, so that they release their reference.  */
 | 
			
		||||
-    if (client->close) {
 | 
			
		||||
-        client->close(client);
 | 
			
		||||
+    if (client->close_fn) {
 | 
			
		||||
+        client->close_fn(client, negotiated);
 | 
			
		||||
     }
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -975,7 +975,7 @@ void nbd_export_close(NBDExport *exp)
 | 
			
		||||
 
 | 
			
		||||
     nbd_export_get(exp);
 | 
			
		||||
     QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) {
 | 
			
		||||
-        client_close(client);
 | 
			
		||||
+        client_close(client, true);
 | 
			
		||||
     }
 | 
			
		||||
     nbd_export_set_name(exp, NULL);
 | 
			
		||||
     nbd_export_set_description(exp, NULL);
 | 
			
		||||
@@ -1337,7 +1337,7 @@ done:
 | 
			
		||||
 
 | 
			
		||||
 out:
 | 
			
		||||
     nbd_request_put(req);
 | 
			
		||||
-    client_close(client);
 | 
			
		||||
+    client_close(client, true);
 | 
			
		||||
     nbd_client_put(client);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -1363,7 +1363,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
 | 
			
		||||
     qemu_co_mutex_init(&client->send_lock);
 | 
			
		||||
 
 | 
			
		||||
     if (nbd_negotiate(data)) {
 | 
			
		||||
-        client_close(client);
 | 
			
		||||
+        client_close(client, false);
 | 
			
		||||
         goto out;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
@@ -1373,11 +1373,17 @@ out:
 | 
			
		||||
     g_free(data);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+/*
 | 
			
		||||
+ * Create a new client listener on the given export @exp, using the
 | 
			
		||||
+ * given channel @sioc.  Begin servicing it in a coroutine.  When the
 | 
			
		||||
+ * connection closes, call @close_fn with an indication of whether the
 | 
			
		||||
+ * client completed negotiation.
 | 
			
		||||
+ */
 | 
			
		||||
 void nbd_client_new(NBDExport *exp,
 | 
			
		||||
                     QIOChannelSocket *sioc,
 | 
			
		||||
                     QCryptoTLSCreds *tlscreds,
 | 
			
		||||
                     const char *tlsaclname,
 | 
			
		||||
-                    void (*close_fn)(NBDClient *))
 | 
			
		||||
+                    void (*close_fn)(NBDClient *, bool))
 | 
			
		||||
 {
 | 
			
		||||
     NBDClient *client;
 | 
			
		||||
     NBDClientNewData *data = g_new(NBDClientNewData, 1);
 | 
			
		||||
@@ -1394,7 +1400,7 @@ void nbd_client_new(NBDExport *exp,
 | 
			
		||||
     object_ref(OBJECT(client->sioc));
 | 
			
		||||
     client->ioc = QIO_CHANNEL(sioc);
 | 
			
		||||
     object_ref(OBJECT(client->ioc));
 | 
			
		||||
-    client->close = close_fn;
 | 
			
		||||
+    client->close_fn = close_fn;
 | 
			
		||||
 
 | 
			
		||||
     data->client = client;
 | 
			
		||||
     data->co = qemu_coroutine_create(nbd_co_client_start, data);
 | 
			
		||||
diff --git a/qemu-nbd.c b/qemu-nbd.c
 | 
			
		||||
index 651f85ecc1..9464a0461c 100644
 | 
			
		||||
--- a/qemu-nbd.c
 | 
			
		||||
+++ b/qemu-nbd.c
 | 
			
		||||
@@ -336,10 +336,10 @@ static void nbd_export_closed(NBDExport *exp)
 | 
			
		||||
 
 | 
			
		||||
 static void nbd_update_server_watch(void);
 | 
			
		||||
 
 | 
			
		||||
-static void nbd_client_closed(NBDClient *client)
 | 
			
		||||
+static void nbd_client_closed(NBDClient *client, bool negotiated)
 | 
			
		||||
 {
 | 
			
		||||
     nb_fds--;
 | 
			
		||||
-    if (nb_fds == 0 && !persistent && state == RUNNING) {
 | 
			
		||||
+    if (negotiated && nb_fds == 0 && !persistent && state == RUNNING) {
 | 
			
		||||
         state = TERMINATE;
 | 
			
		||||
     }
 | 
			
		||||
     nbd_update_server_watch();
 | 
			
		||||
-- 
 | 
			
		||||
2.13.1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +78,8 @@
 | 
			
		|||
                                      "qemu-CVE-2017-8112.patch"
 | 
			
		||||
                                      "qemu-CVE-2017-8309.patch"
 | 
			
		||||
                                      "qemu-CVE-2017-8379.patch"
 | 
			
		||||
                                      "qemu-CVE-2017-8380.patch"))
 | 
			
		||||
                                      "qemu-CVE-2017-8380.patch"
 | 
			
		||||
                                      "qemu-CVE-2017-9524.patch"))
 | 
			
		||||
             (sha256
 | 
			
		||||
              (base32
 | 
			
		||||
               "08mhfs0ndbkyqgw7fjaa9vjxf4dinrly656f6hjzvmaz7hzc677h"))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in a new issue