|
|
7711c0 |
From 2304c1c3b634b52dcca0a42c4986a04fc2b89369 Mon Sep 17 00:00:00 2001
|
|
|
7711c0 |
From: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Date: Wed, 27 Mar 2019 17:22:51 +0100
|
|
|
7711c0 |
Subject: [PATCH 113/163] nbd/client: Add nbd_receive_export_list()
|
|
|
7711c0 |
|
|
|
7711c0 |
RH-Author: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Message-id: <20190327172308.31077-39-jsnow@redhat.com>
|
|
|
7711c0 |
Patchwork-id: 85212
|
|
|
7711c0 |
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 38/55] nbd/client: Add nbd_receive_export_list()
|
|
|
7711c0 |
Bugzilla: 1691009
|
|
|
7711c0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
From: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
We want to be able to detect whether a given qemu NBD server is
|
|
|
7711c0 |
exposing the right export(s) and dirty bitmaps, at least for
|
|
|
7711c0 |
regression testing. We could use 'nbd-client -l' from the upstream
|
|
|
7711c0 |
NBD project to list exports, but it's annoying to rely on
|
|
|
7711c0 |
out-of-tree binaries; furthermore, nbd-client doesn't necessarily
|
|
|
7711c0 |
know about all of the qemu NBD extensions. Thus, we plan on adding
|
|
|
7711c0 |
a new mode to qemu-nbd that merely sniffs all possible information
|
|
|
7711c0 |
from the server during handshake phase, then disconnects and dumps
|
|
|
7711c0 |
the information.
|
|
|
7711c0 |
|
|
|
7711c0 |
This patch adds the low-level client code for grabbing the list
|
|
|
7711c0 |
of exports. It benefits from the recent refactoring patches, in
|
|
|
7711c0 |
order to share as much code as possible when it comes to doing
|
|
|
7711c0 |
validation of server replies. The resulting information is stored
|
|
|
7711c0 |
in an array of NBDExportInfo which has been expanded to any
|
|
|
7711c0 |
description string, along with a convenience function for freeing
|
|
|
7711c0 |
the list.
|
|
|
7711c0 |
|
|
|
7711c0 |
Note: a malicious server could exhaust memory of a client by feeding
|
|
|
7711c0 |
an unending loop of exports; perhaps we should place a limit on how
|
|
|
7711c0 |
many we are willing to receive. But note that a server could
|
|
|
7711c0 |
reasonably be serving an export for every file in a large directory,
|
|
|
7711c0 |
where an arbitrary limit in the client means we can't list anything
|
|
|
7711c0 |
from such a server; the same happens if we just run until the client
|
|
|
7711c0 |
fails to malloc() and thus dies by an abort(), where the limit is
|
|
|
7711c0 |
no longer arbitrary but determined by available memory. Since the
|
|
|
7711c0 |
client is already planning on being short-lived, it's hard to call
|
|
|
7711c0 |
this a denial of service attack that would starve off other uses,
|
|
|
7711c0 |
so it does not appear to be a security issue.
|
|
|
7711c0 |
|
|
|
7711c0 |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
7711c0 |
Message-Id: <20190117193658.16413-18-eblake@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
|
|
7711c0 |
(cherry picked from commit d21a2d3451d7f1defea5104ce28938f228fab0d4)
|
|
|
7711c0 |
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
---
|
|
|
7711c0 |
include/block/nbd.h | 15 +++++-
|
|
|
7711c0 |
nbd/client.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
7711c0 |
2 files changed, 143 insertions(+), 4 deletions(-)
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/include/block/nbd.h b/include/block/nbd.h
|
|
|
7711c0 |
index be19aac..19332b4 100644
|
|
|
7711c0 |
--- a/include/block/nbd.h
|
|
|
7711c0 |
+++ b/include/block/nbd.h
|
|
|
7711c0 |
@@ -1,5 +1,5 @@
|
|
|
7711c0 |
/*
|
|
|
7711c0 |
- * Copyright (C) 2016-2017 Red Hat, Inc.
|
|
|
7711c0 |
+ * Copyright (C) 2016-2019 Red Hat, Inc.
|
|
|
7711c0 |
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
|
|
7711c0 |
*
|
|
|
7711c0 |
* Network Block Device
|
|
|
7711c0 |
@@ -262,6 +262,9 @@ struct NBDExportInfo {
|
|
|
7711c0 |
/* Set by client before nbd_receive_negotiate() */
|
|
|
7711c0 |
bool request_sizes;
|
|
|
7711c0 |
char *x_dirty_bitmap;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Set by client before nbd_receive_negotiate(), or by server results
|
|
|
7711c0 |
+ * during nbd_receive_export_list() */
|
|
|
7711c0 |
char *name; /* must be non-NULL */
|
|
|
7711c0 |
|
|
|
7711c0 |
/* In-out fields, set by client before nbd_receive_negotiate() and
|
|
|
7711c0 |
@@ -269,7 +272,8 @@ struct NBDExportInfo {
|
|
|
7711c0 |
bool structured_reply;
|
|
|
7711c0 |
bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */
|
|
|
7711c0 |
|
|
|
7711c0 |
- /* Set by server results during nbd_receive_negotiate() */
|
|
|
7711c0 |
+ /* Set by server results during nbd_receive_negotiate() and
|
|
|
7711c0 |
+ * nbd_receive_export_list() */
|
|
|
7711c0 |
uint64_t size;
|
|
|
7711c0 |
uint16_t flags;
|
|
|
7711c0 |
uint32_t min_block;
|
|
|
7711c0 |
@@ -277,12 +281,19 @@ struct NBDExportInfo {
|
|
|
7711c0 |
uint32_t max_block;
|
|
|
7711c0 |
|
|
|
7711c0 |
uint32_t context_id;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Set by server results during nbd_receive_export_list() */
|
|
|
7711c0 |
+ char *description;
|
|
|
7711c0 |
};
|
|
|
7711c0 |
typedef struct NBDExportInfo NBDExportInfo;
|
|
|
7711c0 |
|
|
|
7711c0 |
int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
const char *hostname, QIOChannel **outioc,
|
|
|
7711c0 |
NBDExportInfo *info, Error **errp);
|
|
|
7711c0 |
+void nbd_free_export_list(NBDExportInfo *info, int count);
|
|
|
7711c0 |
+int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
+ const char *hostname, NBDExportInfo **info,
|
|
|
7711c0 |
+ Error **errp);
|
|
|
7711c0 |
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
|
|
|
7711c0 |
Error **errp);
|
|
|
7711c0 |
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
|
|
|
7711c0 |
diff --git a/nbd/client.c b/nbd/client.c
|
|
|
7711c0 |
index fa1657a..8a32169 100644
|
|
|
7711c0 |
--- a/nbd/client.c
|
|
|
7711c0 |
+++ b/nbd/client.c
|
|
|
7711c0 |
@@ -836,7 +836,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
|
|
|
7711c0 |
trace_nbd_start_negotiate(tlscreds, hostname ? hostname : "<null>");
|
|
|
7711c0 |
|
|
|
7711c0 |
- *zeroes = true;
|
|
|
7711c0 |
+ if (zeroes) {
|
|
|
7711c0 |
+ *zeroes = true;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
if (outioc) {
|
|
|
7711c0 |
*outioc = NULL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
@@ -880,7 +882,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
if (globalflags & NBD_FLAG_NO_ZEROES) {
|
|
|
7711c0 |
- *zeroes = false;
|
|
|
7711c0 |
+ if (zeroes) {
|
|
|
7711c0 |
+ *zeroes = false;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
clientflags |= NBD_FLAG_C_NO_ZEROES;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
/* client requested flags */
|
|
|
7711c0 |
@@ -1059,6 +1063,130 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
return 0;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
+/* Clean up result of nbd_receive_export_list */
|
|
|
7711c0 |
+void nbd_free_export_list(NBDExportInfo *info, int count)
|
|
|
7711c0 |
+{
|
|
|
7711c0 |
+ int i;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ if (!info) {
|
|
|
7711c0 |
+ return;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ for (i = 0; i < count; i++) {
|
|
|
7711c0 |
+ g_free(info[i].name);
|
|
|
7711c0 |
+ g_free(info[i].description);
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ g_free(info);
|
|
|
7711c0 |
+}
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+/*
|
|
|
7711c0 |
+ * nbd_receive_export_list:
|
|
|
7711c0 |
+ * Query details about a server's exports, then disconnect without
|
|
|
7711c0 |
+ * going into transmission phase. Return a count of the exports listed
|
|
|
7711c0 |
+ * in @info by the server, or -1 on error. Caller must free @info using
|
|
|
7711c0 |
+ * nbd_free_export_list().
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
|
|
7711c0 |
+ const char *hostname, NBDExportInfo **info,
|
|
|
7711c0 |
+ Error **errp)
|
|
|
7711c0 |
+{
|
|
|
7711c0 |
+ int result;
|
|
|
7711c0 |
+ int count = 0;
|
|
|
7711c0 |
+ int i;
|
|
|
7711c0 |
+ int rc;
|
|
|
7711c0 |
+ int ret = -1;
|
|
|
7711c0 |
+ NBDExportInfo *array = NULL;
|
|
|
7711c0 |
+ QIOChannel *sioc = NULL;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ *info = NULL;
|
|
|
7711c0 |
+ result = nbd_start_negotiate(ioc, tlscreds, hostname, &sioc, true, NULL,
|
|
|
7711c0 |
+ errp);
|
|
|
7711c0 |
+ if (tlscreds && sioc) {
|
|
|
7711c0 |
+ ioc = sioc;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ switch (result) {
|
|
|
7711c0 |
+ case 2:
|
|
|
7711c0 |
+ case 3:
|
|
|
7711c0 |
+ /* newstyle - use NBD_OPT_LIST to populate array, then try
|
|
|
7711c0 |
+ * NBD_OPT_INFO on each array member. If structured replies
|
|
|
7711c0 |
+ * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */
|
|
|
7711c0 |
+ if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) {
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ while (1) {
|
|
|
7711c0 |
+ char *name;
|
|
|
7711c0 |
+ char *desc;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ rc = nbd_receive_list(ioc, &name, &desc, errp);
|
|
|
7711c0 |
+ if (rc < 0) {
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ } else if (rc == 0) {
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ array = g_renew(NBDExportInfo, array, ++count);
|
|
|
7711c0 |
+ memset(&array[count - 1], 0, sizeof(*array));
|
|
|
7711c0 |
+ array[count - 1].name = name;
|
|
|
7711c0 |
+ array[count - 1].description = desc;
|
|
|
7711c0 |
+ array[count - 1].structured_reply = result == 3;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ for (i = 0; i < count; i++) {
|
|
|
7711c0 |
+ array[i].request_sizes = true;
|
|
|
7711c0 |
+ rc = nbd_opt_info_or_go(ioc, NBD_OPT_INFO, &array[i], errp);
|
|
|
7711c0 |
+ if (rc < 0) {
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ } else if (rc == 0) {
|
|
|
7711c0 |
+ /*
|
|
|
7711c0 |
+ * Pointless to try rest of loop. If OPT_INFO doesn't work,
|
|
|
7711c0 |
+ * it's unlikely that meta contexts work either
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* TODO: Grab meta contexts */
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Send NBD_OPT_ABORT as a courtesy before hanging up */
|
|
|
7711c0 |
+ nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ case 1: /* newstyle, but limited to EXPORT_NAME */
|
|
|
7711c0 |
+ error_setg(errp, "Server does not support export lists");
|
|
|
7711c0 |
+ /* We can't even send NBD_OPT_ABORT, so merely hang up */
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ case 0: /* oldstyle, parse length and flags */
|
|
|
7711c0 |
+ array = g_new0(NBDExportInfo, 1);
|
|
|
7711c0 |
+ array->name = g_strdup("");
|
|
|
7711c0 |
+ count = 1;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ if (nbd_negotiate_finish_oldstyle(ioc, array, errp) < 0) {
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Send NBD_CMD_DISC as a courtesy to the server, but ignore all
|
|
|
7711c0 |
+ * errors now that we have the information we wanted. */
|
|
|
7711c0 |
+ if (nbd_drop(ioc, 124, NULL) == 0) {
|
|
|
7711c0 |
+ NBDRequest request = { .type = NBD_CMD_DISC };
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ nbd_send_request(ioc, &request);
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ break;
|
|
|
7711c0 |
+ default:
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ *info = array;
|
|
|
7711c0 |
+ array = NULL;
|
|
|
7711c0 |
+ ret = count;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ out:
|
|
|
7711c0 |
+ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
|
|
|
7711c0 |
+ qio_channel_close(ioc, NULL);
|
|
|
7711c0 |
+ object_unref(OBJECT(sioc));
|
|
|
7711c0 |
+ nbd_free_export_list(array, count);
|
|
|
7711c0 |
+ return ret;
|
|
|
7711c0 |
+}
|
|
|
7711c0 |
+
|
|
|
7711c0 |
#ifdef __linux__
|
|
|
7711c0 |
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
|
|
|
7711c0 |
Error **errp)
|
|
|
7711c0 |
--
|
|
|
7711c0 |
1.8.3.1
|
|
|
7711c0 |
|