|
|
ddf19c |
From f49ff2ed5675f1d0cddc404842e9d6e4e572d5a7 Mon Sep 17 00:00:00 2001
|
|
|
ddf19c |
From: Eric Blake <eblake@redhat.com>
|
|
|
ddf19c |
Date: Wed, 10 Jun 2020 18:32:01 -0400
|
|
|
ddf19c |
Subject: [PATCH 1/2] nbd/server: Avoid long error message assertions
|
|
|
ddf19c |
CVE-2020-10761
|
|
|
ddf19c |
|
|
|
ddf19c |
RH-Author: Eric Blake <eblake@redhat.com>
|
|
|
ddf19c |
Message-id: <20200610183202.3780750-2-eblake@redhat.com>
|
|
|
ddf19c |
Patchwork-id: 97494
|
|
|
ddf19c |
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 1/2] nbd/server: Avoid long error message assertions CVE-2020-10761
|
|
|
ddf19c |
Bugzilla: 1845384
|
|
|
ddf19c |
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
|
|
|
ddf19c |
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
|
ddf19c |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
ddf19c |
|
|
|
ddf19c |
Ever since commit 36683283 (v2.8), the server code asserts that error
|
|
|
ddf19c |
strings sent to the client are well-formed per the protocol by not
|
|
|
ddf19c |
exceeding the maximum string length of 4096. At the time the server
|
|
|
ddf19c |
first started sending error messages, the assertion could not be
|
|
|
ddf19c |
triggered, because messages were completely under our control.
|
|
|
ddf19c |
However, over the years, we have added latent scenarios where a client
|
|
|
ddf19c |
could trigger the server to attempt an error message that would
|
|
|
ddf19c |
include the client's information if it passed other checks first:
|
|
|
ddf19c |
|
|
|
ddf19c |
- requesting NBD_OPT_INFO/GO on an export name that is not present
|
|
|
ddf19c |
(commit 0cfae925 in v2.12 echoes the name)
|
|
|
ddf19c |
|
|
|
ddf19c |
- requesting NBD_OPT_LIST/SET_META_CONTEXT on an export name that is
|
|
|
ddf19c |
not present (commit e7b1948d in v2.12 echoes the name)
|
|
|
ddf19c |
|
|
|
ddf19c |
At the time, those were still safe because we flagged names larger
|
|
|
ddf19c |
than 256 bytes with a different message; but that changed in commit
|
|
|
ddf19c |
93676c88 (v4.2) when we raised the name limit to 4096 to match the NBD
|
|
|
ddf19c |
string limit. (That commit also failed to change the magic number
|
|
|
ddf19c |
4096 in nbd_negotiate_send_rep_err to the just-introduced named
|
|
|
ddf19c |
constant.) So with that commit, long client names appended to server
|
|
|
ddf19c |
text can now trigger the assertion, and thus be used as a denial of
|
|
|
ddf19c |
service attack against a server. As a mitigating factor, if the
|
|
|
ddf19c |
server requires TLS, the client cannot trigger the problematic paths
|
|
|
ddf19c |
unless it first supplies TLS credentials, and such trusted clients are
|
|
|
ddf19c |
less likely to try to intentionally crash the server.
|
|
|
ddf19c |
|
|
|
ddf19c |
We may later want to further sanitize the user-supplied strings we
|
|
|
ddf19c |
place into our error messages, such as scrubbing out control
|
|
|
ddf19c |
characters, but that is less important to the CVE fix, so it can be a
|
|
|
ddf19c |
later patch to the new nbd_sanitize_name.
|
|
|
ddf19c |
|
|
|
ddf19c |
Consideration was given to changing the assertion in
|
|
|
ddf19c |
nbd_negotiate_send_rep_verr to instead merely log a server error and
|
|
|
ddf19c |
truncate the message, to avoid leaving a latent path that could
|
|
|
ddf19c |
trigger a future CVE DoS on any new error message. However, this
|
|
|
ddf19c |
merely complicates the code for something that is already (correctly)
|
|
|
ddf19c |
flagging coding errors, and now that we are aware of the long message
|
|
|
ddf19c |
pitfall, we are less likely to introduce such errors in the future,
|
|
|
ddf19c |
which would make such error handling dead code.
|
|
|
ddf19c |
|
|
|
ddf19c |
Reported-by: Xueqiang Wei <xuwei@redhat.com>
|
|
|
ddf19c |
CC: qemu-stable@nongnu.org
|
|
|
ddf19c |
Fixes: https://bugzilla.redhat.com/1843684 CVE-2020-10761
|
|
|
ddf19c |
Fixes: 93676c88d7
|
|
|
ddf19c |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
ddf19c |
Message-Id: <20200610163741.3745251-2-eblake@redhat.com>
|
|
|
ddf19c |
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
|
|
ddf19c |
(cherry picked from commit 5c4fe018c025740fef4a0a4421e8162db0c3eefd)
|
|
|
ddf19c |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
ddf19c |
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
|
|
|
ddf19c |
---
|
|
|
ddf19c |
nbd/server.c | 23 ++++++++++++++++++++---
|
|
|
ddf19c |
tests/qemu-iotests/143 | 4 ++++
|
|
|
ddf19c |
tests/qemu-iotests/143.out | 2 ++
|
|
|
ddf19c |
3 files changed, 26 insertions(+), 3 deletions(-)
|
|
|
ddf19c |
|
|
|
ddf19c |
diff --git a/nbd/server.c b/nbd/server.c
|
|
|
ddf19c |
index 24ebc1a805..d5b9df092c 100644
|
|
|
ddf19c |
--- a/nbd/server.c
|
|
|
ddf19c |
+++ b/nbd/server.c
|
|
|
ddf19c |
@@ -217,7 +217,7 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
|
|
ddf19c |
|
|
|
ddf19c |
msg = g_strdup_vprintf(fmt, va);
|
|
|
ddf19c |
len = strlen(msg);
|
|
|
ddf19c |
- assert(len < 4096);
|
|
|
ddf19c |
+ assert(len < NBD_MAX_STRING_SIZE);
|
|
|
ddf19c |
trace_nbd_negotiate_send_rep_err(msg);
|
|
|
ddf19c |
ret = nbd_negotiate_send_rep_len(client, type, len, errp);
|
|
|
ddf19c |
if (ret < 0) {
|
|
|
ddf19c |
@@ -231,6 +231,19 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
|
|
ddf19c |
return 0;
|
|
|
ddf19c |
}
|
|
|
ddf19c |
|
|
|
ddf19c |
+/*
|
|
|
ddf19c |
+ * Return a malloc'd copy of @name suitable for use in an error reply.
|
|
|
ddf19c |
+ */
|
|
|
ddf19c |
+static char *
|
|
|
ddf19c |
+nbd_sanitize_name(const char *name)
|
|
|
ddf19c |
+{
|
|
|
ddf19c |
+ if (strnlen(name, 80) < 80) {
|
|
|
ddf19c |
+ return g_strdup(name);
|
|
|
ddf19c |
+ }
|
|
|
ddf19c |
+ /* XXX Should we also try to sanitize any control characters? */
|
|
|
ddf19c |
+ return g_strdup_printf("%.80s...", name);
|
|
|
ddf19c |
+}
|
|
|
ddf19c |
+
|
|
|
ddf19c |
/* Send an error reply.
|
|
|
ddf19c |
* Return -errno on error, 0 on success. */
|
|
|
ddf19c |
static int GCC_FMT_ATTR(4, 5)
|
|
|
ddf19c |
@@ -595,9 +608,11 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
|
|
ddf19c |
|
|
|
ddf19c |
exp = nbd_export_find(name);
|
|
|
ddf19c |
if (!exp) {
|
|
|
ddf19c |
+ g_autofree char *sane_name = nbd_sanitize_name(name);
|
|
|
ddf19c |
+
|
|
|
ddf19c |
return nbd_negotiate_send_rep_err(client, NBD_REP_ERR_UNKNOWN,
|
|
|
ddf19c |
errp, "export '%s' not present",
|
|
|
ddf19c |
- name);
|
|
|
ddf19c |
+ sane_name);
|
|
|
ddf19c |
}
|
|
|
ddf19c |
|
|
|
ddf19c |
/* Don't bother sending NBD_INFO_NAME unless client requested it */
|
|
|
ddf19c |
@@ -995,8 +1010,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
|
|
|
ddf19c |
|
|
|
ddf19c |
meta->exp = nbd_export_find(export_name);
|
|
|
ddf19c |
if (meta->exp == NULL) {
|
|
|
ddf19c |
+ g_autofree char *sane_name = nbd_sanitize_name(export_name);
|
|
|
ddf19c |
+
|
|
|
ddf19c |
return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp,
|
|
|
ddf19c |
- "export '%s' not present", export_name);
|
|
|
ddf19c |
+ "export '%s' not present", sane_name);
|
|
|
ddf19c |
}
|
|
|
ddf19c |
|
|
|
ddf19c |
ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), errp);
|
|
|
ddf19c |
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
|
|
|
ddf19c |
index f649b36195..d2349903b1 100755
|
|
|
ddf19c |
--- a/tests/qemu-iotests/143
|
|
|
ddf19c |
+++ b/tests/qemu-iotests/143
|
|
|
ddf19c |
@@ -58,6 +58,10 @@ _send_qemu_cmd $QEMU_HANDLE \
|
|
|
ddf19c |
$QEMU_IO_PROG -f raw -c quit \
|
|
|
ddf19c |
"nbd+unix:///no_such_export?socket=$SOCK_DIR/nbd" 2>&1 \
|
|
|
ddf19c |
| _filter_qemu_io | _filter_nbd
|
|
|
ddf19c |
+# Likewise, with longest possible name permitted in NBD protocol
|
|
|
ddf19c |
+$QEMU_IO_PROG -f raw -c quit \
|
|
|
ddf19c |
+ "nbd+unix:///$(printf %4096d 1 | tr ' ' a)?socket=$SOCK_DIR/nbd" 2>&1 \
|
|
|
ddf19c |
+ | _filter_qemu_io | _filter_nbd | sed 's/aaaa*aa/aa--aa/'
|
|
|
ddf19c |
|
|
|
ddf19c |
_send_qemu_cmd $QEMU_HANDLE \
|
|
|
ddf19c |
"{ 'execute': 'quit' }" \
|
|
|
ddf19c |
diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out
|
|
|
ddf19c |
index 1f4001c601..fc9c0a761f 100644
|
|
|
ddf19c |
--- a/tests/qemu-iotests/143.out
|
|
|
ddf19c |
+++ b/tests/qemu-iotests/143.out
|
|
|
ddf19c |
@@ -5,6 +5,8 @@ QA output created by 143
|
|
|
ddf19c |
{"return": {}}
|
|
|
ddf19c |
qemu-io: can't open device nbd+unix:///no_such_export?socket=SOCK_DIR/nbd: Requested export not available
|
|
|
ddf19c |
server reported: export 'no_such_export' not present
|
|
|
ddf19c |
+qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available
|
|
|
ddf19c |
+server reported: export 'aa--aa...' not present
|
|
|
ddf19c |
{ 'execute': 'quit' }
|
|
|
ddf19c |
{"return": {}}
|
|
|
ddf19c |
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
|
|
|
ddf19c |
--
|
|
|
ddf19c |
2.27.0
|
|
|
ddf19c |
|