Skip to content

Commit

Permalink
nbd: Fully initialize client in case of failed negotiation
Browse files Browse the repository at this point in the history
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>
(cherry picked from commit df8ad9f)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
  • Loading branch information
ebblake authored and mdroth committed Aug 24, 2017
1 parent f28b890 commit ec49c8a
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 6 deletions.
8 changes: 3 additions & 5 deletions nbd/server.c
Expand Up @@ -1376,16 +1376,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);

Expand Down
2 changes: 1 addition & 1 deletion qemu-nbd.c
Expand Up @@ -324,7 +324,7 @@ static void *nbd_client_thread(void *arg)

static int nbd_can_accept(void)
{
return nb_fds < shared;
return state == RUNNING && nb_fds < shared;
}

static void nbd_export_closed(NBDExport *exp)
Expand Down

0 comments on commit ec49c8a

Please sign in to comment.