Message ID | 7c7619a2-a6f3-c30c-c8d0-aac1f96ae661@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 06/13/2016 06:19 AM, Paolo Bonzini wrote: >> + /* Sanity checks, part 2. */ >> + if (request->from + request->len > client->exp->size) { >> + LOG("operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 >> + ", Size: %" PRIu64, request->from, request->len, >> + (uint64_t)client->exp->size); >> + rc = -EINVAL; > > For writes, this should be ENOSPC according to the spec. Good call. >> + if (nbd_co_send_reply(req, &reply, 0) < 0 || command == NBD_CMD_READ || >> + (command == NBD_CMD_WRITE && !req->complete)) { > > It's simpler to always set req->complete. Putting everything together: > > diff --git a/nbd/server.c b/nbd/server.c > index 4743316..73505dc 100644 > --- a/nbd/server.c > +++ b/nbd/server.c > @@ -1017,6 +1017,11 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, > TRACE("Decoding type"); > > command = request->type & NBD_CMD_MASK_COMMAND; > + if (command != NBD_CMD_WRITE) { > + /* No payload, we are ready to read the next request. */ > + req->complete = true; > + } > + Nice. > @@ -1213,12 +1218,9 @@ static void nbd_trip(void *opaque) > LOG("invalid request type (%" PRIu32 ") received", request.type); > reply.error = EINVAL; > error_reply: > - /* We must disconnect after replying with an error to > - * NBD_CMD_READ, since we choose not to send bogus filler > - * data; likewise after NBD_CMD_WRITE if we did not read the > - * payload. */ > - if (nbd_co_send_reply(req, &reply, 0) < 0 || command == NBD_CMD_READ || > - (command == NBD_CMD_WRITE && !req->complete)) { > + /* We must disconnect after NBD_CMD_WRITE if we did not > + * read the payload. */ > + if (nbd_co_send_reply(req, &reply, 0) < 0 || !req->complete)) { I'm not sure I agree with your change on NBD_CMD_READ, but we can hash that out with upstream NBD list on the correct protocol, and make any further changes as a followup.
On 06/13/2016 06:19 AM, Paolo Bonzini wrote: > > > On 12/05/2016 00:39, Eric Blake wrote: >> We have a few bugs in how we handle invalid client commands: >> >> - A client can send an NBD_CMD_DISC where from + len overflows, >> convincing us to reply with an error and stay connected, even >> though the protocol requires us to silently disconnect. Fix by >> hoisting the special case sooner. >> > It's simpler to always set req->complete. Putting everything together: > > diff --git a/nbd/server.c b/nbd/server.c > @@ -1213,12 +1218,9 @@ static void nbd_trip(void *opaque) > LOG("invalid request type (%" PRIu32 ") received", request.type); > reply.error = EINVAL; > error_reply: > - /* We must disconnect after replying with an error to > - * NBD_CMD_READ, since we choose not to send bogus filler > - * data; likewise after NBD_CMD_WRITE if we did not read the > - * payload. */ > - if (nbd_co_send_reply(req, &reply, 0) < 0 || command == NBD_CMD_READ || > - (command == NBD_CMD_WRITE && !req->complete)) { > + /* We must disconnect after NBD_CMD_WRITE if we did not > + * read the payload. */ > + if (nbd_co_send_reply(req, &reply, 0) < 0 || !req->complete)) { This doesn't even compile (too many ')'). I assume you'll fix that before your actual pull request goes out.
diff --git a/nbd/server.c b/nbd/server.c index 4743316..73505dc 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1017,6 +1017,11 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, TRACE("Decoding type"); command = request->type & NBD_CMD_MASK_COMMAND; + if (command != NBD_CMD_WRITE) { + /* No payload, we are ready to read the next request. */ + req->complete = true; + } + if (command == NBD_CMD_DISC) { /* Special case: we're going to disconnect without a reply, * whether or not flags, from, or len are bogus */ @@ -1064,7 +1069,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, LOG("operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 ", Size: %" PRIu64, request->from, request->len, (uint64_t)client->exp->size); - rc = -EINVAL; + rc = command == NBD_CMD_WRITE ? -ENOSPC : -EINVAL; goto out; } @@ -1213,12 +1218,9 @@ static void nbd_trip(void *opaque) LOG("invalid request type (%" PRIu32 ") received", request.type); reply.error = EINVAL; error_reply: - /* We must disconnect after replying with an error to - * NBD_CMD_READ, since we choose not to send bogus filler - * data; likewise after NBD_CMD_WRITE if we did not read the - * payload. */ - if (nbd_co_send_reply(req, &reply, 0) < 0 || command == NBD_CMD_READ || - (command == NBD_CMD_WRITE && !req->complete)) { + /* We must disconnect after NBD_CMD_WRITE if we did not + * read the payload. */ + if (nbd_co_send_reply(req, &reply, 0) < 0 || !req->complete)) { goto out; } break;