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
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAmImtE8ACgkQp6FrSiUn
 Q2ovmgf/aksDqf2eNcahs++fez+8Qi9ll5OY/qGyjnzBgsatYKjrK+xF7OnjoJox
 eRX026lh81Q4EQK7oZBUnr2UCY4bncDBTI7MTLh603EV/tId5ZLwx007ERhzvtC1
 mIsQHXNuO9X25LQG2eWnfunY9YztQpiT5r/g3khD2yPBqJWIvBfblzPLx6FkF7px
 /WM8xEKCihmGr1Wr3b+zGYL083YkaBWCvHoR8mJt3tEFUj+Qie8XcdV0OVyI0XUj
 5goIFRcpVwBE8P2nLtfUKNzEXz22cmdonOJUX7E5IvGO21k5F/HrWlHdo8JnuSUZ
 t0w5L9yCxBrRpY1burz30b77J0WMCw==
 =C8Dd
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2022-03-09 11:38:29 +00:00
commit fdee2c9692
17 changed files with 268 additions and 69 deletions

View File

@ -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;
}
@ -1765,6 +1768,11 @@ static QemuOptsList nbd_runtime_opts = {
.type = QEMU_OPT_STRING,
.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,
@ -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

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)
@ -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;

View File

@ -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' } }

View File

@ -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 {

View File

@ -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) {
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

View File

@ -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 =="

View File

@ -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

View File

@ -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

View File

@ -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},

View File

@ -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": {}}'

View File

@ -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"
}

View File

@ -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)