9ae3a8
From 0e97bcfd7ab3c7b3d489de3cf4c7c4977b73cd23 Mon Sep 17 00:00:00 2001
9ae3a8
From: Eric Blake <eblake@redhat.com>
9ae3a8
Date: Fri, 9 Jun 2017 22:04:12 +0200
9ae3a8
Subject: [PATCH 5/6] nbd: Fully initialize client in case of failed
9ae3a8
 negotiation
9ae3a8
9ae3a8
RH-Author: Eric Blake <eblake@redhat.com>
9ae3a8
Message-id: <20170609220413.28793-2-eblake@redhat.com>
9ae3a8
Patchwork-id: 75576
9ae3a8
O-Subject: [RHEL-7.4 qemu-kvm PATCH 1/2] nbd: Fully initialize client in case of failed negotiation
9ae3a8
Bugzilla: 1451614
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Thomas Huth <thuth@redhat.com>
9ae3a8
9ae3a8
If a non-NBD client connects to qemu-nbd, we would end up with
9ae3a8
a SIGSEGV in nbd_client_put() because we were trying to
9ae3a8
unregister the client's association to the export, even though
9ae3a8
we skipped inserting the client into that list.  Easy trigger
9ae3a8
in two terminals:
9ae3a8
9ae3a8
$ qemu-nbd -p 30001 --format=raw file
9ae3a8
$ nmap 127.0.0.1 -p 30001
9ae3a8
9ae3a8
nmap claims that it thinks it connected to a pago-services1
9ae3a8
server (which probably means nmap could be updated to learn the
9ae3a8
NBD protocol and give a more accurate diagnosis of the open
9ae3a8
port - but that's not our problem), then terminates immediately,
9ae3a8
so our call to nbd_negotiate() fails.  The fix is to reorder
9ae3a8
nbd_co_client_start() to ensure that all initialization occurs
9ae3a8
before we ever try talking to a client in nbd_negotiate(), so
9ae3a8
that the teardown sequence on negotiation failure doesn't fault
9ae3a8
while dereferencing a half-initialized object.
9ae3a8
9ae3a8
While debugging this, I also noticed that nbd_update_server_watch()
9ae3a8
called by nbd_client_closed() was still adding a channel to accept
9ae3a8
the next client, even when the state was no longer RUNNING.  That
9ae3a8
is fixed by making nbd_can_accept() pay attention to the current
9ae3a8
state.
9ae3a8
9ae3a8
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
9ae3a8
9ae3a8
Signed-off-by: Eric Blake <eblake@redhat.com>
9ae3a8
Message-Id: <20170527030421.28366-1-eblake@redhat.com>
9ae3a8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
(cherry picked from commit ???)
9ae3a8
https://bugzilla.redhat.com/show_bug.cgi?id=1451614
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Conflicts:
9ae3a8
	nbd/server.c - code lives in nbd.c instead, with older handlers
9ae3a8
---
9ae3a8
 nbd.c      | 6 ++----
9ae3a8
 qemu-nbd.c | 2 +-
9ae3a8
 2 files changed, 3 insertions(+), 5 deletions(-)
9ae3a8
9ae3a8
diff --git a/nbd.c b/nbd.c
9ae3a8
index 8a32e18..b5cdc1b 100644
9ae3a8
--- a/nbd.c
9ae3a8
+++ b/nbd.c
9ae3a8
@@ -1280,18 +1280,16 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
9ae3a8
 
9ae3a8
     if (exp) {
9ae3a8
         nbd_export_get(exp);
9ae3a8
+        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
9ae3a8
     }
9ae3a8
     qemu_set_nonblock(client->sock);
9ae3a8
+    qemu_co_mutex_init(&client->send_lock);
9ae3a8
     if (nbd_negotiate(data)) {
9ae3a8
         nbd_client_close(client);
9ae3a8
         goto out;
9ae3a8
     }
9ae3a8
-    qemu_co_mutex_init(&client->send_lock);
9ae3a8
     qemu_set_fd_handler2(client->sock, nbd_can_read, nbd_read, NULL, client);
9ae3a8
 
9ae3a8
-    if (exp) {
9ae3a8
-        QTAILQ_INSERT_TAIL(&exp->clients, client, next);
9ae3a8
-    }
9ae3a8
 out:
9ae3a8
     g_free(data);
9ae3a8
 }
9ae3a8
diff --git a/qemu-nbd.c b/qemu-nbd.c
9ae3a8
index 047dd49..cde7431 100644
9ae3a8
--- a/qemu-nbd.c
9ae3a8
+++ b/qemu-nbd.c
9ae3a8
@@ -267,7 +267,7 @@ out:
9ae3a8
 
9ae3a8
 static int nbd_can_accept(void *opaque)
9ae3a8
 {
9ae3a8
-    return nb_fds < shared;
9ae3a8
+    return state == RUNNING && nb_fds < shared;
9ae3a8
 }
9ae3a8
 
9ae3a8
 static void nbd_export_closed(NBDExport *exp)
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8