nbd: make server compliant with fixed newstyle spec

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>
Message-Id: <1455129674-17255-9-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-02-10 18:41:06 +00:00 committed by Paolo Bonzini
parent f72d705f0d
commit 26afa868db

View File

@ -310,6 +310,7 @@ fail:
static int nbd_negotiate_options(NBDClient *client) static int nbd_negotiate_options(NBDClient *client)
{ {
uint32_t flags; uint32_t flags;
bool fixedNewstyle = false;
/* Client sends: /* Client sends:
[ 0 .. 3] client flags [ 0 .. 3] client flags
@ -332,14 +333,19 @@ static int nbd_negotiate_options(NBDClient *client)
} }
TRACE("Checking client flags"); TRACE("Checking client flags");
be32_to_cpus(&flags); be32_to_cpus(&flags);
if (flags != 0 && flags != NBD_FLAG_C_FIXED_NEWSTYLE) { if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
LOG("Bad client flags received"); 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; return -EIO;
} }
while (1) { while (1) {
int ret; int ret;
uint32_t tmp, length; uint32_t clientflags, length;
uint64_t magic; uint64_t magic;
if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) != if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
@ -353,10 +359,12 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL; 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"); LOG("read failed");
return -EINVAL; return -EINVAL;
} }
clientflags = be32_to_cpu(clientflags);
if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) != if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
sizeof(length)) { sizeof(length)) {
@ -365,8 +373,9 @@ static int nbd_negotiate_options(NBDClient *client)
} }
length = be32_to_cpu(length); length = be32_to_cpu(length);
TRACE("Checking option"); TRACE("Checking option 0x%x", clientflags);
switch (be32_to_cpu(tmp)) { if (fixedNewstyle) {
switch (clientflags) {
case NBD_OPT_LIST: case NBD_OPT_LIST:
ret = nbd_negotiate_handle_list(client, length); ret = nbd_negotiate_handle_list(client, length);
if (ret < 0) { if (ret < 0) {
@ -381,11 +390,25 @@ static int nbd_negotiate_options(NBDClient *client)
return nbd_negotiate_handle_export_name(client, length); return nbd_negotiate_handle_export_name(client, length);
default: default:
tmp = be32_to_cpu(tmp); TRACE("Unsupported option 0x%x", clientflags);
LOG("Unsupported option 0x%x", tmp); nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP,
nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP, tmp); clientflags);
return -EINVAL; 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;
}
}
} }
} }