aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-03-09 11:38:29 +0000
committerPeter Maydell <peter.maydell@linaro.org>2022-03-09 11:38:29 +0000
commitfdee2c96923dfd38aa7a264abb7de6d403f81c4d (patch)
tree741d5162d0fc6dc79f387287ccb0ca8c52d69a7d
parentf14ad81eed531adc9b3ae2af76cd52cfad5c9ae5 (diff)
parent395aecd037dc35d110b8e1e8cc7d20c1082894b5 (diff)
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2022-03-07' into staging
nbd patches for 2022-03-07 - Dan Berrange: Allow qemu-nbd to support TLS over Unix sockets - Eric Blake: Minor cleanups related to 64-bit block operations # gpg: Signature made Tue 08 Mar 2022 01:41:35 GMT # gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full] # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full] # gpg: aka "[jpeg image of size 6874]" [full] # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-nbd-2022-03-07: qemu-io: Allow larger write zeroes under no fallback qemu-io: Utilize 64-bit status during map nbd/server: Minor cleanups tests/qemu-iotests: validate NBD TLS with UNIX sockets and PSK tests/qemu-iotests: validate NBD TLS with UNIX sockets tests/qemu-iotests: validate NBD TLS with hostname mismatch tests/qemu-iotests: convert NBD TLS test to use standard filters tests/qemu-iotests: introduce filter for qemu-nbd export list tests/qemu-iotests: expand _filter_nbd rules tests/qemu-iotests: add QEMU_IOTESTS_REGEN=1 to update reference file block/nbd: don't restrict TLS usage to IP sockets qemu-nbd: add --tls-hostname option for TLS certificate validation block/nbd: support override of hostname for TLS certificate validation block: pass desired TLS hostname through from block driver client crypto: mandate a hostname when checking x509 creds on a client Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--block/nbd.c25
-rw-r--r--blockdev-nbd.c6
-rw-r--r--crypto/tlssession.c6
-rw-r--r--docs/tools/qemu-nbd.rst13
-rw-r--r--include/block/nbd.h3
-rw-r--r--nbd/client-connection.c12
-rw-r--r--nbd/server.c13
-rw-r--r--qapi/block-core.json3
-rw-r--r--qemu-io-cmds.c16
-rw-r--r--qemu-nbd.c25
-rwxr-xr-xtests/qemu-iotests/23399
-rw-r--r--tests/qemu-iotests/233.out58
-rwxr-xr-xtests/qemu-iotests/2416
-rw-r--r--tests/qemu-iotests/241.out6
-rw-r--r--tests/qemu-iotests/common.filter9
-rw-r--r--tests/qemu-iotests/common.tls31
-rw-r--r--tests/qemu-iotests/testrunner.py6
17 files changed, 268 insertions, 69 deletions
diff --git a/block/nbd.c b/block/nbd.c
index 146d25660e..34b9429de3 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -90,9 +90,10 @@ typedef struct BDRVNBDState {
uint32_t reconnect_delay;
uint32_t open_timeout;
SocketAddress *saddr;
- char *export, *tlscredsid;
+ char *export;
+ char *tlscredsid;
QCryptoTLSCreds *tlscreds;
- const char *hostname;
+ char *tlshostname;
char *x_dirty_bitmap;
bool alloc_depth;
@@ -121,6 +122,8 @@ static void nbd_clear_bdrvstate(BlockDriverState *bs)
s->export = NULL;
g_free(s->tlscredsid);
s->tlscredsid = NULL;
+ g_free(s->tlshostname);
+ s->tlshostname = NULL;
g_free(s->x_dirty_bitmap);
s->x_dirty_bitmap = NULL;
}
@@ -1766,6 +1769,11 @@ static QemuOptsList nbd_runtime_opts = {
.help = "ID of the TLS credentials to use",
},
{
+ .name = "tls-hostname",
+ .type = QEMU_OPT_STRING,
+ .help = "Override hostname for validating TLS x509 certificate",
+ },
+ {
.name = "x-dirty-bitmap",
.type = QEMU_OPT_STRING,
.help = "experimental: expose named dirty bitmap in place of "
@@ -1831,12 +1839,11 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options,
goto error;
}
- /* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
- if (s->saddr->type != SOCKET_ADDRESS_TYPE_INET) {
- error_setg(errp, "TLS only supported over IP sockets");
- goto error;
+ s->tlshostname = g_strdup(qemu_opt_get(opts, "tls-hostname"));
+ if (!s->tlshostname &&
+ s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
+ s->tlshostname = g_strdup(s->saddr->u.inet.host);
}
- s->hostname = s->saddr->u.inet.host;
}
s->x_dirty_bitmap = g_strdup(qemu_opt_get(opts, "x-dirty-bitmap"));
@@ -1876,7 +1883,8 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
}
s->conn = nbd_client_connection_new(s->saddr, true, s->export,
- s->x_dirty_bitmap, s->tlscreds);
+ s->x_dirty_bitmap, s->tlscreds,
+ s->tlshostname);
if (s->open_timeout) {
nbd_client_connection_enable_retry(s->conn);
@@ -2037,6 +2045,7 @@ static const char *const nbd_strong_runtime_opts[] = {
"port",
"export",
"tls-creds",
+ "tls-hostname",
"server.",
NULL
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index bdfa7ed3a5..9840d25a82 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -148,12 +148,6 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
if (!nbd_server->tlscreds) {
goto error;
}
-
- /* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */
- if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
- error_setg(errp, "TLS is only supported with IPv4/IPv6");
- goto error;
- }
}
nbd_server->tlsauthz = g_strdup(tls_authz);
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index a8db8c76d1..b302d835d2 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -373,6 +373,12 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
session->hostname);
goto error;
}
+ } else {
+ if (session->creds->endpoint ==
+ QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+ error_setg(errp, "No hostname for certificate validation");
+ goto error;
+ }
}
}
diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst
index 6031f96893..2b8c90c354 100644
--- a/docs/tools/qemu-nbd.rst
+++ b/docs/tools/qemu-nbd.rst
@@ -169,6 +169,19 @@ driver options if ``--image-opts`` is specified.
option; or provide the credentials needed for connecting as a client
in list mode.
+.. option:: --tls-hostname=hostname
+
+ When validating an x509 certificate received over a TLS connection,
+ the hostname that the NBD client used to connect will be checked
+ against information in the server provided certificate. Sometimes
+ it might be required to override the hostname used to perform this
+ check. For example, if the NBD client is using a tunnel from localhost
+ to connect to the remote server, the `--tls-hostname` option should
+ be used to set the officially expected hostname of the remote NBD
+ server. This can also be used if accessing NBD over a UNIX socket
+ where there is no inherent hostname available. This is only permitted
+ when acting as a NBD client with the `--list` option.
+
.. option:: --fork
Fork off the server process and exit the parent once the server is running.
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 78d101b774..a98eb665da 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -415,7 +415,8 @@ NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
bool do_negotiation,
const char *export_name,
const char *x_dirty_bitmap,
- QCryptoTLSCreds *tlscreds);
+ QCryptoTLSCreds *tlscreds,
+ const char *tlshostname);
void nbd_client_connection_release(NBDClientConnection *conn);
QIOChannel *coroutine_fn
diff --git a/nbd/client-connection.c b/nbd/client-connection.c
index 2bda42641d..2a632931c3 100644
--- a/nbd/client-connection.c
+++ b/nbd/client-connection.c
@@ -33,6 +33,7 @@ struct NBDClientConnection {
/* Initialization constants, never change */
SocketAddress *saddr; /* address to connect to */
QCryptoTLSCreds *tlscreds;
+ char *tlshostname;
NBDExportInfo initial_info;
bool do_negotiation;
bool do_retry;
@@ -77,7 +78,8 @@ NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
bool do_negotiation,
const char *export_name,
const char *x_dirty_bitmap,
- QCryptoTLSCreds *tlscreds)
+ QCryptoTLSCreds *tlscreds,
+ const char *tlshostname)
{
NBDClientConnection *conn = g_new(NBDClientConnection, 1);
@@ -85,6 +87,7 @@ NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
*conn = (NBDClientConnection) {
.saddr = QAPI_CLONE(SocketAddress, saddr),
.tlscreds = tlscreds,
+ .tlshostname = g_strdup(tlshostname),
.do_negotiation = do_negotiation,
.initial_info.request_sizes = true,
@@ -107,6 +110,7 @@ static void nbd_client_connection_do_free(NBDClientConnection *conn)
}
error_free(conn->err);
qapi_free_SocketAddress(conn->saddr);
+ g_free(conn->tlshostname);
object_unref(OBJECT(conn->tlscreds));
g_free(conn->initial_info.x_dirty_bitmap);
g_free(conn->initial_info.name);
@@ -120,6 +124,7 @@ static void nbd_client_connection_do_free(NBDClientConnection *conn)
*/
static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr,
NBDExportInfo *info, QCryptoTLSCreds *tlscreds,
+ const char *tlshostname,
QIOChannel **outioc, Error **errp)
{
int ret;
@@ -140,7 +145,7 @@ static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr,
}
ret = nbd_receive_negotiate(NULL, QIO_CHANNEL(sioc), tlscreds,
- tlscreds ? addr->u.inet.host : NULL,
+ tlshostname,
outioc, info, errp);
if (ret < 0) {
/*
@@ -183,7 +188,8 @@ static void *connect_thread_func(void *opaque)
ret = nbd_connect(conn->sioc, conn->saddr,
conn->do_negotiation ? &conn->updated_info : NULL,
- conn->tlscreds, &conn->ioc, &local_err);
+ conn->tlscreds, conn->tlshostname,
+ &conn->ioc, &local_err);
/*
* conn->updated_info will finally be returned to the user. Clear the
diff --git a/nbd/server.c b/nbd/server.c
index 53e68cf027..5da884c2fc 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -2085,11 +2085,10 @@ static void nbd_extent_array_convert_to_be(NBDExtentArray *ea)
* Add extent to NBDExtentArray. If extent can't be added (no available space),
* return -1.
* For safety, when returning -1 for the first time, .can_add is set to false,
- * further call to nbd_extent_array_add() will crash.
- * (to avoid the situation, when after failing to add an extent (returned -1),
- * user miss this failure and add another extent, which is successfully added
- * (array is full, but new extent may be squashed into the last one), then we
- * have invalid array with skipped extent)
+ * and further calls to nbd_extent_array_add() will crash.
+ * (this avoids the situation where a caller ignores failure to add one extent,
+ * where adding another extent that would squash into the last array entry
+ * would result in an incorrect range reported to the client)
*/
static int nbd_extent_array_add(NBDExtentArray *ea,
uint32_t length, uint32_t flags)
@@ -2288,7 +2287,7 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
assert(client->recv_coroutine == qemu_coroutine_self());
ret = nbd_receive_request(client, request, errp);
if (ret < 0) {
- return ret;
+ return ret;
}
trace_nbd_co_receive_request_decode_type(request->handle, request->type,
@@ -2648,7 +2647,7 @@ static coroutine_fn void nbd_trip(void *opaque)
}
if (ret < 0) {
- /* It wans't -EIO, so, according to nbd_co_receive_request()
+ /* It wasn't -EIO, so, according to nbd_co_receive_request()
* semantics, we should return the error to the client. */
Error *export_err = local_err;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index f13b5ff942..e89f2dfb5b 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -4079,6 +4079,8 @@
#
# @tls-creds: TLS credentials ID
#
+# @tls-hostname: TLS hostname override for certificate validation (Since 7.0)
+#
# @x-dirty-bitmap: A metadata context name such as "qemu:dirty-bitmap:NAME"
# or "qemu:allocation-depth" to query in place of the
# traditional "base:allocation" block status (see
@@ -4109,6 +4111,7 @@
'data': { 'server': 'SocketAddress',
'*export': 'str',
'*tls-creds': 'str',
+ '*tls-hostname': 'str',
'*x-dirty-bitmap': { 'type': 'str', 'features': [ 'unstable' ] },
'*reconnect-delay': 'uint32',
'*open-timeout': 'uint32' } }
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 633b46cdb2..2f0d8ac25a 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -604,10 +604,6 @@ static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
.done = false,
};
- if (bytes > INT_MAX) {
- return -ERANGE;
- }
-
co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data);
bdrv_coroutine_enter(blk_bs(blk), co);
while (!data.done) {
@@ -1161,8 +1157,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
if (count < 0) {
print_cvtnum_err(count, argv[optind]);
return count;
- } else if (count > BDRV_REQUEST_MAX_BYTES) {
- printf("length cannot exceed %" PRIu64 ", given %s\n",
+ } else if (count > BDRV_REQUEST_MAX_BYTES &&
+ !(flags & BDRV_REQ_NO_FALLBACK)) {
+ printf("length cannot exceed %" PRIu64 " without -n, given %s\n",
(uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
return -EINVAL;
}
@@ -1994,11 +1991,9 @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset,
int64_t bytes, int64_t *pnum)
{
int64_t num;
- int num_checked;
int ret, firstret;
- num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
- ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+ ret = bdrv_is_allocated(bs, offset, bytes, &num);
if (ret < 0) {
return ret;
}
@@ -2010,8 +2005,7 @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset,
offset += num;
bytes -= num;
- num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
- ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+ ret = bdrv_is_allocated(bs, offset, bytes, &num);
if (ret == firstret && num) {
*pnum += num;
} else {
diff --git a/qemu-nbd.c b/qemu-nbd.c
index c6c20df68a..713e7557a9 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -69,6 +69,7 @@
#define QEMU_NBD_OPT_TLSAUTHZ 264
#define QEMU_NBD_OPT_PID_FILE 265
#define QEMU_NBD_OPT_SELINUX_LABEL 266
+#define QEMU_NBD_OPT_TLSHOSTNAME 267
#define MBR_SIZE 512
@@ -542,6 +543,7 @@ int main(int argc, char **argv)
{ "export-name", required_argument, NULL, 'x' },
{ "description", required_argument, NULL, 'D' },
{ "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
+ { "tls-hostname", required_argument, NULL, QEMU_NBD_OPT_TLSHOSTNAME },
{ "tls-authz", required_argument, NULL, QEMU_NBD_OPT_TLSAUTHZ },
{ "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
{ "trace", required_argument, NULL, 'T' },
@@ -568,6 +570,7 @@ int main(int argc, char **argv)
strList *bitmaps = NULL;
bool alloc_depth = false;
const char *tlscredsid = NULL;
+ const char *tlshostname = NULL;
bool imageOpts = false;
bool writethrough = false; /* Client will flush as needed. */
bool fork_process = false;
@@ -747,6 +750,9 @@ int main(int argc, char **argv)
case QEMU_NBD_OPT_TLSCREDS:
tlscredsid = optarg;
break;
+ case QEMU_NBD_OPT_TLSHOSTNAME:
+ tlshostname = optarg;
+ break;
case QEMU_NBD_OPT_IMAGE_OPTS:
imageOpts = true;
break;
@@ -802,7 +808,9 @@ int main(int argc, char **argv)
socket_activation = check_socket_activation();
if (socket_activation == 0) {
- setup_address_and_port(&bindto, &port);
+ if (!sockpath) {
+ setup_address_and_port(&bindto, &port);
+ }
} else {
/* Using socket activation - check user didn't use -p etc. */
const char *err_msg = socket_activation_validate_opts(device, sockpath,
@@ -823,10 +831,6 @@ int main(int argc, char **argv)
}
if (tlscredsid) {
- if (sockpath) {
- error_report("TLS is only supported with IPv4/IPv6");
- exit(EXIT_FAILURE);
- }
if (device) {
error_report("TLS is not supported with a host device");
exit(EXIT_FAILURE);
@@ -835,6 +839,10 @@ int main(int argc, char **argv)
error_report("TLS authorization is incompatible with export list");
exit(EXIT_FAILURE);
}
+ if (tlshostname && !list) {
+ error_report("TLS hostname is only supported with export list");
+ exit(EXIT_FAILURE);
+ }
tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err);
if (local_err) {
error_reportf_err(local_err, "Failed to get TLS creds: ");
@@ -845,6 +853,10 @@ int main(int argc, char **argv)
error_report("--tls-authz is not permitted without --tls-creds");
exit(EXIT_FAILURE);
}
+ if (tlshostname) {
+ error_report("--tls-hostname is not permitted without --tls-creds");
+ exit(EXIT_FAILURE);
+ }
}
if (selinux_label) {
@@ -861,7 +873,8 @@ int main(int argc, char **argv)
if (list) {
saddr = nbd_build_socket_address(sockpath, bindto, port);
- return qemu_nbd_client_list(saddr, tlscreds, bindto);
+ return qemu_nbd_client_list(saddr, tlscreds,
+ tlshostname ? tlshostname : bindto);
}
#if !HAVE_NBD_DEVICE
diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233
index 9ca7b68f42..55db5b3811 100755
--- a/tests/qemu-iotests/233
+++ b/tests/qemu-iotests/233
@@ -61,11 +61,13 @@ tls_x509_create_server "ca1" "server1"
tls_x509_create_client "ca1" "client1"
tls_x509_create_client "ca2" "client2"
tls_x509_create_client "ca1" "client3"
+tls_psk_create_creds "psk1"
+tls_psk_create_creds "psk2"
echo
echo "== preparing image =="
_make_test_img 64M
-$QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" 2>&1 | _filter_qemu_io
echo
echo "== check TLS client to plain server fails =="
@@ -74,9 +76,9 @@ nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log"
obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
$QEMU_IMG info --image-opts --object $obj \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
- --tls-creds=tls0
+ --tls-creds=tls0 2>&1 | _filter_qemu_nbd_exports
nbd_server_stop
@@ -88,8 +90,10 @@ nbd_server_start_tcp_socket \
--tls-creds tls0 \
-f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log"
-$QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
-$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port
+$QEMU_IMG info nbd://localhost:$nbd_tcp_port \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port \
+ 2>&1 | _filter_qemu_nbd_exports
echo
echo "== check TLS works =="
@@ -97,21 +101,39 @@ obj1=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
obj2=tls-creds-x509,dir=${tls_dir}/client3,endpoint=client,id=tls0
$QEMU_IMG info --image-opts --object $obj1 \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
$QEMU_IMG info --image-opts --object $obj2 \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj1 \
- --tls-creds=tls0
+ --tls-creds=tls0 2>&1 | _filter_qemu_nbd_exports
+
+echo
+echo "== check TLS fail over TCP with mismatched hostname =="
+obj1=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,host=localhost,port=$nbd_tcp_port,tls-creds=tls0 \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -b localhost -p $nbd_tcp_port --object $obj1 \
+ --tls-creds=tls0 | _filter_qemu_nbd_exports
+
+echo
+echo "== check TLS works over TCP with mismatched hostname and override =="
+obj1=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,host=localhost,port=$nbd_tcp_port,tls-creds=tls0,tls-hostname=127.0.0.1 \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -b localhost -p $nbd_tcp_port --object $obj1 \
+ --tls-creds=tls0 --tls-hostname=127.0.0.1 | _filter_qemu_nbd_exports
echo
echo "== check TLS with different CA fails =="
obj=tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0
$QEMU_IMG info --image-opts --object $obj \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
- --tls-creds=tls0
+ --tls-creds=tls0 2>&1 | _filter_qemu_nbd_exports
echo
echo "== perform I/O over TLS =="
@@ -121,7 +143,8 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
2>&1 | _filter_qemu_io
-$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" \
+ 2>&1 | _filter_qemu_io
echo
echo "== check TLS with authorization =="
@@ -139,12 +162,62 @@ nbd_server_start_tcp_socket \
$QEMU_IMG info --image-opts \
--object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
$QEMU_IMG info --image-opts \
--object tls-creds-x509,dir=${tls_dir}/client3,endpoint=client,id=tls0 \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
- 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+ 2>&1 | _filter_nbd
+
+nbd_server_stop
+
+nbd_server_start_unix_socket \
+ --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=on \
+ --tls-creds tls0 \
+ -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log"
+
+echo
+echo "== check TLS fail over UNIX with no hostname =="
+obj1=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,path=$nbd_unix_socket,tls-creds=tls0 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -k $nbd_unix_socket --object $obj1 --tls-creds=tls0 \
+ 2>&1 | _filter_qemu_nbd_exports
+
+echo
+echo "== check TLS works over UNIX with hostname override =="
+obj1=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,path=$nbd_unix_socket,tls-creds=tls0,tls-hostname=127.0.0.1 \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -k $nbd_unix_socket --object $obj1 \
+ --tls-creds=tls0 --tls-hostname=127.0.0.1 2>&1 | _filter_qemu_nbd_exports
+
+
+echo
+echo "== check TLS works over UNIX with PSK =="
+nbd_server_stop
+
+nbd_server_start_unix_socket \
+ --object tls-creds-psk,dir=${tls_dir}/psk1,endpoint=server,id=tls0,verify-peer=on \
+ --tls-creds tls0 \
+ -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log"
+
+obj1=tls-creds-psk,dir=${tls_dir}/psk1,username=psk1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,path=$nbd_unix_socket,tls-creds=tls0 \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -k $nbd_unix_socket --object $obj1 \
+ --tls-creds=tls0 2>&1 | _filter_qemu_nbd_exports
+
+echo
+echo "== check TLS fails over UNIX with mismatch PSK =="
+obj1=tls-creds-psk,dir=${tls_dir}/psk2,username=psk2,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj1 \
+ driver=nbd,path=$nbd_unix_socket,tls-creds=tls0 \
+ 2>&1 | _filter_nbd
+$QEMU_NBD_PROG -L -k $nbd_unix_socket --object $obj1 \
+ --tls-creds=tls0 2>&1 | _filter_qemu_nbd_exports
echo
echo "== final server log =="
diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out
index 4b1f6a0e15..237c82767e 100644
--- a/tests/qemu-iotests/233.out
+++ b/tests/qemu-iotests/233.out
@@ -7,6 +7,8 @@ Generating a signed certificate...
Generating a signed certificate...
Generating a signed certificate...
Generating a signed certificate...
+Generating a random key for user 'psk1'
+Generating a random key for user 'psk2'
== preparing image ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
@@ -17,15 +19,12 @@ wrote 1048576/1048576 bytes at offset 1048576
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls)
server reported: TLS not configured
qemu-nbd: Denied by server for option 5 (starttls)
-server reported: TLS not configured
== check plain client to TLS server fails ==
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go)
Did you forget a valid tls-creds?
server reported: Option 0x7 not permitted before TLS
qemu-nbd: TLS negotiation required before option 3 (list)
-Did you forget a valid tls-creds?
-server reported: Option 0x3 not permitted before TLS
== check TLS works ==
image: nbd://127.0.0.1:PORT
@@ -39,12 +38,21 @@ disk size: unavailable
exports available: 1
export: ''
size: 67108864
- flags: 0xced ( flush fua trim zeroes df cache fast-zero )
min block: 1
- opt block: 4096
- max block: 33554432
- available meta contexts: 1
- base:allocation
+
+== check TLS fail over TCP with mismatched hostname ==
+qemu-img: Could not open 'driver=nbd,host=localhost,port=PORT,tls-creds=tls0': Certificate does not match the hostname localhost
+qemu-nbd: Certificate does not match the hostname localhost
+
+== check TLS works over TCP with mismatched hostname and override ==
+image: nbd://localhost:PORT
+file format: nbd
+virtual size: 64 MiB (67108864 bytes)
+disk size: unavailable
+exports available: 1
+ export: ''
+ size: 67108864
+ min block: 1
== check TLS with different CA fails ==
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer
@@ -62,9 +70,43 @@ read 1048576/1048576 bytes at offset 1048576
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
+== check TLS fail over UNIX with no hostname ==
+qemu-img: Could not open 'driver=nbd,path=SOCK_DIR/qemu-nbd.sock,tls-creds=tls0': No hostname for certificate validation
+qemu-nbd: No hostname for certificate validation
+
+== check TLS works over UNIX with hostname override ==
+image: nbd+unix://?socket=SOCK_DIR/qemu-nbd.sock
+file format: nbd
+virtual size: 64 MiB (67108864 bytes)
+disk size: unavailable
+exports available: 1
+ export: ''
+ size: 67108864
+ min block: 1
+
+== check TLS works over UNIX with PSK ==
+image: nbd+unix://?socket=SOCK_DIR/qemu-nbd.sock
+file format: nbd
+virtual size: 64 MiB (67108864 bytes)
+disk size: unavailable
+exports available: 1
+ export: ''
+ size: 67108864
+ min block: 1
+
+== check TLS fails over UNIX with mismatch PSK ==
+qemu-img: Could not open 'driver=nbd,path=SOCK_DIR/qemu-nbd.sock,tls-creds=tls0': TLS handshake failed: The TLS connection was non-properly terminated.
+qemu-nbd: TLS handshake failed: The TLS connection was non-properly terminated.
+
== final server log ==
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied
qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
+qemu-nbd: option negotiation failed: TLS handshake failed: An illegal parameter has been received.
+qemu-nbd: option negotiation failed: TLS handshake failed: An illegal parameter has been received.
*** done
diff --git a/tests/qemu-iotests/241 b/tests/qemu-iotests/241
index c962c8b607..f196650afa 100755
--- a/tests/qemu-iotests/241
+++ b/tests/qemu-iotests/241
@@ -58,7 +58,7 @@ echo
nbd_server_start_unix_socket -f $IMGFMT "$TEST_IMG_FILE"
-$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)'
+$QEMU_NBD_PROG --list -k $nbd_unix_socket | _filter_qemu_nbd_exports
$QEMU_IMG map -f raw --output=json "$TEST_IMG" | _filter_qemu_img_map
$QEMU_IO -f raw -c map "$TEST_IMG"
nbd_server_stop
@@ -71,7 +71,7 @@ echo
# sector alignment, here at the server.
nbd_server_start_unix_socket "$TEST_IMG_FILE" 2> "$TEST_DIR/server.log"
-$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)'
+$QEMU_NBD_PROG --list -k $nbd_unix_socket | _filter_qemu_nbd_exports
$QEMU_IMG map -f raw --output=json "$TEST_IMG" | _filter_qemu_img_map
$QEMU_IO -f raw -c map "$TEST_IMG"
nbd_server_stop
@@ -84,7 +84,7 @@ echo
# Now force sector alignment at the client.
nbd_server_start_unix_socket -f $IMGFMT "$TEST_IMG_FILE"
-$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)'
+$QEMU_NBD_PROG --list -k $nbd_unix_socket | _filter_qemu_nbd_exports
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
$QEMU_IO -c map "$TEST_IMG"
nbd_server_stop
diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out
index 56e95b599a..88e8cfcd7e 100644
--- a/tests/qemu-iotests/241.out
+++ b/tests/qemu-iotests/241.out
@@ -2,6 +2,8 @@ QA output created by 241
=== Exporting unaligned raw image, natural alignment ===
+exports available: 1
+ export: ''
size: 1024
min block: 1
[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
@@ -10,6 +12,8 @@ QA output created by 241
=== Exporting unaligned raw image, forced server sector alignment ===
+exports available: 1
+ export: ''
size: 1024
min block: 512
[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
@@ -20,6 +24,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
=== Exporting unaligned raw image, forced client sector alignment ===
+exports available: 1
+ export: ''
size: 1024
min block: 1
[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 21819db9c3..9790411bf0 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -301,10 +301,19 @@ _filter_nbd()
# Filter out the TCP port number since this changes between runs.
sed -e '/nbd\/.*\.c:/d' \
-e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \
+ -e 's#localhost:[0-9]*#localhost:PORT#g' \
+ -e 's#host=127\.0\.0\.1,port=[0-9]*#host=127.0.0.1,port=PORT#g' \
+ -e 's#host=localhost,port=[0-9]*#host=localhost,port=PORT#g' \
+ -e "s#path=$SOCK_DIR#path=SOCK_DIR#g" \
-e "s#?socket=$SOCK_DIR#?socket=SOCK_DIR#g" \
-e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#'
}
+_filter_qemu_nbd_exports()
+{
+ grep '\(exports available\|export\|size\|min block\|qemu-nbd\):'
+}
+
_filter_qmp_empty_return()
{
grep -v '{"return": {}}'
diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls
index 6ba28a78d3..b9c5462986 100644
--- a/tests/qemu-iotests/common.tls
+++ b/tests/qemu-iotests/common.tls
@@ -24,6 +24,7 @@ tls_x509_cleanup()
{
rm -f "${tls_dir}"/*.pem
rm -f "${tls_dir}"/*/*.pem
+ rm -f "${tls_dir}"/*/*.psk
rmdir "${tls_dir}"/*
rmdir "${tls_dir}"
}
@@ -40,6 +41,18 @@ tls_certtool()
rm -f "${tls_dir}"/certtool.log
}
+tls_psktool()
+{
+ psktool "$@" 1>"${tls_dir}"/psktool.log 2>&1
+ if test "$?" = 0; then
+ head -1 "${tls_dir}"/psktool.log
+ else
+ cat "${tls_dir}"/psktool.log
+ fi
+ rm -f "${tls_dir}"/psktool.log
+}
+
+
tls_x509_init()
{
(certtool --help) >/dev/null 2>&1 || \
@@ -118,12 +131,13 @@ tls_x509_create_server()
caname=$1
name=$2
+ # We don't include 'localhost' in the cert, as
+ # we want to keep it unlisted to let tests
+ # validate hostname override
mkdir -p "${tls_dir}/$name"
cat > "${tls_dir}/cert.info" <<EOF
organization = Cthulhu Dark Lord Enterprises $name
-cn = localhost
-dns_name = localhost
-dns_name = localhost.localdomain
+cn = iotests.qemu.org
ip_address = 127.0.0.1
ip_address = ::1
tls_www_server
@@ -175,3 +189,14 @@ EOF
rm -f "${tls_dir}/cert.info"
}
+
+tls_psk_create_creds()
+{
+ name=$1
+
+ mkdir -p "${tls_dir}/$name"
+
+ tls_psktool \
+ --pskfile "${tls_dir}/$name/keys.psk" \
+ --username "$name"
+}
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index 41083ff9c6..5c207225b1 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -25,6 +25,7 @@ import subprocess
import contextlib
import json
import termios
+import shutil
import sys
from multiprocessing import Pool
from contextlib import contextmanager
@@ -322,6 +323,11 @@ class TestRunner(ContextManager['TestRunner']):
diff = file_diff(str(f_reference), str(f_bad))
if diff:
+ if os.environ.get("QEMU_IOTESTS_REGEN", None) is not None:
+ shutil.copyfile(str(f_bad), str(f_reference))
+ print("########################################")
+ print("##### REFERENCE FILE UPDATED #####")
+ print("########################################")
return TestResult(status='fail', elapsed=elapsed,
description=f'output mismatch (see {f_bad})',
diff=diff, casenotrun=casenotrun)