@@ -307,6 +307,7 @@ fail:
static int nbd_negotiate_options(NBDClient *client)
{
uint32_t flags;
+ bool fixedNewstyle = false;
/* Client sends:
[ 0 .. 3] client flags
@@ -329,14 +330,19 @@ static int nbd_negotiate_options(NBDClient *client)
}
TRACE("Checking client flags");
be32_to_cpus(&flags);
- if (flags != 0 && flags != NBD_FLAG_C_FIXED_NEWSTYLE) {
- LOG("Bad client flags received");
+ if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
+ TRACE("Support supports fixed newstyle handshake");
+ fixedNewstyle = true;
+ flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
+ }
+ if (flags != 0) {
+ TRACE("Unknown client flags 0x%x received", flags);
return -EIO;
}
while (1) {
int ret;
- uint32_t tmp, length;
+ uint32_t clientflags, length;
uint64_t magic;
if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
@@ -350,10 +356,12 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL;
}
- if (nbd_negotiate_read(client->ioc, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (nbd_negotiate_read(client->ioc, &clientflags,
+ sizeof(clientflags)) != sizeof(clientflags)) {
LOG("read failed");
return -EINVAL;
}
+ clientflags = be32_to_cpu(clientflags);
if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
sizeof(length)) {
@@ -362,26 +370,41 @@ static int nbd_negotiate_options(NBDClient *client)
}
length = be32_to_cpu(length);
- TRACE("Checking option");
- switch (be32_to_cpu(tmp)) {
- case NBD_OPT_LIST:
- ret = nbd_negotiate_handle_list(client, length);
- if (ret < 0) {
- return ret;
+ TRACE("Checking option 0x%x", clientflags);
+ if (fixedNewstyle) {
+ switch (clientflags) {
+ case NBD_OPT_LIST:
+ ret = nbd_negotiate_handle_list(client, length);
+ if (ret < 0) {
+ return ret;
+ }
+ break;
+
+ case NBD_OPT_ABORT:
+ return -EINVAL;
+
+ case NBD_OPT_EXPORT_NAME:
+ return nbd_negotiate_handle_export_name(client, length);
+
+ default:
+ TRACE("Unsupported option 0x%x", clientflags);
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP,
+ clientflags);
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * If broken new-style we should drop the connection
+ * for anything except NBD_OPT_EXPORT_NAME
+ */
+ switch (clientflags) {
+ case NBD_OPT_EXPORT_NAME:
+ return nbd_negotiate_handle_export_name(client, length);
+
+ default:
+ TRACE("Unsupported option 0x%x", clientflags);
+ return -EINVAL;
}
- break;
-
- case NBD_OPT_ABORT:
- return -EINVAL;
-
- case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client, length);
-
- default:
- tmp = be32_to_cpu(tmp);
- LOG("Unsupported option 0x%x", tmp);
- nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP, tmp);
- return -EINVAL;
}
}
}
If the client does not request the fixed new style protocol, then we should only accept NBD_OPT_EXPORT_NAME. All other options are only valid when fixed new style has been activated. The qemu-nbd client doesn't currently request fixed new style protocol, but this change won't break qemu-nbd, because it fortunately only ever uses NBD_OPT_EXPORT_NAME, so was never triggering the non-compliant server behaviour. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- nbd/server.c | 69 ++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 23 deletions(-)