From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL 20/30] nbd: Improve server handling of bogus commands
Date: Thu, 16 Jun 2016 16:16:15 +0200 [thread overview]
Message-ID: <1466086585-16526-21-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1466086585-16526-1-git-send-email-pbonzini@redhat.com>
From: Eric Blake <eblake@redhat.com>
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.
- A client can send an NBD_CMD_WRITE where from + len overflows,
where we reply to the client with EINVAL without consuming the
payload; this will normally cause us to fail if the next thing
read is not the right magic, but in rare cases, could cause us
to interpret the data payload as valid commands and do things
not requested by the client. Fix by adding a complete flag to
track whether we are in sync or must disconnect.
Furthermore, we have split the checks for bogus from/len across
two functions, when it is easier to do it all at once.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1463006384-7734-5-git-send-email-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
nbd/server.c | 66 +++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 47 insertions(+), 19 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index 8b0fc0f..0e71f78 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -52,6 +52,7 @@ struct NBDRequest {
QSIMPLEQ_ENTRY(NBDRequest) entry;
NBDClient *client;
uint8_t *data;
+ bool complete;
};
struct NBDExport {
@@ -989,7 +990,13 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
return rc;
}
-static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
+/* Collect a client request. Return 0 if request looks valid, -EAGAIN
+ * to keep trying the collection, -EIO to drop connection right away,
+ * and any other negative value to report an error to the client
+ * (although the caller may still need to disconnect after reporting
+ * the error). */
+static ssize_t nbd_co_receive_request(NBDRequest *req,
+ struct nbd_request *request)
{
NBDClient *client = req->client;
uint32_t command;
@@ -1007,16 +1014,31 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
goto out;
}
+ 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 */
+ TRACE("Request type is DISCONNECT");
+ rc = -EIO;
+ goto out;
+ }
+
+ /* Check for sanity in the parameters, part 1. Defer as many
+ * checks as possible until after reading any NBD_CMD_WRITE
+ * payload, so we can try and keep the connection alive. */
if ((request->from + request->len) < request->from) {
- LOG("integer overflow detected! "
- "you're probably being attacked");
+ LOG("integer overflow detected, you're probably being attacked");
rc = -EINVAL;
goto out;
}
- TRACE("Decoding type");
-
- command = request->type & NBD_CMD_MASK_COMMAND;
if (command == NBD_CMD_READ || command == NBD_CMD_WRITE) {
if (request->len > NBD_MAX_BUFFER_SIZE) {
LOG("len (%" PRIu32" ) is larger than max len (%u)",
@@ -1039,7 +1061,18 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
rc = -EIO;
goto out;
}
+ req->complete = true;
}
+
+ /* 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 = command == NBD_CMD_WRITE ? -ENOSPC : -EINVAL;
+ goto out;
+ }
+
rc = 0;
out:
@@ -1082,14 +1115,6 @@ static void nbd_trip(void *opaque)
goto error_reply;
}
command = request.type & NBD_CMD_MASK_COMMAND;
- if (command != NBD_CMD_DISC && (request.from + request.len) > exp->size) {
- LOG("From: %" PRIu64 ", Len: %" PRIu32", Size: %" PRIu64
- ", Offset: %" PRIu64 "\n",
- request.from, request.len,
- (uint64_t)exp->size, (uint64_t)exp->dev_offset);
- LOG("requested operation past EOF--bad client?");
- goto invalid_request;
- }
if (client->closing) {
/*
@@ -1151,10 +1176,11 @@ static void nbd_trip(void *opaque)
goto out;
}
break;
+
case NBD_CMD_DISC:
- TRACE("Request type is DISCONNECT");
- errno = 0;
- goto out;
+ /* unreachable, thanks to special case in nbd_co_receive_request() */
+ abort();
+
case NBD_CMD_FLUSH:
TRACE("Request type is FLUSH");
@@ -1190,10 +1216,12 @@ static void nbd_trip(void *opaque)
break;
default:
LOG("invalid request type (%" PRIu32 ") received", request.type);
- invalid_request:
reply.error = EINVAL;
error_reply:
- if (nbd_co_send_reply(req, &reply, 0) < 0) {
+ /* 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;
--
2.5.5
next prev parent reply other threads:[~2016-06-16 14:17 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-16 14:15 [Qemu-devel] [PULL 00/30] KVM, build, NBD, SCSI patches for 2016-06-16 Paolo Bonzini
2016-06-16 14:15 ` [Qemu-devel] [PULL 01/30] configure: Remove unused CONFIG_ZERO_MALLOC setting Paolo Bonzini
2016-06-16 14:15 ` [Qemu-devel] [PULL 02/30] os-posix: include sys/mman.h Paolo Bonzini
2016-06-16 14:15 ` [Qemu-devel] [PULL 03/30] clean-includes: run it once more Paolo Bonzini
2016-06-16 14:15 ` [Qemu-devel] [PULL 04/30] configure: Enable -Werror for MinGW builds, too Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 05/30] Makefile: Fix tag file generation targets Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 06/30] Make avx2 configure test work with -O2 Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 07/30] avx2 configure: Use primitives in test Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 08/30] configure: Remove unused CONFIG_SIGEV_THREAD_ID switch Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 09/30] nbd: Don't use *_to_cpup() functions Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 10/30] nbd: Don't use cpu_to_*w() functions Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 11/30] nbd: simplify the nbd_request and nbd_reply structs Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 12/30] target-i386: kvm: cache KVM_GET_SUPPORTED_CPUID data Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 13/30] scsi-disk: Use (unsigned long) typecasts when using "%lu" format string Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 14/30] linux-headers: update to Linux 4.6 Paolo Bonzini
2016-06-16 16:09 ` Christian Borntraeger
2016-06-16 16:31 ` Greg Kurz
2016-06-16 14:16 ` [Qemu-devel] [PULL 15/30] KVM: use KVM_CAP_MAX_VCPU_ID Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 16/30] vl.c: Add '-L help' which lists data dirs Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 17/30] nbd: Use BDRV_REQ_FUA for better FUA where supported Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 18/30] nbd: More debug typo fixes, use correct formats Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 19/30] nbd: Quit server after any write error Paolo Bonzini
2016-06-16 14:16 ` Paolo Bonzini [this message]
2016-06-16 14:16 ` [Qemu-devel] [PULL 21/30] nbd: Reject unknown request flags Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 22/30] nbd: Group all Linux-specific ioctl code in one place Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 23/30] nbd: Clean up ioctl handling of qemu-nbd -c Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 24/30] nbd: Detect servers that send unexpected error values Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 25/30] nbd: Avoid magic number for NBD max name size Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 26/30] scsi: esp: check buffer length before reading scsi command Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 27/30] scsi: esp: respect FIFO invariant after message phase Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 28/30] scsi: esp: clean up handle_ti/esp_do_dma if s->do_cmd Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 29/30] scsi: esp: make cmdbuf big enough for maximum CDB size Paolo Bonzini
2016-06-16 14:16 ` [Qemu-devel] [PULL 30/30] vl: smp_parse: cleanups Paolo Bonzini
2016-06-21 15:40 ` Igor Mammedov
2016-06-21 16:22 ` Andrew Jones
2016-06-16 16:02 ` [Qemu-devel] [PULL 00/30] KVM, build, NBD, SCSI patches for 2016-06-16 Peter Maydell
2016-06-16 16:29 ` Paolo Bonzini
2016-06-16 16:55 ` Peter Maydell
2016-06-16 17:01 ` Paolo Bonzini
2016-06-16 17:08 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1466086585-16526-21-git-send-email-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).