Blame 0102-nbd-Fully-initialize-client-in-case-of-failed-negoti.patch

335584
From: Eric Blake <eblake@redhat.com>
335584
Date: Fri, 26 May 2017 22:04:21 -0500
335584
Subject: [PATCH] nbd: Fully initialize client in case of failed negotiation
335584
335584
If a non-NBD client connects to qemu-nbd, we would end up with
335584
a SIGSEGV in nbd_client_put() because we were trying to
335584
unregister the client's association to the export, even though
335584
we skipped inserting the client into that list.  Easy trigger
335584
in two terminals:
335584
335584
$ qemu-nbd -p 30001 --format=raw file
335584
$ nmap 127.0.0.1 -p 30001
335584
335584
nmap claims that it thinks it connected to a pago-services1
335584
server (which probably means nmap could be updated to learn the
335584
NBD protocol and give a more accurate diagnosis of the open
335584
port - but that's not our problem), then terminates immediately,
335584
so our call to nbd_negotiate() fails.  The fix is to reorder
335584
nbd_co_client_start() to ensure that all initialization occurs
335584
before we ever try talking to a client in nbd_negotiate(), so
335584
that the teardown sequence on negotiation failure doesn't fault
335584
while dereferencing a half-initialized object.
335584
335584
While debugging this, I also noticed that nbd_update_server_watch()
335584
called by nbd_client_closed() was still adding a channel to accept
335584
the next client, even when the state was no longer RUNNING.  That
335584
is fixed by making nbd_can_accept() pay attention to the current
335584
state.
335584
335584
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
335584
335584
Signed-off-by: Eric Blake <eblake@redhat.com>
335584
Message-Id: <20170527030421.28366-1-eblake@redhat.com>
335584
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
335584
(cherry picked from commit df8ad9f128c15aa0a0ebc7b24e9a22c9775b67af)
335584
---
335584
 nbd/server.c | 8 +++-----
335584
 qemu-nbd.c   | 2 +-
335584
 2 files changed, 4 insertions(+), 6 deletions(-)
335584
335584
diff --git a/nbd/server.c b/nbd/server.c
335584
index 924a1fe2db..edfda84d43 100644
335584
--- a/nbd/server.c
335584
+++ b/nbd/server.c
335584
@@ -1376,16 +1376,14 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
335584
 
335584
     if (exp) {
335584
         nbd_export_get(exp);
335584
+        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
335584
     }
335584
+    qemu_co_mutex_init(&client->send_lock);
335584
+
335584
     if (nbd_negotiate(data)) {
335584
         client_close(client);
335584
         goto out;
335584
     }
335584
-    qemu_co_mutex_init(&client->send_lock);
335584
-
335584
-    if (exp) {
335584
-        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
335584
-    }
335584
 
335584
     nbd_client_receive_next_request(client);
335584
 
335584
diff --git a/qemu-nbd.c b/qemu-nbd.c
335584
index e080fb7c75..b44764eb87 100644
335584
--- a/qemu-nbd.c
335584
+++ b/qemu-nbd.c
335584
@@ -324,7 +324,7 @@ out:
335584
 
335584
 static int nbd_can_accept(void)
335584
 {
335584
-    return nb_fds < shared;
335584
+    return state == RUNNING && nb_fds < shared;
335584
 }
335584
 
335584
 static void nbd_export_closed(NBDExport *exp)