[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 08/15] nbd: Fix NBD unsupported options
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PULL 08/15] nbd: Fix NBD unsupported options |
Date: |
Thu, 7 Apr 2016 18:50:38 +0200 |
From: Alex Bligh <address@hidden>
nbd-client.c currently fails to handle unsupported options properly.
If during option haggling the server finds an option that is
unsupported, it returns an NBD_REP_ERR_UNSUP reply.
According to nbd's proto.md, the format for such a reply
should be:
S: 64 bits, 0x3e889045565a9 (magic number for replies)
S: 32 bits, the option as sent by the client to which this is a reply
S: 32 bits, reply type (e.g., NBD_REP_ACK for successful completion,
or NBD_REP_ERR_UNSUP to mark use of an option not known by this server
S: 32 bits, length of the reply. This may be zero for some replies,
in which case the next field is not sent
S: any data as required by the reply (e.g., an export name in the case
of NBD_REP_SERVER, or optional UTF-8 message for NBD_REP_ERR_*)
However, in nbd-client.c, the reply type was being read, and if it
contained an error, it was bailing out and issuing the next option
request without first reading the length. This meant that the
next option / handshake read had an extra 4 or more bytes of data in it.
In practice, this makes Qemu incompatible with servers that do not
support NBD_OPT_LIST.
To verify this isn't an error in the specification or my reading of
it, replies are sent by the reference implementation here:
https://github.com/yoe/nbd/blob/66dfb35/nbd-server.c#L1232
and as is evident it always sends a 'datasize' (aka length) 32 bit
word. Unsupported elements are replied to here:
https://github.com/yoe/nbd/blob/66dfb35/nbd-server.c#L1371
Signed-off-by: Alex Bligh <address@hidden>
Message-Id: <address@hidden>
[rework to ALWAYS consume an optional UTF-8 message from the server]
Signed-off-by: Eric Blake <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Paolo Bonzini <address@hidden>
---
nbd/client.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 10 deletions(-)
diff --git a/nbd/client.c b/nbd/client.c
index 1593cd6..6777e58 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -73,16 +73,46 @@ static QTAILQ_HEAD(, NBDExport) exports =
QTAILQ_HEAD_INITIALIZER(exports);
*/
-static int nbd_handle_reply_err(uint32_t opt, uint32_t type, Error **errp)
+/* If type represents success, return 1 without further action.
+ * If type represents an error reply, consume the rest of the packet on ioc.
+ * Then return 0 for unsupported (so the client can fall back to
+ * other approaches), or -1 with errp set for other errors.
+ */
+static int nbd_handle_reply_err(QIOChannel *ioc, uint32_t opt, uint32_t type,
+ Error **errp)
{
+ uint32_t len;
+ char *msg = NULL;
+ int result = -1;
+
if (!(type & (1 << 31))) {
- return 0;
+ return 1;
+ }
+
+ if (read_sync(ioc, &len, sizeof(len)) != sizeof(len)) {
+ error_setg(errp, "failed to read option length");
+ return -1;
+ }
+ len = be32_to_cpu(len);
+ if (len) {
+ if (len > NBD_MAX_BUFFER_SIZE) {
+ error_setg(errp, "server's error message is too long");
+ goto cleanup;
+ }
+ msg = g_malloc(len + 1);
+ if (read_sync(ioc, msg, len) != len) {
+ error_setg(errp, "failed to read option error message");
+ goto cleanup;
+ }
+ msg[len] = '\0';
}
switch (type) {
case NBD_REP_ERR_UNSUP:
- error_setg(errp, "Unsupported option type %x", opt);
- break;
+ TRACE("server doesn't understand request %d, attempting fallback",
+ opt);
+ result = 0;
+ goto cleanup;
case NBD_REP_ERR_POLICY:
error_setg(errp, "Denied by server for option %x", opt);
@@ -101,7 +131,13 @@ static int nbd_handle_reply_err(uint32_t opt, uint32_t
type, Error **errp)
break;
}
- return -1;
+ if (msg) {
+ error_append_hint(errp, "%s\n", msg);
+ }
+
+ cleanup:
+ g_free(msg);
+ return result;
}
static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
@@ -111,6 +147,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name,
Error **errp)
uint32_t type;
uint32_t len;
uint32_t namelen;
+ int error;
*name = NULL;
if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
@@ -138,11 +175,9 @@ static int nbd_receive_list(QIOChannel *ioc, char **name,
Error **errp)
return -1;
}
type = be32_to_cpu(type);
- if (type == NBD_REP_ERR_UNSUP) {
- return 0;
- }
- if (nbd_handle_reply_err(opt, type, errp) < 0) {
- return -1;
+ error = nbd_handle_reply_err(ioc, opt, type, errp);
+ if (error <= 0) {
+ return error;
}
if (read_sync(ioc, &len, sizeof(len)) != sizeof(len)) {
--
2.5.5
- [Qemu-devel] [PULL 00/15] Misc patches for QEMU 2.6.0-rc2, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 01/15] ps2kbd: default to scancode_set 2, as with KBD_CMD_RESET, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 02/15] hw/timer: Revert "hpet: inverse polarity when pin above ISA_NUM_IRQS", Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 03/15] docs: fix typo in memory.txt, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 04/15] nbd: Return correct error for write to read-only export, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 05/15] nbd: Avoid bitrot in TRACE() usage, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 06/15] nbd: Improve debug traces on little-endian, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 07/15] qemu-nbd: Document -x option, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 08/15] nbd: Fix NBD unsupported options,
Paolo Bonzini <=
- [Qemu-devel] [PULL 09/15] nbd: Don't kill server when client requests unknown option, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 10/15] nbd: do not hang nbd_wr_syncv if outside a coroutine and no available data, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 11/15] spapr: fix possible Negative array index read, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 13/15] translate-all: add missing fold of tb_ctx into tcg_ctx, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 12/15] hostmem-file: fix memory leak, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 14/15] tests: ignore test-logging, Paolo Bonzini, 2016/04/07
- [Qemu-devel] [PULL 15/15] target-i386: check for PKU even for non-writable pages, Paolo Bonzini, 2016/04/07